From 0ab371e244bdd3599768f985ef320b729de39222 Mon Sep 17 00:00:00 2001 From: kdubious Date: Thu, 4 Dec 2014 10:02:16 -0500 Subject: [PATCH 01/80] KEW Changes to create an Alphabet navigator. Also a few minor fixes --- app/libs/runeaudio.php | 42 +++++++++++++- app/templates/header.php | 9 ++- app/templates/playback.php | 103 ++++++++++++++++++++++++++++++++- assets/css/runeui.css | 6 +- assets/js/runeui.js | 75 +++++++++++++++++++++++- assets/less/runeui-custom.less | 62 ++++++++++++++++++++ db/redis_acards_details | 2 + 7 files changed, 290 insertions(+), 9 deletions(-) diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 35053995..7ff85d3c 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -588,6 +588,12 @@ function deleteBookmark($redis, $id) return $return; } + +// browseDB +// $sock = MPD Socket +// $browsemode = ("file", etc.) +// $query = the path ("NAS/Music", etc.) + function browseDB($sock,$browsemode,$query) { switch ($browsemode) { case 'file': @@ -766,7 +772,9 @@ function _parseFileListResponse($resp) if (is_null($resp)) { return null; } else { + $plistArray = array(); + $plistAlphabet = array(); $plistLine = strtok($resp, "\n"); // $plistFile = ""; $plCounter = -1; @@ -786,6 +794,21 @@ function _parseFileListResponse($resp) $dirCounter++; // $plistFile = $value; $plistArray[$plCounter]['directory'] = $value; + + // + // Set up server side Alphabet Navigation + // get the first letter, and if it is unique, send it along in the JSON for this item + $str = strtoupper(substr($value, strrpos($value, '/') + 1, 1)); + + if (!in_array($str, $plistAlphabet)) { + // working with only letters for now + if (preg_match('/^\s*[a-z,A-Z]/', $str) > 0) { + array_push($plistAlphabet, $str); + $plistArray[$plCounter]['firstLetter'] = $str; + }; + } + // + } else if ($browseMode) { if ( $element === 'Album' ) { $plCounter++; @@ -1841,6 +1864,12 @@ function wrk_i2smodule($redis, $args) } switch ($args) { case 'none': + // + // Not sure this section works as expected, but I added the "Remove" + // commands to address what could be added by selecting Transducer + sysCmd('rmmod snd_soc_rpi_dac').usleep(300000); + sysCmd('rmmod snd_soc_pcm1794a').usleep(300000); + // sysCmd('rmmod snd_soc_iqaudio_dac').usleep(300000); sysCmd('rmmod snd_soc_hifiberry_digi').usleep(300000); sysCmd('rmmod snd_soc_hifiberry_dac').usleep(300000); @@ -1848,7 +1877,8 @@ function wrk_i2smodule($redis, $args) sysCmd('rmmod snd_soc_wm8804').usleep(300000); sysCmd('rmmod snd_soc_pcm512x').usleep(300000); sysCmd('rmmod snd_soc_pcm5102a'); - break; + + break; case 'berrynos': sysCmd('modprobe bcm2708_dmaengine').usleep(300000); sysCmd('modprobe snd_soc_wm8804').usleep(300000); @@ -1905,6 +1935,16 @@ function wrk_i2smodule($redis, $args) sysCmd('modprobe snd_soc_pcm512x').usleep(300000); sysCmd('modprobe snd_soc_iqaudio_dac'); break; + // + // Adding an entry for the Musica Pristina Trtasnducer DAC, based on PCM 1794 + case 'transducer': + sysCmd('modprobe snd_soc_bcm2708_i2s').usleep(300000); + sysCmd('modprobe bcm2708_dmaengine').usleep(300000); + sysCmd('modprobe snd_soc_pcm1794a').usleep(300000); + sysCmd('modprobe snd_soc_rpi_dac'); + break; + + // } $redis->set('i2smodule', $args); wrk_mpdconf($redis, 'refresh'); diff --git a/app/templates/header.php b/app/templates/header.php index b70d22f5..53ae02cf 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -1,10 +1,15 @@ RuneAudio - RuneUI - + - + + + + + + diff --git a/app/templates/playback.php b/app/templates/playback.php index 0a83fc56..621b0297 100755 --- a/app/templates/playback.php +++ b/app/templates/playback.php @@ -66,6 +66,10 @@
+ + + + @@ -314,7 +318,7 @@
-
+
-
+
-
\ No newline at end of file +
+ +
+ +
+ \ No newline at end of file diff --git a/assets/css/runeui.css b/assets/css/runeui.css index 20bd20af..a7fb6b83 100644 --- a/assets/css/runeui.css +++ b/assets/css/runeui.css @@ -7,4 +7,8 @@ * * Copyright 2013 bootstrap-select * Licensed under the MIT license - */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:20px}#volume-knob{margin-top:20px}#countdown-display{position:absolute;top:125px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:125px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file + */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:20px}#volume-knob{margin-top:20px}#countdown-display{position:absolute;top:125px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:125px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}.overlay{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}.overlay nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.overlay ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}.overlay ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}.overlay ul li span{font-size:30px;font-weight:300}.overlay ul li:last-child{height:20px;line-height:20px}.overlay ul li a{font-size:16px;text-align:right;border:0}.overlay ul li a.share-twitter{background:#55ACEE}.overlay ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} +#overlay-alphabet.overlay ul li { + display: inline-block; + width: 15%; +} \ No newline at end of file diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 7cbcfaeb..28681728 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -88,8 +88,10 @@ function checkWebSocket(){ if (window.WebSocket){ // console.log('WebSockets supported'); return 'websocket'; + console.log('websocket'); } else { // console.log('WebSockets not supported'); + console.log('longpolling'); return 'longpolling'; } } @@ -97,10 +99,10 @@ function checkWebSocket(){ // check HTML5 Workers support function checkWorkers(){ if ((window.Worker && window.Blob) || (Modernizr.webworkers && Modernizr.blobconstructor)) { - // console.log('WebWorkers supported'); + console.log('WebWorkers supported'); return true; } else { - // console.log('WebWorkers not supported'); + console.log('WebWorkers not supported'); return false; } } @@ -412,6 +414,13 @@ function renderLibraryHome() { $('#database-entries').addClass('hide'); $('#db-level-up').addClass('hide'); $('#db-homeSetup').removeClass('hide').removeClass('btn-primary').addClass('btn-default'); + + // + // by default, the Library panel does not need the Alphabet nav + $('#overlay-alphabet-open').addClass('hide'); + // + + $('#home-blocks').removeClass('hide'); var obj = GUI.libraryhome, i = 0, @@ -898,6 +907,14 @@ function parseResponse(options) { content += '">'; } content += inputArr.directory.replace(inpath + '/', ''); + + // + // Add an Anchor tag to manage navigation to the first letter when the PHP returns it to us + if (inputArr.firstLetter) { + content += ''; + } + // + content += ''; } } else if (GUI.browsemode === 'album') { @@ -935,6 +952,7 @@ function parseResponse(options) { content += ''; } } + break; case 'Spotify': @@ -1113,6 +1131,21 @@ function populateDB(options){ content += '
  • add newadd a webradio to your library
  • '; } document.getElementById('database-entries').innerHTML = content; + + + // + // look for the named Anchor tags to see which navigation letters to disable + $('.alphabetTag').each(function (index) { + console.log("alphabetTag index:" + index + " name: " + $(this).attr('name')); + var button = $("a[data-alphabet='" + $(this).attr('name') + "']")[0]; + if (button) { + $(button).removeClass('disabled') + } + }) + // + + + // DEBUG // console.log('GUI.currentDBpos = ', GUI.currentDBpos); // console.log('level = ', GUI.currentDBpos[10]); @@ -1121,6 +1154,13 @@ function populateDB(options){ } $('span', '#db-currentpath').html(path); $('#db-homeSetup').addClass('hide'); + + // + // Show the Alphabet nav button + $('#overlay-alphabet-open').removeClass('hide'); + // + + if (uplevel) { $('#db-' + GUI.currentDBpos[GUI.currentDBpos[10]]).addClass('active'); customScroll('db', GUI.currentDBpos[GUI.currentDBpos[10]], 0); @@ -2170,6 +2210,10 @@ if ($('#section-index').length) { // ---------------------------------------------------------------------------------------------------- // scroll buttons + $('#db-alphabet').click(function () { + //$(window)[0].location.hash = "R"; + $('#overlay-alphabet-open').trigger('click'); + }); $('#db-firstPage').click(function(){ $.scrollTo(0 , 500); }); @@ -2244,6 +2288,33 @@ if ($('#section-index').length) { overlayTrigger('#overlay-social'); // play source overlay overlayTrigger('#overlay-playsource'); + + + + // + // alphabet library navigation overlay setup + overlayTrigger('#overlay-alphabet'); + + // implement a means of scrolling to the selected letter, + // plus a little to accomdate the fixed header + $('#overlay-alphabet a').click(function () { + $('#overlay-alphabet-close').trigger("click"); + + // ** + // this may need to be tweaked to play well with other hash tags + if (window.location.hash.length == 0) { + window.location.hash = '#' + $(this).attr('data-alphabet'); // navigate to the letter + } else { + window.location.hash = $(this).attr('data-alphabet'); // navigate to the letter + } + + var scrollTop = $(window).scrollTop(); + var scrolloffset = scrollTop - 80; // use the actual height of "header" + $.scrollTo(scrolloffset, 500); + }) + // + + // play source manual switch $('#playsource-mpd').click(function(){ if ($(this).hasClass('inactive')) { diff --git a/assets/less/runeui-custom.less b/assets/less/runeui-custom.less index 773441d0..af1d5e48 100644 --- a/assets/less/runeui-custom.less +++ b/assets/less/runeui-custom.less @@ -1229,6 +1229,68 @@ select.selectpicker { // Social share and Renderer display/switch overlays // -------------------------------------------------------------- +// +// Overlay as a class... check this. I just added it to the minified CSS + +.overlay { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + background: darken(@brand-alt, 20%); + nav { + text-align: center; + position: relative; + top: 50%; + height: 60%; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); + } + ul { + list-style: none; + padding: 0; + margin: 0 auto; + display: inline-block; + height: 340px; + position: relative; + li { + display: block; + height: 60px; + line-height: 60px; + margin: 0; + padding: 0; + -webkit-backface-visibility: hidden; + backface-visibility: hidden; + span { + font-size: 30px; + font-weight: 300; + } + &:last-child { + height: 20px; + line-height: 20px; + } + a { + font-size: 16px; + text-align: right; + border: 0; + } + } + } +} + + +#overlay-alphabet.overlay ul li { + display: inline-block; + width: 15%; +} + + +// + + + + #overlay-social, #overlay-playsource { position: fixed; diff --git a/db/redis_acards_details b/db/redis_acards_details index b17156d5..3b4505e6 100755 --- a/db/redis_acards_details +++ b/db/redis_acards_details @@ -62,6 +62,8 @@ $redis->hSet('acards_details', 'AudioQuest DragonFly', '{"sysname":"AudioQuest D $redis->hSet('acards_details', 'USB Audio CODEC', '{"sysname":"USB Audio CODEC","extlabel":"Behringer U-CONTROL UCA202","mixer_numid":"3","mixer_control":"PCM","type":"usb"}') || $return = 0; $redis->hSet('acards_details', 'NuForce USB Audio', '{"sysname":"NuForce USB Audio","extlabel":"NuForce DDA-100","mixer_numid":"4","mixer_control":"PCM","type":"usb"}') || $return = 0; $redis->hSet('acards_details', 'Rotel PC-USB', '{"sysname":"Rotel PC-USB","extlabel":"Rotel USB","type":"usb"}') || $return = 0; +$redis->hset('acards_details', 'snd_rpi_rpi_dac', '{"sysname":"snd_rpi_rpi_dac","extlabel":"MP Virtuoso (I²S)","hwplatformid":"01","type":"i2s"}') || $return = 0; + $redis->sAdd('bcm2835 ALSA', '{"id":"1","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi Analog Out","hwplatformid":"01","route_cmd":"amixer -c *CARDID* cset numid=3 1 > /dev/null"}') || $return = 0; $redis->sAdd('bcm2835 ALSA', '{"id":"2","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi HDMI Out","hwplatformid":"01","route_cmd":"amixer -c *CARDID* cset numid=3 2 > /dev/null"}') || $return = 0; //$redis->hSet('acards_details', 'snd_rpi_wsp', '{"sysname":"snd_rpi_wsp","extlabel":"Wolfson Audio Card (I²S)","mixer_numid":"1","mixer_control":"Playback Digital","hwplatformid":"01","type":"i2s"}') || $return = 0; From 723c411c40c13878fec7a5979bc01a62d2289ab2 Mon Sep 17 00:00:00 2001 From: kdubious Date: Thu, 4 Dec 2014 10:06:57 -0500 Subject: [PATCH 02/80] IE fix for header + Added Transducer DAC Settings --- app/templates/header.php | 6 +++--- app/templates/settings.php | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/templates/header.php b/app/templates/header.php index 53ae02cf..62c5dfaa 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -4,11 +4,11 @@ - + + - - + diff --git a/app/templates/settings.php b/app/templates/settings.php index e6c5089a..308ac5a5 100755 --- a/app/templates/settings.php +++ b/app/templates/settings.php @@ -106,6 +106,10 @@ + + + + From 67dce745a2057d280e26639db1677c5f24185dc0 Mon Sep 17 00:00:00 2001 From: kdubious Date: Thu, 4 Dec 2014 11:09:06 -0500 Subject: [PATCH 03/80] Ignoring the Logo file --- .gitignore | 3 ++- assets/img/logo.png | Bin 2096 -> 74506 bytes 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b1746bcd..2ee8d486 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ test/ sync.ffs_db -node_modules \ No newline at end of file +node_modules +assets/img/logo.png \ No newline at end of file diff --git a/assets/img/logo.png b/assets/img/logo.png index ea63415fad4b573ccfda4d408cf093e01c0838e7..5823154e2b4aa8df26976caa82e046710af81275 100644 GIT binary patch literal 74506 zcmbq&1A8V-6K-tVwr$&Xp4c1PwzIKq+s?+e?Tzi^?E9Vb4^CfI)m?MXbXU(@UENg^ zsiYtY4}${(1Ox;xEhVP%ug?F+R8SEAq$k~7`o9XySwvb5>R<7JGL87BLpw-mI|Bj1 zqWs6e3)_C5|1RRWh-ub!x zNkh{k`zqa5PFEdkR8dw}Mpx$C`<(tURz)|TXtE#8#Th0hO+I4Kp%F9TK%&$%Yf$9G zd#cpnj}XZS6L=Bxq)((Qhs8nTWtLmUP(}kH4(fkJ5ZgrV)BBo!Im#yimfL;8)9L5s zYRlR0CHEuyl<&pw`J+tmw=xUN{DRb?83b#Eix-9bDs|^liE1&%?4vgG+;YrLO$yef zO~247{#nNbhZmlK^3b+C*7y3x637RHWuz+^dU9g<$74}bC=_1Kd8t48IVF;NwIY<{&w))Kn_>)1py#~VW=*R zhuOD3v_Va4L`T&T&d(NZ>Mcu4aA04 zwL9&zXJ`0g7qBo+Oa@0t7D@e~QBH~=#)9hCJqR4K6OG)2_pb=}>j9{qT@o=8q%m;> zll_8v2S4#?Tr!9@@C$r=(?s8AL{)|Dg8DT9^{YbWisr+JQxQ&}C`YzFf%ZuV{BE(e3uCKQ~CV+a$ZE-nz1^8=9EIp2MIJu77ER8jx1~eceNlEAC`w-ijUis=0sF zaZJghEQ6ex5e!${@xwVijXykW%QfBkIo-)lXuq*kb4Kk8Ip%8U6{;*zo!qZF_eR~# z)=)T(Ie*0N{lr)q<}!#ot`o(jZF#hx7RvB4CNb|c5Q?$ho9ucSwh96?oS0-d_R^`I zKe3$pGynS4Tc9#eMD=mEEGw)<-RrZt_xXhTlRf+PkE)uUvi!O89yIM`J_Jvl1^!Xq zfBM_!|KRM|iR8GxY=7&!l;&fT!071ciyu0>trcTc9hQz;-Sk&~o2Ts8j`gOM=WEiB zaVBgMKb5YNOQG|I;TEqiVEP&qwfwABy??$>%GO#$;(cf0`#)#-kN>|4bunuJ5KxD& zt+kq}NA_jUdMe)NZ=%e_ZIod>o9T1Uc1Avn>+FwWyxlZOG#GHhkdjWAy+X{KYJe2L zQ8}21Oh5bm#o8QspI{$5_ZnLr2*x;Sd#pM}4i=Hsd2{-6KQB(d_x<4VbG>T#7}EkV zuje3*(xT0q(cTkE}b-!4({?Qb@?)03tes0760ldSXzTW{RqmL@s+;+P_dXmpP2Q2@!! z(jKUD&5Eb9Su!u>W@6q`3ni;J0EB zu*w(Ywzs>l4_xiu>I<#%38^wp8;yT!(nQb)3*z>pJ3j^!K)WT$#EfK2Q%`>*G)d3! z73c!b>ka7pfx77pULC%qY;W{R;yTp)gYB=!^-({(zP;|;Ke=nZJJ^ER^rWy=4#9bW z-)>aYuFU}1Zp7=*{>Bwlg zc?9g5Gg+$wGXATDj}gy@P3w)~XJzyvv%nd+d&9F97Pr?HuQuviEk*4|xUM}P8Vr=z zo5Q^y9N|UrI(XZ`vw5gp`~g*h-L<}5;RI`-oR?2~CyVr3fZzVL+N!<2aK6ngLln-6 zoo&zid2QWoJiqF4I;_1-D+a871B+aoj@)g=jw?%S#!6l5szpWX%{WI* z^lY7ukD>J=a~NSn zDR!M#SuwQjkgeb6pt%uOA>!}OSfMJCf7L-syB;Q5D}`xhZTAuexeCwOO#HamPO}fb zdFOg(+B?&|hfWI!6o<-kTkDYbLKXkE^QT%*1JFsjo0HsLIr*biaAbNUd zG!`*9ZB%A@$@Ox^oLmNrZ{&;Xra8!KiJ26lM4N9{%6~E!{uY^AjT&YZ%GIjdpPqk4 zs5$IaRY_-@z-|ut;HVtjSSyFNyg1UG^f4XP6TBgw%yGxSgJ~a0zSzkoaBT&=oY>g6 zW*Za5(;7@9AI*28ecap`5?Iggbr>!3h&{Nrz#vGWWhpB@b6CY1NO8*DO^4NDcR-<% zuCU8d1FBrdsVn}ZqM59*z_-c;(=XPWkpkUK4^tS)Hk-{{Uj>f71U>6bee2x*=mm@K z8vd4xBfwZ!Zz#v14K=!d$I2meN`vxJL3^Nz07In{Kk8Bvvd(0!F1* zWFlfm5%Ncndw;t$`mp2o)*q_>AWFY*m6tN#LhGckp0_F4i|>q>YRys!@A5YF^54wd z+fAhL7s#}y(Z}V~>ekp=E~=aq;e(=@VAc5x&nOA1VH~cA z5<3h{@nU`0)cY9y%yDhe*tYG3=+n!I6eb9;7wBNw8m%phvy8XJNl4Kc`D_(mIsBc8 z1(#VUA0hqf4D*L^18&yttrhD@g{B(E1=0-+H8mQ-zHoU=_BR)G)e4La+-DF1a5Lwc zGyOXtxX(=YSF;UsyGw<{2&ct%)>UCf(`_j$vEr;wjkDVd_R;C4z$_NEz}fEu>^Ghg zn=xa9+$$SmwLbE=lt}ue^Xr*e;`K%|=sTDXTtR-T3daSdU*L?)e8D=wPwcE^na^gS|O z|Ha;u$PrZ$Mcymz{0vcjpY9^L$+^GyNqnH;}C*L|V%aMFol}u_j zr)n-al6Ir*En`Ss0x zkRp^k1L|gG9Ufd`sd;Tm*xl|7ycAo@cOLS5^{`@iO6RawLA6}43xPlxU3 zCJYuPHc#*&dse0A16~3(&O4#F@B_c2J!1hIZ`X~{edk^j_-#7JSR@sXT$f!wPuqf19O*)T%!8Q8oN92$GKpy!p7+F9qeMBvhA4d4O7shd_Uc9So2iO5 zrR%1z*{`1EJsIPhU(CM}YqxnM;+O%6Jf=nM#!sclh2Lda87?+c1#S+vV=x z(^(^2AmNS7aktY};X@A!26?V5jSZp~4jaeyigVw1Lua8lT4MMwS0*S|HgiOHao}vD zDQ?lK++m9)xNRK17vAq2OqcQ|-AVH6!|QQ{vFpRziEGLk%zdRmV|Jk|$sy|8c{F?o z+z-ahQ%ub3lISus_v7Lr;n<@Xwx%CyMT|NLKj46NB0lM|c4R5NXk==98B<~{} z;Q691TtPvre{sqX-@(r)FOUqaJ>0AK!cEVbFQ==bOV_s?%Yi9PV0t@MJOu!Ao@ zY?o;nF8$#!mN4R>ab7(@0f~*{{H--fdvK4EAMQIC1TRmO$bFhR=s!{g0UM?S(-`n5f-M}v5<{VYIYwfyYThTKwF;LK6N-=?HeXDto z1-?<~CU?cmr@Sp<23~I7(z@&%_SI{4MuYvyW9i)%Ym6n1&qCNVx(feetLKSk@i;qTG~>_@n>%Rh`v zM>!pVF7eZKsdunl;`R-r|AAB2P&KrVD(sTBXD_mS9Nr9Fm!ztv1 zLcR@K9|ju`-3qJy29w*%+v3#eVtFZU@Byp1TE zH_--qgqui&Hh8nkpU6DHX&-@D%Ua@0UL;$Pc>%jfx3VjvFI?!J-miN{+0q7kK6*bB z9BE%s6@Q|0u*BZg#K(xlCc)6^7Yeo%enfAkFBhDSRQQfmNGExs)sF${KRJtXmC|2t z9^_A_hbdOYy6nZe_)_lRu`lH4{M8?Bdo^%htsRzKFsF@sOnp4&|MD5; z)>4%mbhUl9P2u*5;PXQ(<~4f^(qc9T>nq9X)6_{|CorGiGLQVL_Axm|1BkBW-*uZV z%G^d3Jv$34znqKGep25K7E>8Hl#Gx)m`PgUv+_3Hwe%4XI-P=8S?Jz3r3X_WRF_j{Tv2czmF zY8F06R5Opp=oDQFfe={DX_e{@Y~S1`bJqrdZPLRP-9EkQad0Y44|9}5O}k(lxhk3` zl}~Fr-x$4#3jNBV(`SJ^!-hT)gnuq8+TKrP+Znw6H~fD1$o)=h8*8expSG4_fHZy)Vsp+oZb-u*De=e{rWukTp_3bM?B#!&}$!mnbzVTA9)AuH@&U3Yn>8>zq z(96^73;FYgy5DCDUpRmd`@ZAI>t-%Yj(9P7xM|SO`LhX!vGQ?T*2LQc|5RP{+>O|0 zxdEHk5-!Qs_ui(_R14Yn#Z@by#>Q{|?D^5hk)_qyFZqT%=c!LC)7i)55VBs^;%H*!VB`N=qP)Tdh zEGf-Ly1lp^P1*PB?=EC>{73QEvUk%DwARKRf7|s3bj#FF&y&V)T@Bqne?q@mub=UC z3eN-YBeTn}`tz?ek=NvdM6O1hTOM9wMKe8s*Zoohv1EjleU-%nklR-id_RMSk%QRy} z8r-wVo^9{b)tF?Ug*P5qQqQeleDH#61eoH>*sc}d5VPI+Jk8rNw`*B#gvE$oM$t6n zqwMFhN&dsn=3M#Lw*8&}mi!0xZzw{LUcb^uOqpN_jGi&$moK6gm95gBd8&1e`pM)96^G`+koF`$PKGub|FQOd( z(huTgM3i@;f`1}UTO=zu#P5{Mg^|QJVGa`dpZHlq$s{Cu-e`>88OP=rL77-U7KBMAP|qZ`#o`a0))2{z1^$F<+}1ORfp_JVj*=| zt4b3$2Pes!Tf9@YdCglZtCtn*?_H_8^|e^VKLzGj6RqV^*ADgKyD{_=FR5s`;>S4d$9DX3cM1bK?Gx5RPn6&dzS{StSML1T ze}I7p#Ks0nGdBAT*6^77j#;L(Z)lehghF}Y$KMFNuR!mK`@8E@pa-b#_kg?o?l4yVTN=V!Dt!ZBG>J?^ z&-J91PLiusoxHq6g&V;K1E@nmkZV7vM2_RO**${I*Q&SUi~Z=Yvkt;KABbm$+_SH~ zz}>l^&y0LxSLA2;lLYlWBu8+BHz&ijSAJ*QyHD^hUU&JhIHlQ}UvbZ`Ti|r5zE?GLm8_jzdoWwijM55fZ!-#D>+Roi znp}7j_C`AGdB1WV6ZJl1`F0k6)cs7`Zk48xec6{Oj-zI9$4#Sr2~6Ib!ox3iT?g;3 zlGcoxUidA%iMD^Uil+Fvc9uOZ9%-LvYq z-9X(>81or!(}hEw^eZNHTYkh8iaxp-??;z{>P}&;!2Xj`Vay_mx@}{F0Y`owZ`jzGK9fKkQop#LL}HRah|Vs4}^DSY@< zKJ6Za2=%no=_npy)`S$NVpz4B?SJCIyAMm>9b$8I7cg8Vz`+&b)6&+cq zeu7=FeeW4gxU*DM-p(Bbg!ab7J7jhBus^(S(_dvbi_Jw(vjroEyTBXSWcJ^J4-#yE z$X_L2@mSYRlAI|AI8-NNZcG8fqF#238*fqng6U_$GT+(?23T6Ed0yAY*x}Ta*Ilc$ zQ98q7w_Xt1*x(}~8_kY4&gLI?WoJ%GAGVJNxKmtTf0K^>Hhdi^cT^ILpk_uldp#sf zqCBj7DuxJ9jw2JOd$KtYe5ZjMBeQAMn<`)d+^^%!(bAU{mneooxFIp&0V-? z*)79pYq)69?!MI(6#laJQ^LVsTpuq`tNsccqH8XvECRwyNM|bl9UxIgZp@)8XD?xAV1|GY-AH_{N-~ zDE2RK1g3Yw7=)&G(}~0Og@g2z(f+U=?{PLi=u)w@sLjXb(z(vky}EFv9tHxy6g{c(Ztad0a_K ztBbP}^mzUy`qRZ{wIf^7t#3e(1L4)D*b&v&zm0?YqJ5K`3LAAx#F;mE`qTgALV<|uF+KUE+dd)L zPUGhJnJ(ykyeCeSemI(_udpWy%vk98`xQiYziKh9PJuvRpwCW_Ybb3I(&b}OH)I|1 zaj(oHlGWp(_zQP#kkLLzz*2wa?zzowyR^>^e{qsKKzoQY{tnU|nX2nkuTF)a$q=kfGb#S%KFZ%(v(B1YlvZ)N_9tR#t!S39JthFQ4%o{OG30 zd8MD{^s36zfV^kN(*?Kh(U?wHmG$*XRDV+0)sr@9XHy@#EzFSu^BdGCbbU6Oj-fb!u|4D}GFsD~Dbx&JSVZ z;9Hbr?feUJ8rJXWhl09fa|2eAdkuU%i-EMA!s@VG0H{u80tM&Yd-(+U>k_0KjJCJ? zC!hFwRp=bDtvBrJtE}sFV3GBp1G0wnmOP+`NV$RN@bv9C7&4?V{PeLWybXHl&eu3# z6Hy6eOE{tJCnRszGvKAO`}076?*VfC zsS)Zmy10KF`>Hglsp({+=j537zy!&ljEp9C4mF$4FKCzF8;m!sE*lUr4TE)EHBAeS z_wjl$T_xxQvD@n#6v53O4(spYOdR5j^Zn-{aT z-C8uh?!FIX-&3@zMoBZsIaKGi0BDmk_KgUFYvlu|&RM*KXZic@$)Rhnvaw-7*q9Pd zWW2oJmZ|mC`*TDB`YluUPG+bn)g`RYI+#T+5>q*BuHhsBuCrFy?(KaFS&$|=Ow=qg zVzZ&h*=YoHJ=L zWqRu;xyE*ATWTq5gmxf?aPfeH;sE(&!}-|^AQTGksT#nGp`4eH$s5IpRFR%nlAWq{ z8ToZTM#i8AJ<7}@?e3Q9^nQW(eAq($54TCJx=vyX?#3WOYqsl)Mn5D?oC1)h#jr4v#IVw`uE)wpx9j=@N&kh~8?qVSE#-KDHNEyk7Qh2^r zt282IE}6RE*Jl+0AMU87b;&`6s&`{fBvd&;_lB5jRIV1mMc89_R> zYtmVAV}>kf&~7X2LcVK=G`p^%Z&2%LWqXgIqC8pONX`P)IYF?wLUO=oh(H$yxkz!2(@E9;!0%QN11|$a*fdZK@ReyttU@-#q&k|O2*ij2q1;Sz-qF*q=7gHFg0cJ>RWW46 zF@(yM{>p>G{y9vu)D!4!ey4aPnzkv0V)vu?I6HKC!nmFmIOfI z0tyF8OH0^qsU+D+Vp)jFRCKKa4D&1Hx8%R@5yntS`4R{fPz{3RQYF!UlwAhG=8`Tk zUdm;m4{2#Q6ktpv>O5WxezMOJ1Z<*|%4{~UjvdsXgMH|2YJxHKM3OEJW4^RX8zAg% zFD7u3-TCkFBZ-n4ccMKT4>2YhZSBI>BV_#a-Mu~Wkl>~>TgL}4hu*MEF{V92!hWu~ zU!_#(d>(S5PwB7up}R%9+(EcZ4fN?@zgzGlkTm{0l6X=@q79y@t=R)L*^JU9h9?H7 z+5uu9U~fDf^XU6qWNla~b$*kYhKqCGa`T8~akt@op0hNYfsDvH;PYf4Qs9=4lF%C1%*%2+ z;PZM_bZGABVj}zgo`dy~hWJGJQn$6uNMb~BvRVpb0r?Grri3jcLcf-S@yZpnKQZ1I z)2HAM zOi{-8>qAz_d}Zm%7OxHwTOsT_g>XxjZCG#(1J5*0kH4~t=DQJw6oP|W|Gc1d)k2&6Dc?1VBL$2 zW4srxm8&I(LE?o&1Os4F$T3o8G-ZZXqvL~v4Ac`bPhPZ*OgO7_0Rx67<@cRVWEQ+8 zagiU@d{9OcRs)4{Q_eb<{U#@{ruqR8v?-M!nNrUWmP#&(2CyIVRyATiB8UuP>s-jv zL?W}~?M-oz&LEeJbM$6RRzMT^ABLb5emZ*Dj3L)Sc`fwbx4RU zx@2Z?WpY$LT8F9uodaOFwaN5ix}XMV#D5EYx8#&AD6Z0jD(y1jF5sis0ZOO|5Nv{0 z0L`=$g)2&)-a6(TRs{rMqgF=SpRN|}O|Iv|G3^toUWp<%bW?oG2N8pGXC|pdo-VP( zf?AliXTWSd`CPsc6)ZJ?74HqgS6CS?b4Zk5oe~>|zGhQM=dE_2cCmw5Kcg&GW^fotDMN1d9#_w>v?@Xch{fBMVh zJhw7AQ-RPqoh){CnXhyxr^c6o8Fu$%BLyZdA(KGw6Dxdv#-+om{V!TMav!TC&V8di zcs=cj*||51RIrDl%y*E!PQl#CuScMjuXK(QWqkv|cG&mJb zy~7A?9$WjE9NNWDVBD7R9v3=T89erY%gC>z+Ur@WdP2|A+X{LNY>QQZm!92wXg7BU zTg@02QaLx`ooR6*yBVaQbRB7FP1`*5O7^mv1|lE%+PQuQ6zEia)R{7Vct!GyE=gAxTWsLo&})&RIcA&G2SaRGXm zB>f^uz}<+pwzA6&3e%yCYvO7i1I(8V{PUk&eg7yDHEM;F2fE1BJd_x`qbN4FgQv1f zlhaaYkjvAjvZ+fZPU6X7q<^p-yiZkuR6kV8r%8F1XS}2gEVOY6- zCPKDOHSRVejBp})@Y8%ni%P0!vNW2A(R!sYJa)J8sjocK5Sby_>mbdDShcI=z!hdF z5YveCIVmR0+U@Zz03}oibRp1}bZDhfC*`Ex7c6=UcUka5-;%uhY} zx*{zFS``|SLXij$D?u}%U;`o%Ca zM@(vGm=)0oU?1mDPftkcHkcTi;HZ-xs|g4nzy6!gG@D$b6{DEawb;YLP?BtlPOd2G z1bfR3?p|8`o}ndv7<_EWjHpU2+{BdG>#q!!_Kq?` zMJLdS1;fdmu$#l-WYh%tGEm0ZR58rR1yn5_$SY?ts`f8B2hD2Ax2!}b7=%G}v$>C} z!KA(Kb2d9nkk`Ej9L>w(lzg)Oc4&xCCO<~>=lro+L~W-viF92 djM2wH^bIg|5i#n#> z$-=4WB*qO#NWCXPX2f(`A&@FKGaUzXuUOI#>9?7o z9Bzm#QeNgP1KzO;6t6QSyfVoVdeWwtUEvmxjZ!Q8bXm9x1WO*5JBHw7cFEf>Brkfn z$ov}9$(IpQxd|gHceTj4=~Jb8X~Z78abncQXu6mUCAJs2SHXcSLh~EsVnUBm$x*}} zbthV(b7Uo9nPeKi%wpzEV0*M?ShFqkpp3Ni6S!dXg}JHnJdp!NK%1E# zbAQiLz~iP|7-fGw&zJmx;wu|Sz0e}wVzC?*%_nhPOYW>la>}?iTN~8*YmC|V$4i!J zQ*A9ppL@5(tjMx)u!wW+DIJCsYxa>6^luIg<-J3d^s#5PH0mB}(e|1Q?hT)-R?FA; zAaq8lnP_+;1h)0u>4t>?1vjN3aolf0R8wTu%r`(Vi=jRUanuo*;EdzxcIq{cZ5@m7 z_H#}8DvpgsSCJ@p7r(PK<+37=nfiHgF>0m$wAgJ>|9#WmZ*?Kr0jP_fNV6`Dpzhi; zE;MK?Em+nb5hYvkj$D3ez5xtY{YIr~&=va24X16pL=O;s=ZTTX;ljnBlKp@LZq~ zX>4E3%6e0?Q+DYm)2kV2?cdeX+|+9djS-`*d`fPHRJT!cUr4H2LZl)^%+pkR-2kCf zGz1W=*b>Z!O8BE1n&^vS2c&+kGP%_S`OpqC11@S@FjgE?a2kxi)C$9_A1UzW)pybz zaDYS<=KBC?C`#YE@kfkQVJa^I(1Eo-1`H8Px>_UkxECd-{b>wk*-3z~Kk4+AwOAyh z#%E3ryyIq4bd#=)X`xIa4^I68(&qiwDiE?3CR+wUZna|~0J05-Gh}%gk$}B`n#g5O zV)8;7ob4n$uy>d}^Uk%uHvIMXx!h36QzOI106G(N^d$u+q%#@pGLJuutNA@N8mvU9 zJ3Ec(j(nE$BZQ&^ZC(Zl z5_2d|+)|h7KD()1w`5>U9a}Dnu_93_c!+R)-kPtK1X?d?mn6f*xt>k;V1;ksQvAZ7>D@uCEIDePDXtxmEeb3( z%U|&-LrFJqWt9Y9HKL#?mznn5&|kgaEpjXv=BpBlrS(l*B0m&k-ozlCGZbN10Iu$l z&Nuw4tNg3_P^*=}W$g_@GG!j9nd45&l37)ykhE=8o+aEN#OHA)u8cq}zO?v!*(Ubi zNy9>mHsb04Xbp^p1niSx0Cc6tG;uS*(LCxQ+0h%@LMb2<(^JlHOm1DDuP)88bcYa< zr_78ev=QfYKi(p{p>Y6|gyvPJ9;?hO2Bxu7f)6I;B+LZXXcs!aTxlR7dZ#Vd)$hTH02Gx@hu(gN98D+_}$pZGz-x-X?xzRj=| zZ%;3l#-STU4=EQpTybrD%hjGiS7TB7V_d#0War?c`5iX#1Smw(&Trd!0czI}XbU5) zy4G!3qe;Y+;n{~aDpYi;UO(30`Qr>h>Az6@0d+*$_6cE!y_W-I ze{i6o`NJ6*fZtY30sf%;SGUSGnS3T#x67W1uqbJ3m|2x8S@eo<%AN)+ zIjRDj&$(RcnJhK_PM3*LU9sM1+1yc^k4QdF99DnNgEFwL88+Y z{mMmvm=~)DLlGPLq4CL)7Jjo`dcYaT<+U z_7ZB6O1ZlAy0;b9l99$FvncEtII6^5BdQsrhcIQHVADcINZ9$#kKX{anYtVtb&!SH zUE}e&kOgl^|85MeIv&Km%3VX;KMIaRes4*(Q*cHZ{5K8jZ)`qS>CFQ=B0M!~{tN!X zRF`Pg&annTA_Dx;bB|6631ELC6U%DLlTC}&P^7rRA(bd(JUWEqnTh$)Q#@P~G0cKJ zBAyx(>Jd>N$-{Z!oiwEW@drOemQ;dMB`_gZK4xCp>h1#3Y&&tFC4(AFYlru;m46L~vns{{45N zn+sk+(<^qdfp6sS=idin+jVcMN;4%G_`zk&0hZ|qStYs}pLpp;?%Uyx0X4}svNiEWXe#}Z( z5>L*&_*}DGOO1H%@P#rv;=?3nkd+=55~4W3pgUd@gy(g zO9ugi5`6=&h;Zr!Mlah49kep>9~^^ylICTs&#Q}2Oi8{01OZFxUDjN1s?wDC-~NrA zj$t;V{k2#)#cl1cGRJIvq8KGg%x0ExGc6M`oWhHpNTYq^Fzs>EjcP9^zU;3;K8c<} zTQR1pL!+$<+%41JU)LTttjaZ8w8fLMG+u}lxO}UBSWJmn31yxn)#{jLrBWYnqFS)r zGX#KpK(`nq8x?fq!cK@rJLldM z_uI`3=cqkrIondEB%J^@q?bcoI^EM_Lm;{K9cm9sx8XW~X6;(5HREi+>ahCSwJEKQ zxIVb-5P{95v=MB>00DZkrS@z(MmF4eZP*&gDt4$@^ucIOSo#d2*tuMpk>HnMBE$i| zp%eBT0<>3>OjXcl?Lf4KfMq>0)o0NlKyfW9(F5U5iA+of-`3iv@6e9^1*1w~;$0p` zS*-k5W_sMBU`k=^U0QqFf+Uf_A@t^;z!UYR?zQz+d@!Q4)=IoKk|of0zSt*n%4MJl zMoEVrY-K=TqFhA-0S!X(z!+h6688Xak%4r1jEUk~Sqj+|KQGUhOE%NV>s)1ozcaz% zj0Rs#=JR3{(P7Xy4lcK<6NN^=$V1qR?qQfWa16O{jJa?O8i=0Vg;CZXjr~QQY$WW;3Ja@Z>eWdtn=Kl@btUQEeBgvnfs+0VE10 z*0GFX>)Zs;6V;dFaC1dQV@PG9(QPLgp;Otp&JOrdl7u$f;D}$ymi=Ma@;dtiksbT` z04IZ(ZfAMmfU_f>Y~=n;A{Kq{OygjmXyHqX{lQH+nYfKWHd+kXmkl2Bm9GsC!CAC0 z`mRQ+NQ?L5FmGk8^7LzH&WHRY_*@!HLWpE1sn0zv>kij)*|F9@?)|+{vrZ#24T&Bx z*2vJLJLHC8`NwpWWa79C?AgA3<{TJw;q%tBo5vZtmUQxYKB9$#0FV^vQKK^U@+_89 zXBsHSasCa;0TXoxF8MtrL;|cy`9~FJLnS<6)r}*BhuWRz8Sd~?v_Ns@+RNg(oML9J z#c}T0lN-bE2jkWp+S{eTdD}}fcN`8wx--eAYLE2#Q2prH6tkiDJIe_bJq`glt=YRz z+ao2iUzBrn?{5U?A6CwqVX8(RrsTDIFODZf@8J|_cc=kW(d>F=g}6vXJToyWBGQM0 zTa2Mr?^@(SW!9%GL9b#97li;753pj^9#C2I>J^DXYa@9zMz^>YXX?7pWa0>P;#<78 z1-)qiaE{ku0}uTQHQF(LXW4WSXm3Nfyy-$1*BZ*K1HPip@nhwBsCTFYLwS76L9s7g z6;)*qx~>u^p;4Bzy-)Tdgd+Xea-BoMTIm{6VZ(xu%rfp$5gg2mkSgD;DCCYtu2Gkb ztPxGsk&$KjAh1R{#sszY6(3_9tXLEa6Sl}5#q$j`!75N~K0GTQJ)P1J3hV!2>@8y} ziIqUjFiv2?oJ^7lGjnFb%*@Qp%#0IeW@ct)JV{QNnVDg8@7-O!KP#yLVaI=(1as`Ubmq?v{Okcse> z(ee0(3O5jx(Tla%Llb4I42s%HNikEnQ3<#8(f+XU4eX?NvZ>`9US{x!YKfifk}}&n zq(gopOe=^xZvQrjn_Ivt8XTy_m{wziVoVtS49gWi-_DhfS#cXtlNtD=dQ?VJ<=m(L zXdw}YU&=rKT^Cf%L6Y%1jWf96?PPFOubq2nTpuHuEZc#uw=jx_5(C_7d7?TkV$5i) zk#~MDCgfkRSE@lXUYX?Z#auN+WIIrI=GrYXBJf}60+3@?mk~2?M^8zK)HK206GoJK z%u{f(Ybd76J~g9HhRTRLDNF&tRQU$>DZYKA2%X-FXf zURbI>L2AUw9j_5>dQ87{h8HuGz!`V@rO)zK9;b_c*EiSz8wZPrA#!%R;tavm3OWtr zNf?k3mxonEc6apr>%HpDC2(cC{*9j!+!WH43|prIrdz`SD9zZub{gFn!DLwI#7r2Y zo8^x&!c+sl)!4f1z1BSx`CunY$~1n!m{k+Qn~`|El)B^`S~wz}4+^mmKuj3Zw^#fH zPw`xCW|}jJ`J}zN;AcpUlx;~0AJ)rqp(&ogs^C1cphic4!pkPZ#7+635sFTE;S3k* z-sfb6vI~~g?42-o{N-sGaN1;cs}j|&{o~H?g`>Z*k}VsrfD@_Bg-1;J^p<0qr7HTc zCB;6U`rX`ad9yp*nzZL%KKsO?g*pLS8d)LZWl zcDX~ruCN4aC_wKfRGSEjM4i>H`F!lgZ@O@jCBSjg0w2kwf4aQ>Axr8*Kt8fyQiw1NwXR=#3kXO zNVaM5cGK%|$5Rb$3i5ip_ggCbCkhX4u4~Z0>uN3WW*mJ9L@1-mSim|^>H?+A2M=LR zn##HtKXi}8bJk8pB@KFM4aLtvopJ6WdSG}IB~uA3l~d(M@lt+z%WbkgYl5WOc?9li?Ff$=StonD9V;ee^fGh(&fk3N+MkxjE zMdcWWAi<&aw;YP;F-X<5sKPjY<3j&R zf`1^VGt=N?1uWv(rHTBQZN^mdLyJ}&@k&dX{|8Epi=-cU)>qIpL6E&J!j`Rhly4s^ zSTP||D-~y5$2a?iB|oQUm)PZywv=Wna19XnH7@T_#vV;DiKMw{K{doS6&j@(H2xhR z1n0^n3iZ%&*v^iMSCW}n;B-QSohZfuU`IT2ojzg0EJ`q{y##|s8#x)1fLB3vUybmm z$SaV9LV@H-cF8H%n2RNXeV1w+aebF^En?z2+qjX@y;>m%6(UZ2(b;-D zGklPYTQ%Etl7XGew@bmO<6P^-B-aP59@?Lvjy4rAw&Wy(8 zl#F{H5C7oEwWbxQIjZ~KqsdJ4+ow~fphp0-+A0|`zn!bW+bmlkqS~Gl>ijQoyJg39 zh133pfu~IoMX;*{nd?AKKm4M;uPaweuyqH3=_#I=Rd90p5Q@FE_Ym640_Uj2SGWo< z2BjkjaYcVanZtt3MEOX;lNC&>-cS%b`q6li3U7pxKIGXV*mZi4w8diJYJyfe3>4n4 zJSs$8M@lR^M5`+Z(8ABnysfkTP{cO1Ax^Rx1d9c`)j$IHQz+`Vr^b_paj$gg zoW)f@{JOd|FYQ*?P2ba*dG}xQ3C$)e_vaiUn3W%fsepsC3L*7RUF}(nxofVHH ztz=aeiuOd3>oA1%`nWlL;NlMxt>RmVACSX_3maxtmf4m`{h*3!9m|NtJbMRznUWbU z%!h!+{jR~g36CuOR;sh{Xg~8?0&Azpi`$=)GH16dwBOyNg!y$*E6)WZIhcXjMrc-O?W5BaoZD0JGvn=3Tx+Gnmj)TVxwo44bCDYUg0?Wuc+n=47VMu zwBnX3L0T}Io9~vmDeZ^UM3b*dhPdkA`DmBo4(`nBV$OOu{sOz5wW;kH;u8CeR?93c z!IHr$&HA`qU&q_of>jGFEtAuD9?yVHC-|aCyNfqjiaVaCs}NQqlsf1a>gYb!?JgNz zB`2%a&Dq744d*=4K$8`>^y)5@X1I2?i7%kwKaU4R!4!)FHPIAaC0BIq;_b^^%dJls z46Xo(8JG$Hs2g6>Feq`+-$RfQw_>9#L^F}5hpKMxk6VxxWtT)iM? z8TqIwU`=Xwr~Q2}h_WvO{ZoS_ihsK-r^l;_5l)cHfk!35DQ;N3<{dDmc;DtsuABtnCfSFQ6I9E$f%Z663k)+{x%V~^U4(2PmUgul#*>yIfTc3tnBN<@(kX2wVHYk zb_(>ZJw4!tU0hb=lzL66oXiBAVftL6G8!PNxH2HsgvA(rfTe)40);Aqk!c$*>`mvW z&A#2lt4C(X?b4IH(EdV5y5hNZ2}Cjkl)G}vx{}HQVLm>pQlg?XuT(EQHzQ)~WzNb& zYlMz{R+Y2t#pJ=Y`BlRSL*&HxzZ)N4TfyWf` zM;%$_;4dkg_#_x!Ao#539(bnH0T_G+sfi<3Q~s*nj}>fV^|&sAz+}bvp~hn~0_F-l zY7d{t84Uz$&P}T{#SrwaWaByw1RLJXEEjy7%k9-o5THs>pKD`Ye`d;(%!oezk_Gl@ zWSXf=N7NDZ(RR=At-7@nQA5l?RVd`})Xtn6nsfsU&&e_q&y>qLWAO_qRuSdK;;xq| zkUP(xS$MaDnp{;R$llW}p)J#4JZx>tL+>ey0%W6*fi)=O>c&+NT z3RoHo%kU}vl|V6J(zx7fFmApY&Imd?={HCeoNlf*w5tx%0x8ObaWvo;qTk#3djw-U z3=J_RF}^NSk%A|y?1$+xdaUx;yxJNyoXR-*#1iOqEhe}xMWTI|&W{VFIY>wj!5)6o za;eIdn`dQu!=KfM&AW;DPB117=1w)KKo3R6KqCAAajH0vHi4gX@5MYR^!Nec#puf_ zT?RUa_Ar02V>SbrE%K!+&B5$e!#B|c_roGUQP$K9a=oNM3~z`sBJv_EA}zp92(AA5 zH@s3G8Xlv?xaw67{}Ln;b9&(^aZ)o{V#~s6o50ROC2=)~am?Rs!=LxF?)2S8gwMXt zodAJmNvCc&RN0r=UEo1IoVLJm>ZK<3V+#&M#qkOX<47b@Pd!(GLtk^mN1nQjTo(Y9le2{LRnX)}R9=^`w#~oY8uGoKp_a-%TVN zbf+@hTP|NKN(Gg=s?=@H^3xMNQ76&b@51meV;#K8ADS!(paw8g;Z%`>BHTkz1y2Tt z)0O zqnhvZTo%UZ5n7jud^6{Eg+r)1&WWh36vxjH1da9P^7VwYkXKN|*|BmRCb$`@>Qq+G zI2&X{L@&I^0j;TD-R6ZkhQk65*gFd=KiTyCtTOcs#{D7?4MHXvbQr7YE))unW967^ z*mzj0GpWQn&=^&Q`~F5}4DRw&LH<% zt%p+E8flT|g2=^1Ernn;W#)>s{mt^Zu{}9iBUU5St<6=5SjTV*z_EC`Ym3G0yQ)m> z4NUwH&B*sDrrFH;wSkNRWxc2=qtmtMw(;pHD@aWI1|ItTo%cI8>-de1sW)c@!>6|A+`{Z){`kY zV-A;Ao^W=$RUY}WxPWC>;<_Hk`||ZHDo6PHq2Pb=IIe8 z3kK-%NQtAPd^gMKi?d!oS0%3m&Wdv1`gm2x$SNL9%-6<3govl8cu0BsN7e7ZKpq~!;aF&&92 z2%9rrZd4jN5PvBY@Hx3O+oq$Dg&RF@Gt;quc>Tb9l+P1Nze2FW>2(R$W$87`l(g{= zz~sFW%|Q#9wBZL(plOR{rws;~y$-u#m`w(tCEr3cIgzp1xYe#G*{XEa8|U!iha;?s zdm1`7iZUc?sjQ!fS;f4`xo?o?Z6B1naiMUN+ZX>L-~I3Y;8_IcMO5BQdtdV2c0xuI=LwqP_*0bO4~HuFaLGH2MpWJLTOUCgM?7`( z+urAOy-TNN_8++CvE=*Y%9c$g!J4!25%-Bd7hH7qYm`e8m1j7@`WkG87^7JN)Lu

    ;U?4eT4U>gF1Yk8C;C3t>Oo00-}|Jt3u6q>VIcr`+85Xk0ko178p zp<1wH>9d}b`@#Lv2r-S={zXaaQMV>eO>F>PxWjf~gh1vzATo4Ue3LEBs^u_aAE{9w zUJ`NCPcEkz%b*meGF^Gx?A}eUxZ5T;t!2z1CUL8e&y8x<-g=4VepPDBt}chh;ba9z zFXJa$ms8uEDybHKS#F3hD`NSJc^3vr_@?swv>1u25+Z~gd~Y~d;Ou#O@7vFN(?XkL zInCgo+p4-3i<4dDzJT0~gQ?~OkaD!0t{D(JHrKJ2x;?6gGmPg>QASJXY|9Kt-Jb+y zIH^ixJRR$WpkM0@rw?U{l3b(SXHhxDNwM3Wa2KU~|MZ_Z&Q@yG1AiJcEQ+q9i@66m zP_}P3JRLJ$++|UX(O;zDXzeoAC+^9=r?Yos1i5mHD#viVfe1vBZ|Oz|pj!#T-^+-hvpdq!Z}n1oV*<8dbKjO-9_Rr!zh5vJf1N zde!(S8qR5BPYc7Du8*f3_LWS`6X_OJ+tW?Su?xu7=%%Mwy$n$s@do&<5 zxm0S&Cn|w>(7ehw1J$QkS3uv;LGn*Qi0k_5bc@Njc2F6{VQmfEQJFh=ba=`>Cp1nI z3~<$Py%fw0*B-N#+7=ty$k9o($NJmXn>U~7L~1PeN3rcWwm~>3p(t4i%ry*V8{eQd zbpKIyX+T?c(m^=^4sl}@NlR(J(}@va(jyq{n0CNo5sny_!|@f`!K5r|cNk0SUA6q7 zJ1W2cT%dtX>0SQkn}LMt{ss+A7g`h$1DvPLUMiq}>N=V=tBR*^E(G8KSrhY0Nn;NB z3iFUbSPq*LZmR@<(q9vL3iY@^ z9)G;tFL~FP0BOT@=zonQ%cv36j9^!IsgUvWw#^$4%6*eHh&Zp@4aTDj_`oJ?XN-%i zrS&50E)3%s0r&Fr@M6l;>!G5%`P<1g7miRPUE11&vM)1MlE}DZ7 zq(~UD;P2}6bit`tcb%aSbvo)BNU1rk*P2L@@9&mWr^Bw-vif(R@B@+;iYtQ#(=9t5 z@x7Qu_3AWhXEEWwML$0hAs^6;$=Af;5ztUAqLhyxvPa*Hs!fm)DjCdz;gkpEa%Saa zWH<}3ZbMy{V!jqxTdv%9G#@=G4y)aB%v|1Hi;5gn6u&txIsbz>;{K8;LC*L%)^Q?@ zGSgrX#SZTP#zUOv#JvJyQwEw=pG67IuUwBSLM%TIlNEz^9PP2QZYHmV=z{4vmu83} z+V&4=tx|NCF;%4r9D18726q;eU&R6_eDRxA-UfXrSdI)XOztQP z)p~MM-BFrv4~BvecK=4mfqNnw+e$rIvf6!RViF2K(+AkW_P zoO?JcxOGu?uf4SXWolES3G-{)=n?y*B^_m=%I$UhrPb2UKnq#LIr}+N&NA5?jI3pN zMeA0*g2FPDIl0jFqta3dHqT!suoEEAs;8sLpzO2;4x)N9x)=qD5P&)IoKh}z98+xB zj5DOw=#L#^-`5B7w&1v&=YsWnfmD)CGS^%LY3gx)BW}V^D*7B-O^;3e`PbqMHkrx&EGrS+`|!L3#JWiDFZxVYdo%x>j$4TRjswjGeV! zvMZ064KEVkA+&~LLRe(IP#^)j4%MQ@26Lh+LO2^iY329ftn9uWQo_$@j(`Qr6Um=h zok9GB63=&;L08T-7qgU{=I7OPe_X@%7*}NyhB?!9`T#h22Q080@@%ndSBmH%csCtn zr8R>-J&4I1VNWfjn=kqFWm|acKV2z{JQ|8bzU*#mM}2DK1tYiwhGsa0qH_lGHjX#nh3u5?3pmBeKUYEIEVb4W zUvCvoPLY++!Kv`H{(P##s2f4`Quc3h{pAvM*bqy7tAe9H5D}DI&dn0(Ghsh&T>XsG zDXUvF_MK(mNWEU&w(rzd>IhnTtG`}4=Hl*$OvOH?#w#juEw9(L*G7ZrLsiTUf&~@2 zUVVhHfz8r6Ho@zkPr86|WX%R@+i6h=?}DJXoI}HI0Qi1kyR2 znRfzp|4Z&7^Fg1tS4j=9Oba8sd+9Mj>r!Z!`D2krOutgJh*rD{wX;_*KwC#6?hoiC zmvVH$e$+*#R4Yt}g2LXO0>|5{@9Z90fTLXF9)%=OJUM>&mN<~=6Yv3_zH*bm3|g;Pv< zY}0SA)Dm#3>Se;9iW${%v8ZODBNJ0$=vMR;jTI*%r_N79ECp=HXYKv* z6de5v(vhA>2@YNiZ{#qZAAXM)$zYV}^+P#Xi6btZvJ3arWD3f%3KR!gB9^bmz;aWt zoUUB`Io(O>DrgLtZz&80Er}+pE9SSWe-`0iMd&3=$#{q-1a&-QC-C=9(=;E#kS~j+ zW{^uL6(aRl`*CJcrfS)rAJ1kRYRGniWo7#s7lcSO5ZFl?XAyEMIy>w|K$EY3I-5g< z@g7b}-1tXreT?yep6SkV4k5Uzd$in#i45{Z6p1-ml)-sHmue`TMJ2=qCV&6%Ox-9I z%IJkJxU0HcBw|Q^-w5YTgs~ z5l)Rhs;rh6*{__t2=fX1pKKY?8hSF;fk*p|6I|`YQ>5yc54+iPNft&8Sc1ql#i1BH zO?R1Ja==fH>s1H_yvf3Jk9hq}5VrV*Umr0t?APMbQ|}D6AS@uZ1toG(DhCPd0GEKu z20qSI_ER%i#KUOLu>?bR@FO=3L_Yh765}%F>FdJm+DcTOvKz{?ei;idFlacWDtWpv zyv!;s9Ze=8JZ=60D>N;FlDlO8A8?LyPy0-G?tbmleoSRpOg?dbeR~P5=bCusUbBWw zcsxg`vKBwU^{~J$hY3L$E-XA+H!wo3pZlt}(AOn1^R@VH`>hROtau2syrNaqhAb3* zM32CcJ#>S@=bh9PEW?+(XDp3o$sWupW zrdp{i=!*nPyeR`xh_YZ|6N3yGR*VBOF~$n~tp=~}31;zhv;F0*_s`X*D* zX%8ZI?hmwBia?CLVqEDM6hPScbh$8*DM4^^R5KBR&~l@Zs;8j-z|As{#{09OyeuO` z8T{G{AF2B%3W^2wH=@^|v;YKw1PiE=FHjeLM%9&@I>@>hBuBHm%9M|0j1|m=BS`@= zfYk@X5GB(0c?gR2tXU}~+d+VZi-WpW|%CVxNqGf z&9AMz!mW+hL4~vt4`E&EPJ~e(Dfze;xyh5eplx zjVS~&Tq7H%P8)@t05bhlIA+APxINCzh&@s&@^8{DMQ)=EK9bnO@KYiUqVYyc1v9R3 zx=L=qjrxdye}vFka?;UFF(eg^kqU(@D3MHgdOCIjNL}v?U-giko_~Y^b_Pu7O)ijh zWJ4c9odZ3o6HO;2tH&q^iEf;6g&7@0o7J)&HslXf$LJE`a|zD@McS4letp$!4UP^y zeNU_J?d>Aw(@e%0l8yJr?c!X{r9syepaJ^%)^FT%GlMsk)}&{0so|($#`OKRFA&=8 z=sWX0E3}1h`zjWfp@mTIV>SyqZ#S&`w&l|KJ09ryprS)ThY@us9VN_Vy48_@JO#ng3r4!xU)+c#o1 z_Hy%*Y*8nBH;{1XwCu?gQ;F9Z&g_4@ap01yH;Af_AGOz`XzQ!hBhvG*tM=Gjr z<{I-q+{1u9i>UO}(%kU~SDI<`_NJ7EG&udYg$zJ1~_*pG{^7CTEw81!X zR#r2}K>8TU?dEO;yYmg3PZQnsf`aZvMEj~cX(Ig1rS7VGYUj8BL-c9;?r6{kY5NqZ z#&YX25Bjke!IQW3#R;BWbw9^)DbbctkkI;~c5FT2vda7Ui1w;VrjQWTrTh0LmV?~Y zI7nniEvZc@#4a$VNLHk7;j;b1{(k9TmhL~8@%Fxd-6(_`|Dm%VoTs=dB;4dh7vZv; zKuJgbx9okxJ<~Ul%wB&6%|)`8?z^T-NwUhL)cqfr@$V)IYY*W;uHn2Xrk>4Z@-n+J zM!02)@Sd9oSo|^eGs_iK_P!90_rmT81`ltDR?PNR&QE&UW*?wIg-pRtyXWz@^At&& zeiwQMdDMpE_QC^8Lwk-11tCNz@YkZA7%P@S^gyT*zMI!G)_!#_^xJmrT}BQ_%?EhU z(oFPT3vNO|R5NbedP^x9W=G}`T9RkmOhO!`7d{ied7L{g)+IMwpBHLBLJz41NZPHZ z+t=Rt$OdS-3WA-wb){qRBM>~DHI>xeFLnL=Haj%^PpgHN1n_k(zUFaw;}XGI72$Nf zzHj|CeUiR;;vEGw$rOM5QFzu?6T%zT^L~iJ!Kz;+oN4*sU|SaY`KNJp`uX8P{enF1 zI#+rlHh0LY>_5wyYfbRXofY*kW}i5ss>tMeD9Z`$0E8BKclvm+lbxwX5p3&zU_h%A zJyai?a&A`NB0P#2|M`0Iy6#oC7p@m@WG)m`bSqxA72*etz;ffjwDo)j#jWd`;8^#* z0cSfis=sZ@TY*?p-Mnxl$z=7?>GX+|%Yv|srm|w}*i*<{rgyCvZll>5N;PbxnUs>j zT%~4HIKK#s0?eyMog36B>KSV%=jvvj^SY}9+?_CIV6xqoh_V_kE-R>YmX~E(?0M_i z5wB6(-E@E;C@|GwBLh${o%~H4znDr^{IPF;Aek1=lb&Mm#Y-@0NQ=Y6Zlw`w)?KaA z2O4g`d^)yCR&@h^5<=O%GRsPWsc$gY9zq#x*+j?rJ83!I;D=^$U$S|vF;24;1W|X} zGO1N~^W;hw@Ab3JY1jPO5?I7-RI{YQRR^jq4wb;~Ar&J{w?4iYd! zw))3Y-B}sQs$m9{QBe|Ok9FLGTOk=#V6hph0m^44*i9tcK!avCtw>iQTm{sIKYm}( zL4IF`8SAYAsmyqJ6BsUdPp%-y1;V3NBp-0wb|o2yR`Um)c6r>*l=_oNhuI-b=ZVxP zph4wqd$M7eh=1$ReOT<~Z!Fr(D3H=v5aaFE$`n5DmDave$|_IB)zt@aESXj^Om%td z`9xeYIw1rn$WURbWwf72$&eML+`<@#^j7+3s4teQ@oMECe3c8KN|iDHrT%rAcsXZk z*o7gGGK(K&BGJqZHmE7>Q(FCJ43Aq_f~H1qnK|DFH`soO2;E7u=JWr^i()6D-Y=I> zAtf+GM&|~AU<0(9iaRXqs8bMZPL$`V>#Q0MM2EoCCBv)@_8LN}o{}Js{8U(O>WEKE za0DAB>YUp6yVZ1ApMVb4GW&gU!FdMUCHZGO4&1|4!Zx8C-LPcbzZe)d_-$^Ue%I}^ zBiPFMo9?15E;^F7_2@Y-6{Rss)s-+JV|yjPPnTKmo-e z&9Fz_mNhbxRoMk~HfXBFowXOM2}i219650fD{P4%WSOOrmhQ~6?&#LdU}Cf;E%)cA zT~oB*rGd;Rt&3D6$l^sKZM*w*%OmR47`~a_Ime`xSD*ULeGtTKs8PS-_9(Sl<(Q3z zh6pmvMC?b0?UsXLix(uFu<%qyBQb*SsZN?!x{5ctDX$LV9ycp>=bJP~Mj1mS6+*4h zR4X@Gh}}D)E8vw8J0T$xAU5TCQM%LF>)ioZqT6z8!#}$@FYMelPtF=-MA%%+@MSvi z9${B=46(Z8z#~idy1k|Hvk-8C2I~9{Tjy=;sYdMDo%WWBZM|i;phCLLqg?ALJ2=+l z8yP!VHBq>!m=A$yAS+dJA@Q|TM~cBCzf5(alCjCi-bw|=)cM-Nt{L{0^P{bDEbfKj zZ+raUG54V_Ha9#h6g-iP=byQGZ5?8@NQgX~T=$O1FOJBkj{Lt7Ds@#=h8YN(_M{hA zp3#~tDzcAg*H7Rlr#WL#S5|jlW{hu;FA0+6*YDvTK!(QfDxn<3W|Xsg*CRJkLl^1p zPBwDV34(VA3R&@3+qWwVde_pXU?a^1n3};B>*ubABiy*v@c{oO@xl|%e4FD?6S#K= zh!=|E58E;xP(lB*D&iQl7ZZ!?AfRY+U~ueR=#%vSKioJuxva6$j);Kt6HbFSA&)om z4MfKqo%)6ER&<@bVOcd=iy$`rS>Zux-5}5~BCAI}(HkQw_o|e|dTaF7Oc!@f-ydx4Rq0?!X#`F|9fo{`|}ykz?Rb=ivc7h8^`Y4VH(vZuZq_QCY`)yiV=r- zuXLTlrNk4B(Fwb_-)?^!w-L<$HbZBAYR8)C^*#lSmaI^#@}iy;UahjiTj2W41xqF` z^xU#|8n4C+HITZs;i}wYSDIo&$yI8Y9tqoK_sjlOp<7cTD=$7cuc@8sutz6%?Ex9& zZ{GmvLAtui-i1j{Fd3BaR8hV{xuR>jQ@vgVxT(*wFCDq#3-{1wBhwh) zBl98GYElPIemNH~xP{4e<0oYS@CUc=gw8Os~p1r zql|}{;O4LVmoknjFiDkLL?ZKlbG;oA=GOhqP{SVWB^$Y|kkVl|nfz4y#- zZ~B2lwOX~A z_0HCukpV|860YCX1C9tnI%XVFvqze=80ysaXKPn`4|areJ{`!LYhFZbvG?#zxAMk` z#|!0Y2ehfm0(Bp*t%s8-Qne6MMi2X)RbPTz-VNN8A@OdSR(o{=D~dbJFwTDO4MeIO zf!;X@Q=)Hm9rPG)KBJ!=i@UuR4x#F_<>KE5Xxu8evyS^kiHF8APWwf{_SAAhLD<{Q zZ>4MVH*x!n1JIQ(a&Wu8DddcTm!@1?1z3ktx#)04x{-v@VYWB)Zf_T~KBs5U<=vDjONPPliM(DKV?y5 zNugg0beeTI=_(Vi$IJPsFhxciHTzOAnnlFt|M|JLM1-?mmwScZVrYt?bX(ia)BOSIb=Nbcr{AUP!_~pOCO5-n zG4pmES=@E4?&&6USK({PdggJx7Q1&UC=9qW$!Y0%OG(Q**=Kk4yVUyt)Ph(L_DmdPp6A`@a=Wc4{`CIy)+)QI+r|Et<5z^R>3G(iBRBEBrD==aX594f_O$a< z`IM7s9Z%jZsxxc@ldNuQ?|lgUHulSJW0-Y^(8{GJyVm=3obW@=Wz*dV{1)-HAf- z*m{rm7}Mj2+C0?Uit$2oYaaQ_v;u$i#6h7QDt7G@`<^w-jJKCeP!+G6t>}9CwY8bT zI%bb&-ftpGB0qnO6+Jc4eXT$BD9&n67~6_7SPFWd{|j~>z6y7-YN%Qyy+~-Xtd77YmH0d9`$Q<{wjttfBon^d;AM+j7DrH%G6I&v{>TVa=XP`V^~Z z0o{6a)fnO@r@Tl1u%6WJDZ1j{xIeL}xlM?}`*b1=PuS-BWAbH3-5|?`U@v;&l{hVW z@}8AE?UfZX|MDn#bX4~Ig!F%0f27Fb$2oZyPoCB-InxKmqP$Y%eODbcc^mQqzD_6} zXmNZJ#|1&()m39qvMB7woY*m;?eBX`^QWF%%lDlauJPl7D8BJ;aTJ><_Q%}labE<% z*#D*!1bxa#nt3PAwnz!gWUd(=Y{;7s8b7wsH5|~!t&EI!ApL5XQ1`-3^RDdVmN+VK z`s5Qo`W`hxo)w$q`d>A-pijIiJKx+2@9J(Z|Et>@S>CshFeivlWfTAR{kNLBr1#&# zy|~%$JN{3XoTzW1HxJXRn!9V_?6=n53I7qUk>wH2w$!Q?JWO)T;lgUqp7&&WMM|Ev z#I;?ZI{wWhyux}lmA>!i=45@LT9rR^;v5^ja;k{>1jS~KJ&@_GD z*ibAthdhVg>GIFv%eo%V>tx?AZAriM9I=cM4%%X^`8$5KXEJTQLvq-hW8G$5xzfh^ zT0q;ASDjk;RcCThWi3BcZPzHwA4N-rlyD=)CbfW>2%N;^;#=yJA z?izsUo^Iv!Ow8nGUl#oEZ(mUzV4|qcpQr9Gty}N68mEZMISZ|lrq$6jdUNG&39lbx z_c`~UHSWKEoqXwb2ND)4K2UyoZ*z8$*2vG6FlMz>ILS!I>kn`S)4Tuu(gLjD<--Vej$w+Yvi+0x>yIrov$!)ik25n9E~H_DB@^z)z^0GAh+#v20g1D^Lvb%k$r zJdFEm{6I=r)kjl98a2m!ULhs?jx7^AT=gJG^yVeKG_3HYcY;y9;;e9^_2K2N5HK?H zZme;`4_N)6l+>8E?J2Z8uhyNR-$K&GYt9M18K)oH91^vp z^4BRX$9_p;v9DA|MiswH%iZHs?1`&xNy*txNzY`Z^$fjl98LaOe<*LK1J;wbfX}*K z%KJgGJ+4!B-b_sb%j&U|xTS?_=T2=?Jv~ax--_y!FXEe11b~sRIQNtCZAH(z2B+@) z8~=J+rA8WH>wSh+RLb{3_juf8L`RD}`^EAo>C^uH_4{JN(Py(!z^1gj#2FWpc!lUww<-hs`q-ur;}{MSd?m>hD|P z>xdZd*~7Vs>GL_fwXUtHBhK{6<|{E~bog%3{CJh3oPE9`=(8xe^zhuZg z{plRR;LTO+Ecv@}5@i+dKOZLHf2u79SnY(G(AC)|fTDK-$C1m*tYYj1m8aEf6;E^L z+6nfj*OBvWz?Z|_aTLbI+)AYFW+zWqY*|;1t&Yw3R$@~|&n~|W7IcZ@-LyIJ-VL4k zr_nahRpP;Wg{Y&`9n1A=04wlj>H2|d3?{)~)85kEPj@5g;1?Hd>{A0c;DOuf!dL54 zAjjtNES9;gNh8^buHahGBl$}V+lpspt9~+T;-zOM?3qg(Gl96WMxl9^_@Is?GE7iI zTgqXBl0S!vt;WP*LokN$XS%cUOixYc(7KQG(>t^f;c~I6dx~#eGzlU{NsbNcy!PvZ zFA-d_XF&eDfz19>S_{U3HK|2O|!dfw~aR& z=v)r^)11E=P_A3@?l49k-iXRU(v=N-<3e>j)6RKgQ-PMsv09pB1zy^>KW5$L8t_nfUgZ)2A`l5!<41UI5Cbx!6|g zavjPSXVz^zBu$5QP4BM#Kb+tVs+MQ}>96jM^%+?HuDc=pZQPHys)K;mi`o9}4!k-! z@wa@>GbVe`=fU5xyG-`I&bN$8x1@UhGHu(KPNo?pd`jT&-zSG|72nrfZGUEck@~&? z8ZULHz6s`tk&+t*k(M^-C1;-l*0gh~WuGsyFYD5u9`H|pieDGc&@5Mk)D5^oeN2%; z%A0I0kxngF8c_MkBYY*gurp-&rkt}|BoSq1g51eXcXi_%sb@Zo$BEv5JNth%HCP^~ zdYW~@!&?x3aE4p+hb>s!OCufK^lW0tcqTnV|Abt?wB3czs7}~;4){`$<e>qbM8r@%)g_ms*zcmuBhq>^j%vpXI}6e7;ckDM)A_O zxzH*s`HWw3cRTHFxT{#v_383Hz{hQ}=z9A7VCl(u5a8SD$iHy_yx-{AZz2*D&)EI~o^-6kd+4G^TqtMpy;Z!A z(Xs!EWi*4BdL`f&kAJlF^l{EI$gc~;{M=Ewe07d+Osz70usAy#ly{ygo)AOUy?4Rx zs=)(ZtZey8*dO*-x7h&DZ`ogM8?=8Jy%L&y9f^B%C(g7RYk+i61Huv4aNf@rkQ_MY zdg%@{oFbgIw=$mGv`c!tvA#@Q(NnI*X4FadgxlfQuUxHt&!M@ps?fE&Rrd(Egb3I^ z=C-Q5BM7BjFEyu52tKF|7&GYMmTe%5R++xr{^)vIUA1_tyDFfdK*RaparN2Hr94IYMPE^^sprh5V3 z?$)+%UcUFqJE^zJr@BX*Yx<|#75mA-CxF&Jl>Fr54)a8k{As=;;ppVxudA7@E;S|L1aR z`f6um?EBCR`&%^jr{i}tUvAznS{(u_9hn)z?Ss!3)c5n94@aI!z|73e;#ROTz#HDl}pe>w_u8Fe# znq-#^VP--^{eO{mR!?zs;nqijy99T4861Mc-~@Mf8=OHyaJRwT-E{~W+})i724@Jt z5(s&7_^Q4-|G??$i)UB&zS#SsYuD3j{Z?|yf2SwpQbJ=zs*s_rJvpOjs|exuP1c4B z?5?IJJMsFSgsws#YDfX!LW)2%>PF0+^=t%vI+`lmL42VE=^>g*aA*Um0nqqZLqAcC zGzz0BaVm>w#A#qa*{H`UX^)HMlk$gZ82I0L)8?1h3+DM9Hy#yi#(us*KNbCE=As&V z3LX+0Y~MSPMCB3_*7L28JPw=S04Wo%Mz6E+qZ#KTNnIL6jFZ^$%8wP^;oI)+@EBGs zUqOWoZl{3=bYHGKJ1UyAFAQ&;A4R86z08sW)s}zeh1O@tduyHBq|KwIM2){NIVr}v zbR>8&6NBg_Y^|wd(1^rW08rkeLa^{{B6jQyT7wr-cVeAcXM&f5+2p*?d;*P$5Qt6f z%o39Ts;ZU<4}bEF7$6?)!uc6K(al2IXJm=(sPS%7cuU!n{7AUz4jGeBiX~g0iJAH2 z32|Ok&Gk#w=bphmv(=W$C%_c+Tf(rIz;$8unf}Zc+$TM=bh0xv7|TIXZcaQWPl@fg zbN>Kh@q8X(zx(R)*X0|tyjrD1K>Wtg7Q;qk#UyywbO}F2e1~hW0_ujdarJnb5Txi& zw3~EtjvsLL_bH*0u=9bbOV}0PKzyrQ`dZcWyQqL=Qw!<@L*SYIJ^Q>WVRwQ#bC*6@ zx`HefO+Hs>RnJN2z#z|m2t~g~LzufAr=1I&bDHYT$9ydqF~(1UCN{Y9@wolAQBP8K z?$BZUGyT5?Drkoy>z+o&M+V>Tg$AA`V9D4qQrUTVWd&=cnfs~|gs-8&^4Xm!-ew)i zYpl+}&iRvx3sIFqaVN^0LR3z1C^!_6Jo+Zf#*ODX11l^+`zuusRB{TeZW|u_OJ(bM zZRhDmrStNu7lxWXydOAqkNi~JcKTV4Y5OoMBgQ>7Ui6$j&>UE{Rnk|Z>NTrIfj4m3 z&{_gU*FhHqp1X+jVP%&cJC`xi6a||M3RZb(Ml~NbU~}iw2>1(G0>o zjK_DpMGsZ0u}y7}XVm50CH7ljVQn`o6N+t#&oigH?W(Mc_cnOz+MPEDtEoYM5bRYX zP5mYD_(`y1_umub9@)|F!Yzy*Ed=KN3ewpA2Q$Xn3 zc;qGtgMkhQMJB{0wJ#cpM??zA8;Vg!o%kQ0m&`oppOOu7jkd?sC(^~+sbz^~r{;QH zaX6MZ1X7{LaY9ov+Sl|M=8dT2U-Sj+To!aADX6NqK>|7nP69&h*2?@{btqt$_`pgY zyD73Yc-9^4T75dewJ@;)L{vQY$dZSp>9Dcsnik$C!bt0?Y5q37$Jm(?8AG&$7Lug8 zoXrN2w4u8%pz3e`2IB%Ae&~l3w$!m`NBm}W0EBnuyJA)=)2!-A0%$vb2LCP+aFu6) zvaYtag6Rkt@;N^Z)2Q0U;up=FB|AakxmZtH`5St@TIItW!0iu?q_7?SUF-t`>kIs8 zGk8FC0|t5eBgYtojlnjq@Ju+*6*!Te?3nOR^F~1nUe!aGG#5fvDvR3uZw|VufpRAn z6Ak9P;C@~OxwMew)lU17*-7QORninRhV*n;vZP&!UgsDq$`AVal<{tdLU`HZEEB%E z40!n5G4JwVfoib`nv@Z{>RR{9S1;mIvB;ex+-HB!a!%Wghfr0^qAq6{i=BVS8_6@m zhyC-#Hx=0Cij+-rqdSf=tY_D-Y}-$O8Jl`v0?2a<+v>_J+u#iBRMYQx{3|krd#9&b zwnEoO)Nlak9P{*uwcuUI3+;8D!w942HQX+@a!_-%8$B|(0=tIi4Jjvsp5-z z7Q2zSXZxM6YChoj(uK91k8;y3O_tBcAaKBs$x*~MW$cqa4UF%k-AbGJw1*3f4|!(D z%c)x~a#@wtXuJPFNo)?=TnWV9pwKVoOUGIk)+EMK*vevgJ7lu6N(=LsWgcp8ORN9Gpn$p^% z)(2dA+>q&wF}QxEX>0P~~g~KaR+|+&5UasN$I`%;LKMEJUXCqUYK>~2$L7!Ef}on5Mmm^yICY}r?s!TbvES!EH-yN^bXRH-fh5E+8Jz3WH{|pSZ#CqT_t{V4Wwi}Et9ft zsV?gpOa9C}uT&z!!~u+oGwgD8Ybr3o>)04FVfwLcquy8gD*cVWDU?dwS_y$(2~;&H zNpRor>lrp{n`zpNV9kDiD~kMgjj7s>{&MAWm7|>2&Q8czKygc>*au5D)+-|l3P+Mb zNA_Dj?fl|c?<8zzj327+azf%$xTw|SDWjAIS~)V}c>?yeeQC+^0;_tbuFgbIq<7OL zy-GJ1bI>`MbHT;Yfqz3r(TEFy(o85dA^nsTJFkGMwoAg z`j-Eaw#$uvLEieBQay!oVmZD-@*KW^>MBGxv3Gg29ABlK!N{`Eq{UA{;SG6*YTtlM z0SK<3pD4D9v9%L?9;qHv=*MgQhMOpdPfpsI5{>nq`ZqWrMUmc02DRP8SIXod9~!dh zw(APKY&QbVznY!yFwF5JbGl1xXY>vnWJe2XaaZ<(?RT~KRG@WP7Cd?O|$-ep#QGNn#d&S2JyJ=JNqKLylHPooLm zlu=Z$4w;-+Xx@vY&hjF+?L21-%y;i*DAAq%27Fl@qXFb3VQ(YxK|5fwqD>kn?<>kH zIeHw{3>gCsSUMc+9H>VWPfTBn@pHNdsTJ%`OhdwnsT=Tv+&OM`dD_7c@+&rtzO7LS zCOz}mn|rrKa$2nPQ1Q+NO3B@ai!!;ttt>TPZS6OLQ@*G_o>E_VcPZ`p=KNjA>5@fF zCpyREKhwZ#n?eEXM{?NpdzVpD;=0Y+VvcR=SW?@jFKPgC%nVid?_9eC$|I*Zn?YcXF=n#d zY^}GH*G{K$>WNmFo6lq^>4=FwT${!CC?6{^UH-*nDm(hlmmsfug&ZC^z3;}7R@mI7 zzdRYCV8wae@K=?By*+g}e^RfLp}S2fT~-{^5aYm9G!G`x-CRpg5SujH`Hpc0WV}z0{NIgqe&fq1(`6AN!jbXml z8Q;EE$$pn-E#h9Kfz9t{1p1Squa#e8?-Se3On&vvhuWLRcp=_Mnc?oZor`cG!N^ss zI%~6&U>?pS%`=5RnsOt)8_J<~2|Y{*be#r21&e1kOm<}Z0*)(n^|N?X#bqB&%Gya4 zvP)P~8zU)LD?*Z*GvPrRcfA$ITKoWC-jQTX*(O7H5I8%aobj}rq{k?>(Nw$(-fNy6 zz+izjkrOMI%q3p7YsaF!QP14Y_F3@*&GLn~YW;G`qo6$pFeW9zAX=Tc4(Yn}RevQ+ z_)Gd%fEEXJ9nI(zS=eIcgd%OE+on$YtNuEYY3AjyMjji`Z>aLRubn|cjVW!5J2a`? zT*Ur&%*8jq3p+miU$Gse09t%B1P+dEGn?TqrW z;HaA#&S)fxEXrgeV0b1R31A?qY{#X_tEx{qZMsUb+31-z6=k)zv{HoWvpdMgNy#KY z5s##c`Iw|WE)biAW6=0hu?KrEU7PtXj7eds?b#0On5Du7G)5YBI`SY@*eTKnZfPW~ z_`uYk0<_Ef5lYI~L$;F~vs zIRGU37)QcPuk5+Btl(#%8K0X1^v{kAYmsqxU~5{CBIKmajSRB`mk}SAC+YiL3(v|9 zWqA)zwGXbOKV5z)m=^wiXOWr2NU@pZ^y^4xThlfS`Enyr-*_ZI{!w{GztjlOiLyV*eo4cZU8OakT?u<%5k zpK@PY%i)#nG0wGZR^9@Pe8q)Npptk$b;iGlq3qM1juH&aSI)E^+(%obfJ3mx*awAI zHp*uE-DP|8O_f~oTw5_p-0(v?>J4zR6Q%J{g@W|6IyJs@Bb*|FrWMtGQ3$qF2HJ!L z$2(9!gbR!|xU*0wv z(%n>Y(T4kGIrBgyQt&`@$a09{4B(ab9WQH*C5zrY`oYk|4x z?s^?UN7ZxgRB8XPx`dsMG=BlUqsU}VrJ`=`d>|)0$fQ3qgCbzp>xv9C|+8;bJ zy)*};!+jUBFR<-|Zg0;77HZw%I`OGPniS$!F(H`kF~ELej;3&1&Y*LLhC>)q);xJt zs_tN$qBlnphk{RNz;YO|5!_MZqMI$=I4dX-;3nk!R_Z~#6IYl#O{4Xgi^~xK!E6yI zcAQIK;3xj_Nx0nrqYMUP9i1a}Pank$oMN?Co)1`6um5bPUIn zv0A94%gHX@xQ^0oabcnjaq$L5$Dh_U0=shhaS?Y1PiXS1}bjV2I&~*6wWnfTV&4F z*B>j^rPotf5PxW?KU5s{X{`ouWcrO#<tx_ zD+EzrVUq?`GfCm27l?j;w%Tt4FHuk8lo9eeA~0A|DL( z&XUV-hej`I@xMACfe+G6i05M0ejU6psL3&PKP_2Fm1h8mbJ@eZb4Mee3osFFRb3DT zV)J(wY@Xu|)1RGy5jgq<^Nhnb&zJ#LZ3rvD3QKMh2h`ip3Vvf^Hc!CHr*o&8M7Q1P z^T%93`n<7+`Q&`-@2h^5el`j1wop>VZw(GV%F$o@TAfpu^E}$Dtv?9rdS!1BW%Jj+ z!R|spw9DFh6CfZCwH$GkzXhj7qEyPvR@_q_iS~+_x7lJheJ^`0GtmfE(=UUElyX4& znuU)Y=4HjyKE-@JS;bVTGg58N#mkU3Go+pqLauJ!J{XVkuGEBf{G6akGe=a7R`mfb zbJ+`!T(djIc1}$pucp|sS7e?eFUo?W<_z@IqT-0$>`3Khrm$VZFH2(*|AZeh?h`U; zvqFPcZW3R|BV=r|>wSH34@R^!G z)HxK{j3hwG6u4ZpCrn-t!BjcMAKYNNr`S&@Y5o5 z7;xbyZA$U7)&ad2G#htLxUVF* z`P1KM4v7>OC>5$)3en%Dg#@NnRJ zB3w1}5U2=5I_RoM%6a^#C-|p*=f4D?rNN-ZGHjNkQ+tU6sN1fL7qsaM5p~1y($}iO zix_i5Q)i1^V9ruTs(}p_>9?5&jvu86HP~uz@rA#LYVV=nb?@rt7%k!d6a+L+G+j*e zri5+4dTcKDc=V}KUL(QLn2BUI>f!$6u4YS3Mu#aMTEnd87fgsv)TnKc;&@t1vcRBaT>5_ZkTIL?0AwLwsQQeN9o}@N4Emh?0=CP@1qIGxxj=- zMq-ekEcauUCvOgMbjGX4?R>nYNSF0DiWc6US5UZ!c&@qVhenP!%9%2}&>z(CJq~bQOmTzx zS4A&2Edh%$0t1G9v%ZXQ{ppC&rnHJc*5#g*`p*W;oEjX4fasb=;ocggfcdGVmP+n% z-JyG@Zp}7vV|0REN->whr0GbP^d5(F(1E=P@pXn1#{*b!ZajXApC~5zb9!##*}O6; zf<|e@yMTE?^aMY1DsJD8x^$HP-brht=<0FhJwPR~A#ZQS;V@U$GpKaBy1EGe!@yuE zX`&;pK_qGZBw(n%oKbM(gH>Zub<=v<)>}wIwDI9kF?>Hiv9I>J`*eqggSDxrGqE0P z)%QnIaulK_!kG)r&J{bU6}W@6!rQLK4(;{m@qHgD;`Ooj2jV<>keILJ36d{&Puuc& z);&Dr;IXq@@I-joEw4&TCZI>dUfipb5Nqorb2NejKHc5y+i{jJ^sLm?Ha2U|P&!HlpA_?J`pzqJY zdT=Wvay7DM%5T+})u4Z`j#*Q^+pkYLh+zIwhyCh2*Y2U8p9lf}P6hfc_WMQu9X%G% zxm$dY`g=N`IO(hX`IDCyH)^klNNRD3{Y+|c4Qyj{mG!Xyxw-mGk6AKy4lhvax2x)6 z89)W0|KZ5$b&B(%m?XYUsCP^AHhK9WQW!ML1ocRn7~-|pDz>4l6BUP;ZD zxh|dZv0SQRNOiioK`Tj_d{ZBm;+gvNFAA6qNZ~X@F?l%(Desx@Sm<m|gA zjKWk^a5FR*dE`&Ed{HLfjzTAak#6}g>`C4t)%IGYz)bixSA6t<^p z&!=7hOwvnjva|GY@c(IxjAN6+hfw$RyikmD=>rr+&qJh8^$;{-#W zRVQ%m{D@u9geY!D8Eh_$7l#6Rh6OfL9Se5;1a}7RKz(kCS!X%jkJ{Be$7#*7(PNgF zD&*czFl_Ixi+B&)e_@$*h`ML} zXY@6tS7v<06pi?+yuj&JXw^D8(}w9junk7;gS<9mT#ot6`_iDc#QbCe!GQrQ5nh&tF?sU(^ZvMkqVJ_5IsIUd)x5UT*KwMpjeM;PC7eWkQKe)WLr)qagYEh?|R3{YwF zp#Skr@cT$&-$NUQHSu)JU#$@JP96=|5wC|0C+vE})>Q@2seLcXYD2?S_xdYJS#GK) z5Ke?`U$punGx?k;GS!S* z_YX|>EulqNMLDR|tRzm>`v8i_K!$H9Io4Aveo_?Wn~; z$e=c!6>8fAiXEs6K)`&ZbmRIJ+2`!)FpjL1`^14|N_=oTD3Q*G0aO0e5MCXZ_5rtZ)AD>82%g!l0Wk1*;{w9OteP9Nx<>);km zbS!^%Tmo}s1w6~uV#oqxm=`NLH*H0YF*g_>9rCA^d~gRNpq&b$r$n}Udq7o+`ttTe z7KsuqL{&m{lE8%yf$OR8& z#nnMZDUGHbo^@&`bz5ydW)oV^oEcHxlF;%w6sU|a)xi`3rezL!2(eVu(mmnj+M23t zGpJC>5ea;>xs6{J|2<$=()@#?>hE-myiH(22LmieoL1{D4gy~6}WSqIlX*J8h~1NABk0dA)GduW$1=BNy0hJ z8&5S!Jfl(`=OSEKa;*Ylz2>iWiJCQqw)3EGKR8$2;sUoAyY?!7gOv>qAz8@`)Gq(u_?S zniZ#&(b>iKO1Od+eVW9m0ns3~PYx`Y+qhFG2RLT@CE3hBgitGzO%^;2r8*_B1Mg^r zdzENIjjOCc!ED$c59GzjIc<&MWJ#`@2e&ZEY7QIxA5KpoI_^-mP&=L8iByUil7++LU z`ZWb5Xf3>ZnkKlok>jsz@C|gQuhqXS7|9xIqmKZ6_o{Pa+91UGF?-g6zJSp@(acRE zTc_`O!14ogOv&iUmi1MN>I<%T-VgDW3Llt@+a6@&n$Ca81%BG}>t@V!LcBiYE7ykh z$uIl16pj+!M8E#TE{V$>5A#hIIvVF9jp~73D63W7RDyxGXU(C>rgxBJFZ4`!+xF{c z^Vt^B2I9le0auP!8S~jGgUq8{o?!jxuL9OoMYU^#Tfh3|;JS;D zFDUEZ;e5^g8g$6lH*#=OdDgj(o7nxT`?#*Jv4uI4o! zG!cUg`NMtL1TOD8I9$}pMRyMrJY}QO2-uPgd2sR3o%#`%4mE}3-M3N4lziU0po5vS zg&=8RRcnWU;@tS(=eTleJn{&|Hlmr+E5F@Z(8!*A^~?Mn1bfT4!g-Flo4h9pGZygN zS0tj3PF_7nQ0bgJc(0ZN*uUgm#LA%zwCCFFS?K0OEJuIpY^!>tDOoWei&!VLC8m;Q zOR8pdI*M=zeAjpWDjO$HA7K`F5}eXx3}LQb4{axvXO`<0%uR1X&zmhHEc@fm>Z(=t z;xfddJ=D?$BBlbam$6Q&OcY!pzD2(eT(Y?1lOEpNwV--J21HCdEXuSNb}()8mi6?B zXOpVyBa9pb_1}*ID(dP9#S{2BU`X+Qw9k65ppHCYC%)xL70a$GsOzg7QcXfK(|k=S zWd4)|DJIAk>Dv0v)I!A6To6B90Ws+UjTVj~2k%hf0tJSC{DL@bPL!2X{WN|oJxOIFy;d&SpIm~Pq#=N@~ZPQG)BT@q>Wy)8<0VWbtiI){N zec6t2Dzp9ycSc93U1S^t4Kea@gRiz%4OJctLR<x_aE{MPs$MK;$!b6^goHdBjO`?*O7;{R4+gKY5%K1ZOV`D=8B69 zLSN5s?VK!0d5$m2&}YUH{52@+)t!DJS_MwV5F)Q-(EF|159t@0LV)7)e>P?2^~!O+ zsP4tTtJ+6=A~Voap&wcLZey4hR(%>;5wu<_41UYl$(%yo5cuj~fjNS443KaYBrq)W zAvQ^Pno>^3fhk(yK6t8LlqCz<8*;;S5FOUUfl`V>!8f_JtULNdxJwdpsWs=y+-4-w zzH%Y%tYv@k=xY-UQ|prKN;_F)H8t6PP^X76WJ?h*GnGG44U0?s71qGmg#V4=SqY5_ z;b(((z$cl|8#9f6Qzk)n$a?}LafS2JDGsxQPMwW{j*{utkll3%^7hy5_yPy=-0`L_i z+LQ6{_R79t5D5xUuQ-*>=Sx5&aMnKLcsYWQ#M7t=WEL+F%IHbN7i>jG%9OE;ETYAJ zY^$aZ37(e{`Jd0_!Lg9zgHRfKxOkSQSsuSDV|`Qf&C2}EvR~_wDtRJleBKW^cqZKP zMYxhAb4GNOx?EQ0LX7$q8BRjCgivRB`Cd71E5K8i1c(ax^h33eFz=!~d2Fhn-3528 zy_I*G=zaMnbL%B`5d;@Ock!ekI$pHCG^rkhe7!)aXp_?zrX#M>+yy89Od&?CTuv~h zim>A3)5X0j^lm?_%93F~JZOCt$$$DH?V~LaJpr+llG@k8OFUg+k!_s;MT`jqaMg5J zptT^mY7y(5mHP`&Y|(&#!hhHATTd|ly&cojB6nLl-pU7mWWjqRqTXTk08X=E%iav- z55UkA(vdB#ycEv!aOW8R5|U$a`<1OaDg{g+tcwnhWXf`gvylT>?a<7qf9R+$)7txr zxsfStYQDeaQ5>6L601E)3;1R%6ix6$M?p_M!CQSu9yaW^w-^+=;O1**4OBcqfMrt| zL#g?E`nmCEqX^c=Dfnl)b$$Ce@mYeFs&ZE4*1%R>Kbwcvn63)v?f6LBYE*u@7%n35 z3#=}yPSL<%uAy?L6>7702J1u1?fqHrLYaY??81 zlqPwvo@7?FX2#tw9a|P^VwXWFzNw(&82R}bL5uO1^nAtAO3>@TQA09*m@gx?KH}DQ zVM1O@_Z0|}I8aEyZpfd>wgt?i?{s=QHLY2&R^~wBTx5Ae^fp}m z$|=f|dM84Mf=K}8VWWjyrn+5d+NNR5sux*K@pS2BDSWQE1uRE?&kv6ld-cbMNS)rk zk;p@-9L1w7F;*DcI>gP7YU{z@TVW)e!ZMMyhJ9ix1p7#HpY|-w6dRne!T?K^kSCaluFK8P;I{-qwx%NVmh2qCA+ z$OX;A7&E-q8XSPynS~Kum0UW(-{$pg+ChM^G3a<#N+Ncw`q-}G9=gRC$K3s1Bz7!Y zG?r!OCke-PN`jB_b^e%fwpCqxx;^AG#yH`LQxlSyr6iq~gsYHq3EE&<3j8-}>Z?5Q zi`H+#|3JIW$6lYyk$!zmD@(?bv|~6^TCtHMK1^Luo>bxV^=nM?rS zRvn8|7nNiTVxv@h z{D9C`T*y*K?~xH~QU9%VMdw$ngs+HP6mlUxwo{k0eDs>O5p?>15nOJzevA3sEceFyN z(gn3o06`d@_gJAa=a&>OIbGHi&1OiD;5-FU+^*JEzkw#%iZahkyE8#ucZxn{VM>-Y z@m=ZoouuRtBx4wz-Q1+lZq$=~5zo&m)k!YY{fSWWrIUFP0ye@rZjqWgYK(kb zGST@jbmias-$^Xf+e=J&M&j6NJvy1mGW9jsR&g^%n#>c>1t-Cjz+7#+VqkjG2t=j* zZpZid@4x=|^60WtzuesDJ!+P%p`YhY%F@O|*Qgbzo#PxlA}0@>z6JTeX-th{A8K6v z5#owKsffnO<<0SoyB+_=Qi|NCU|jFpAtZyz!Mxx(Uu#5Dh$3_YYWtSgwM$bb<5m{o z+zGG$Jj|Vz|Er(xQu!7txZ zjRRse_z8EMq!ErymAvw4Go;|=i{dbDgj>=|2WDm%^Oh9R`Mx}#+Pj?e6daZeC_wJ# z9RsrNPRE}~-#lDi_ecDB-n=xc_J1EyIJ}^l9_}=f(zBhkk{>T>Vr$+kORG6D!CheB zb1HjywGWbpI-wI#CYCOySEUr9+px;@GgFrG(~IZJ#q`5!#v81KDnIw#;9oYtRk#cN zxK?Pr^%0`6tw=1%a?W1;^3O^KZm+v8%|XFU<)-?K53j` zvST2ClI=J4YE}I5&#-a!(XbC z_Nh7GQJN0_#aLj~DvN+Ng$qwp5FEo_6Q;&r3gUgggRuHH_kCLe6`^J4wy#eRn|8%v zQ20T;>IB~HJ4i?q3D&%)9o?vON16b^@m%bC23wl-RSEL1(T42&kmiRGgmIXXcTZ3? ziCArXewutYfp&&?oI^;SL@fn17y`v)XZG0L~A3!t3rnlY2MS4?ea5Bcg zo3yp&D)8WQOzg@T)L%1Q5iO{=IH`_O?B6F>_-uvGzH_3fk5g7{9(=@lKOBes{6465 zBCB4n$UJ(qk0kw3W^LEwnb*)jGu^dH8IY|OPuc0sq zDz#DE5vWlqY1ntf!%GLHkiYavr& zlkYkn#xk6Uf!KtU?W-vA;5FZD))tO}ZxbfwsazLV;u5=^Y+^U9FXEK9oMAP3%{QM% zVmP#NURq5??g*OTrw5p%w|cm6xj(IuS@%@6^-a&}-R*i|tgR1oxX^ih0 z>-Q&*kQX=pDJ}RG`K5MM-T*IQOJz-a?X>qDufF1*XBm6pj+&nyVUlXI!{76mdK&N0 zTOwxjQGEr*C5?*pw)e|*YQOL6qNH0?erwzA(G=-qOnir$wqXD66~w9d8Fh=9Ex%=BEqw+`V}eF!FoAk%M|L-kd%{@@=eX> z5TzLxfw^PVuUQC7jq83HzsUOpx6e~vXBt}Z?mm3lTkBC+8%wggtjA$`lg9lOIe5$P z^v>RLy30YU))N?z9mA)>{8KC<63S#&TZ_kpsp2G5`auNIBjhq<3Y^R*g?;T_sZofePS9)3&+9_Wf@o`_{(A@99#chaAK# z{@My~Mr}1OukR;&hYXKL1-=T`F=sEh{vq}@*n zXXc?{9^MG1+k1EejK%Z6jtygyh)(WE#E6UAGxCR*k>jli&71fT`y!t+#PeOMoh1}~ z@>Z`UB-9a$Sj9&~SP`j$bgCn;bLrFAbxAaS5|ERB{qRgy&0U88=1$uG`1qo#e$y4} zG+bZ&DU`7p=A;eMonP7X#Rv0h1XjiHuzI)Z`LrT4CWzet)0#>?DK-)KEHFeq*wBQw zK7%|JBjTrIuakRc2v`&y;y~h#+-Lffgvf11BE|3a^js)D+2f|72}dMNm~E$MZOeWa zv2EG=PCw9_m{$Xg(yc+n zc^~^g;=JXc9kA=jy3u&gj9H0GLnY;5qvA5;j`2QB5J+}ylerPU#sRgrzr%F0?-s$T zg@>UJdv^HZA{QKr@`&>r#8o3IQkH+%ey9(qK-Y`5j#r$kFV(4YYWfiIp82c`O}U;|_2 zPtFw5rCvhbB2NfLU=j?7PBDl>qK=)PChWG|wQTfUNhiNywa?-u8eVu+IM3IZle92o z01;1mu2B*^#B03(m_|E184x>`$F&UgdsN@F&iM;}(fu)2$&=r!{fKbHKuX5wqef@E zM_3W2zT+n^K97xM3#z#SpLEj6JC=o??NlFp5_0V8I2Ufq!5#HP{k1jqmm@rvbqr{j z_nzug3}~(M@L=1mW6!^ZKNUR{5&l8r)m=ir2dfs9A1$K6%sTvk0h2LPgbs zW0*#%Tf|NigBIe*ZU)48Fc2j#hH^#VS61%WTVo$lo{d~!la$zy^Tgo3 z-U&%Gb_^$?W(CTCrU=x4F*9R)1PwUEe#11$nU&ZFnIQQh?>?fV2uX^cw@#h)tOAz) zz73Y@;YF^?nQyb=ZcVHzW!-3cdr9z}@e5+*no;H6^sD?{4Tx!|LQx7FYYq&wf8wi* zrb3RqcwozPF?7lqMi_pAwe%4`7gY6h+>Xq%EGl!yBiCFDHP949c*A8@lT;I4e@ORRx<3zi2!DMkNk5Mh0_R#7fX;~dnZBK4YeH$W(~zR zr!?6un*#zllsaBvd^%Cn2`ueCD?5ff)ENg0JX~be9lPHh8CN#4Tec` zyS)h_eNNB>_=(#$hdhylC`sdTBKbAi>!b}i5w*X59OrQsOOI>1(X3cbAwpPENFasa=h$M~USh@=67@Ks7$f$%bdzCHk}je# zf?d_3!D)AaRvv9c1Eox<8j0I*Q8Mt&%@!$deI@g{imGL^B=bWK3ipVHyTw!Q{Q)Um zKSJrB*4^ZoxqAoy!wl-l2?XLbus-TfuJAB6`! zU+%jl4E+at?=Ps|Z1q72NEkWg(^D*Z8zhoSQ~3G*bUAYIyh8~uG}hyT#K)?Siwi%hBdY)5ZG6H6VknQl zLqI?n1i8xT1{9iW&f-S!;a|@m-Vz~1ej}I}jcKB&CFl=t!!Xpy&z=9TkDCtd43Lpm zG(W{5WV9BdP-60pLh{m~H(uQq|K@@%6DW;YyFi(oQgG#jx3U6#K#IV{mRliLZ}4vY z*@dd)neJgniQ4E$`((!pwU?T9z!cjeTr|%xT$qxjAZ|BHelk-paCk8daE7}rR#XuE zjnwm@<$qGf_@f=~Hl|D)u~nlOyS((zm-hOp0rxnKO*dZF}&i0ki9E zC3-IlGyfrcHtc;{+5h1R{fOVobTJux8FxSzP4C? z{jdJl&Yg}!cWtgHTa^Uv+`%frRy zp~vCi-`Bg7+0QTKPo!NfckCRz3nye}5Y4}4%{z;2J08y&;389J6U+5B>qXUtqW^fs zpFjWi`n)Op`0*ciPbPMn7{EsQOz*!b;=IlO+(;i>7nr5HiFS}qD4(ujmVmq8E$6UB zewf_nE^LTT*ZW__ut}kBQiI|#QV27)lKj`()BhU(`}pkt1N%G>X7Ra!n{IOl%Jp~7 zX!aHwr+f-FPg>#$o%*x{w*2)^RpKh(%wx_` z_37%t*gXB9a)6-{7Yc*x&fUWE&%}%~@C$Sb+y+%uN*k z@b2tM;KB3^8l5MM9wlK_U{9*DgC-V2CXK^}KS)WL^S>!?`)$7FY(q}t>VdHCw)%{F z2b{6eC9s9Ut2NKJR*NFOalg5{yLZoUM|w9;?Z7=E4c5{X&e_i{dOEm+TWN1Fm%!nWx$;jKrS6q!rhVnnXqtWJ1&qn2p1!SC(uaC zKK9wL`z2KCNtQ@O=mq3#$|9azx~M+&WEvpdYC>cImcjG%tZY+B@e^~hoP1~Hc8Qi? ztC7T?^;@?ABx@Qq0zOjia6}2e;Z!>v;cI)ZrKvo${maT8rH-a)U8Ru6V!glG1D3cB z(;G{*SH{rDxz;*}Q6H+bowKPP3ym1=6WafcwDdhjE8_=#h=p<&80TPHn)8jr$HBjI zQQk({?=a%2R#QuQ3@Umt#u7q_4-7VlvBJg=<}|T{93EzHabhg4tr>r8YlI&91aLdz zeq4PsNwcQ*FH`#{7AFPHK9+Do>;`*%XWE}1OCs(H_RP!uSuKYiS%KloiKm>yx7i&x}&9cjpWnPCm;w}SK6|k;#f1%F|BUK{3fh9I z``|SouTi;73@)Oi>7_mz;<)Mw1X$P7yTN}+J%cL=8Fyw#7ozxA!pPv|npbfNrW9sa z2s1jo{OC{IAx@-gd6**q6StC=!R;3NQ7_wx>709ypl>f9QsM6HT^z4lFmNXTbK&w` zaqCK7AP7=k9H^ckPakG5R88)`)bKIhe))v-QpWufa@Z9~-*E$M5_c< ztHi#%wh1c2rpeE1vdn`0a=%f@lf8M2(Dq2u7RhSx@PhlZ@LdnbaX|uA?m6*$hOzH@pK%5aNQ*b0? zEBw@a&OIL9E}l=sq?vWiWe+V^p22)Ao**uvjK-&x98Mx;y#v2Edy~JN2aWr^2h8|IF~*6kow!YU1z^%{J)d`Rofw}(z*mqylQg79 ztJ1(BblGFL9C`qkImI9R`*IaN64DZ#YFm#Oem2CJ@s$iAm4KBA&#T1b0CgmBgcUZ4 z>x@f%=!~`dP+0IbWQYCoj8_z`>P?bJ2k!VDf*U&@(1A;%KD2cAW!ejRz3~vK_aUht z)W#Hk5<^v$Oe`_T^0TZKj&0 z$EPE7<=JNVX#+a4-h`jrhiYDF4b1r300Hh2 z>y$%!MWRu9qXwIZ-g_@U*Ipz7k{1te4^SN2-M=n0y%UJ{et5dC#B^|u zDjIQ43dnQeB56#P5{cC({EA<9Tb)19gl!Dv53#7`e^>cG+r&RwM&&BS@7MOFz(v+e z^H27+tDG^g9YtZs2aTHNhj$YFjcx(2iUU*;qxr{)Su|2btl=!VbYF$m%h>2+pwSn% z&Wt8k?P$NA%el@wcsp~X-;W-fL4$@o-AcaAJduc+0wm>ZMQzi2Sz-)$n1<6e(UD$Iz-AW6jKKo+*Ckc%(FX`&`$1FYUO< zs@O*F>8St?4de3_*jgJAD1&hYHG#!!g3w8w>gLiY? zGE!;o#;<1Ahh->XZ6?edpPZs+&y7U0b!Qdmz>M!^hNTbMU+#B8X)lI!LrN< z_DH6Hzz)JcH?S}6|3BZot_1kw23F$4wn)h*d;DZ}e1EF7Q+V`(M5F!m42V$ae&q}v z&%cGad)K|vW9RNo9S@NyDRqv@`?qa;_}AA6n7h0*J3+#u5D}v~%+I9JfUH~rR~EAl zxIWE(##f5~_`HekY}4O&t46SC6GXgX4UEIkrGC+LT~Fs2T>8N&LM9ryNS1xE0h;Zq7-Jl4V(vpVE)#Yd&B7j&wnrqwR+kw;P&bL=mR5tc${ z-gw9I zcuI}7u?^6_cras8s|a=x^xi{7=gdsDw@khSh)29 z(};|!`>p&L$VW2^C|M%R0@kTG`cSC@^bvkv&%!^r;tZ(y5SS@yp21_s<6DRa0IG^u zSv`MBZ&_}MGM>dx;=v?GYfFCW^Do)RtehhJaW4IO|MPQ;Z%tAa=Svmk=Mu{8T@fxn zNYz|ph`fz$y#ga!(zB8}zTJgkiHM@MEgy#s@#1DQD1Jk{!!>e+;IIyjp%$xEm3D62Z$1{rBbJDmi3WYB7vS+jn6r(tF=Hv z1NG1`n9{nXhA5Yc4u4g4lLPMjauh%<_{h~s`9zAw(MuQm0?`NM1`} z@ieS{0QuE<;(OLDyo=xc@Z0A6nLbfeuivYL8`g`oN<^6*exZ%aK#ugJjT>fT~c^3EtU;)bON?d&0eqvc_11TgvG9rDQ z)pTyx{RYuWcPS49eJtI!KGb8--g(k|xtj+0)qPTbSLW8*!mo>m7MuCs=WgyxD(tq( zT2~DAccZ!Ufo7@KdpMTqDFMCB)fN(cKI|V$Cs7uC(v(|lxrx2{KiXkzaMbBX;)Nc^c@kpI&!EO8+!oBxG9{?z>3a5Mh?D& zVj|4k#L%3EI{BkA@nX!th7hEeHUEVTFN(DG6$=YSgeI^pGgmPzjX zb=P2m^yWA_;g6Vx(h3H~-T5+Rxdll&K=G)~U_J|{q|jT>eo#YB)2|>FwI1W{6w;uy zW|!8kAOf_dkzV%DT;d9I+>+$?^5MKz9;Jssx{?VJ&X7;ZTsSj9ektOcN|(4^kNUOP zXyDAZPWjBupxHKjZk<__KE*?wpEKwK+(Z7#X-BzNShrb4=q;(3gx2RqT-4-yF8^^R z%rD?2bT1I5?FldwRNF-5{`>8bY^2};E@&cX!ZI|^CAT>jjp=d; zllZIhoSYi81zT#>8f3m`AxKLL;zxz7DmhZEJvt9~UHA*4?l}zS8h5?tTU!~b@&#r0 zD1ALV;MlBXv1q^~Jml7*J(b=~x&w=1Sf(QV)OzfY?1nGiP};ZS=( z=H$3nd*IGdayP-53-ah$WGI6gUUi-Q^;Fy``wYKJl1jJgIl)>LioKuQ_xvKL!R8vv zMukkTu@U6BZE&9>V|UDjhYe2e$R@FlJ8&Wcd?GAiH{Fkh*gMbC6Hi^5<3*O>*rH#) zb>@}rpykku<;R|F)vId;yp#QHHO;l7y=REW z!|OXUd^1vOf?WqEgrFVMHk{n$5X|fjgOAkW)@5ug(GDQygWYwPPLX_wUDfOQAyBOf zJ9J?eA&HN{6K^A!KqF-gyo@uon6A=ims$5YEVefQlAKIAY_KaA{A((>yxqjXvH{2_ zj1~R7g!Lb`GQKz457CX?$^L?BS1EKa(Dt>kPckTmgHmlAR`g{irln>~$pa`+wZE=~ zRft;BR6q54*^AN|n=vVB4dG|)=3rNZsqJ1*do6+9mvJB01?vgUTHg+HPbjn85DzIj+~%?=!7DlAED|3c@h?cPRXTc>iyg3TM+`F8e|9z`Y< zBEu79mXc=~m2ySQkl5LmInzQ3lXr>Df!~+N5?lSY#uVxZXJYXe^*gqQ9qElE`ms-( zcV6hR5-h%0zw)5vms*5w4!vQ(Q+O*MwC%Wvk*x^lPVTktUB|KpPul-{TY$C4kTDB> z{rcX!^+O|!7HO>D`W#p8(*axFEC0r48K(t{Q8;P+*tCUk%bBv}A(bu;XMKjQ{!r-z zEkvS!c8@Pd7jg!)oc6Nu)%3=jwm)Kd@>1vX6F2Igq^36IM7+Wp%o|FYmYr{&SZ8U+ zP8JP`RZ%QVr53*t(RR3q>d5~zy1klb!SloM1(y)bV<&>Uj*~u)y=hK>;mKGVgNgME zY)R zsx&oGXXB5J71=nPJ0Y(m(Ts2Uc1$>+l{|bmZfK^0dc-=$2JX;;ahdK#m%d*pkk3f( zU7(k@Lhbqh%|8p7RrzLiza4(iQ>t(7N_0?sjl65Nv0ct?YJ2YksvzX7eH`fvMOWY8 z#@j-0y1;ZW8I!-SS67d@j~@DDN}hOP`k(7h~G%Echt@0@Z4tzF{v2@H6ITHZCIHy9AO}B6Muj?>0Ga?p^ou z7K(p{qbq_uxUgp`a>f{}+l#SBPeQFS#`HB*h#SL&>{= zKC*Z~zPb#19=#`*iyd$vZ7%Ic!LQizt}_Vmd`|>-W9TQmoI@#a7a|P55NbXlQj50# zyo_{I2Qrbq(G|iI`#7HElqg6sSm(V&PYasYbRM^(xSRs*YZ6AFxu}*|5V+eY7(bzN zwuHY3yQovz*zS60;w*qK59H-%|TzqZ7h)eiDSw3AR9P~!W&MEZIb-1poiQ6{ZOUIi&OJ! zg(ZoMArZ%dKL^c24_oBF$n`mx*ctqbcD%s9pyDe~hE|WIs(z||Vy0_Z_PiPJjCQ~q zb>d$x=4qW%5+16{xWk^hi0^qLopS8C_6!t^Fw*S`(V>Ni&sS{FOD0F0DG?cPF8q$K zMvF#evn`fKLPr}!g)5y`8nH72$+2cq&^E1e!V*a|KlC>WV8_W6(~p~06{dT|o$Geh zuztZz!ZoqcqAh$BsPLb$xkb5#`{e!-LX zS+HW@ClRc3ODPp`La3X5kI-gZ1OZrA$=^YIIjxuWjmkpg*&M~|a}jPptWCsYfGM)X z4EPd8xkfs1z+h@(s;}-dEZmw9*{+sTnChchf0r-j%duRAbMLgw>m(D0?6 z$IDVXqk6@M3ZjfT>)HA_-j-7{v_{n+hxd$_TtMq5CV65Sbr*sJSN4k+cp`>dE-bT% z#Qe7mgm=|r9uF$~14RF}gDi)B1N$`4vX8J-dQm5rY&!7PR96qk1p+d-p($yUw?ANM zg8gYVo=;)$?&4tK+w6R1kKWJq{SF;|Qr;dN3Qm>~j z@%)c5nAH?p5+d&y=|y1rO{+3Il>V$WO!2~Emj1^<%ZTnKxSzhm+Zut;&ox&o2Ny_v zeS&Q`W-?|R7w5?r49uq9Hq%#~Nz(O!^&QrWlGVf&Fqap?V;WF~XYrN^*#ZCbwB@k#C@yzzx0Uv)8>h}xdhHnZNF0E)SHjayVvbdy=`cyys>HgJnM#x z&Shic(T9$5A&1V*o{id6*>|;(vh#_|gX16AZ*JVaPe1(*wBF6^)31l3H(r6tmU&h{ zow_GuAwBid&{t@kaJ&61mND$kW7>OWsL4K39!1O~EIlN5AC7Yk8luf94~kIGduU%} zIJeN@1r=BQzpN(;L+!8g{g?^~`CT$O6Oy6kQkb2(_EPbY1zodZP0@#aq5~UeX~^6c ze#08W_(B^v1OL1#?;^4hO*o$D`mjoRG+^;gU3E{Bf9L?F{JL9`V?;~4VWn-nKBxxO z1g1qsx85EY7iU}6FqZ>)sFS2BpB&P+Si}pDE{V~DM0o^sw*b3<9{gE;r=Y1IZ`w|s+h=|Fec zX#mv--JpWMZ0T?7$tNB!!)QR#UeRr??{uH-PWnAh4@^hz%v|D&pY0D;pYA!^#XRor z(F(moPd}*xMm_-!Fm@@dKIKr&EP|!&B~<{EVPlZMJ7{a`BBSAONisLvi|VuJi;*y$ ziIN9I9+zE`Of0ubZ}S|-hVjAZ4#o>^a=k?hAQ<{t=0h9Dbn~|~U>`7OyOU`s0~C)F z8SKTvurxCz&i)-ofv9s_5hWtf7Z!2#5@(^sU+4J&L%#G%85Zsjmx42?!5CawYpxd~ zKg<#-qCygz_!!-MJ7)r6@`O5g#Y%j15aOB7+lNq@F1+dUxXkqD&c{fEZV9lSPp5WH z6TeO7?TF)4tRJ(rusD^?sHr-^am|h!YCP5JZ(D>yD1NU#M_f36h;LbF$p{5m7lJgv zdb0#uQcwv5f=6p+j)W}@TTpR~Xmo-d9Dp3*c`3}C)Dm7M0ro`UMsOqef1}p@Ym5;- zU3z)9)D?AWJ*w*+NNnfEG~*C0YewSTTW(O~lE0Efd-G7QQM17`vr9Q+873Ic)P{Q?1k-kE6m z=-|4b$esk2XnVEQ>!4Px!lLEEAd>@K;P;l-K+P(K0q>t#dRPD?ZUWCC$Y}neH1HH( z_C(1)y_KE$^@+piYj>k0OFKe7GPUiZl@!g{t9kL1%?H%YbSv@8l{afvvfELT#s=o* z=H_Fcz(PJSamI46vuQF_U8Cs?11{1+vPH8hCBdEv10{NNAu9?LND{0mKFVVfAnU@A z#)hmfgK3VvGBj zZj0A@A9BOO8yEDtU0SC#rd?8f*t%1g{$?Pn;CjuvWN%J*I8%M@Ft3)g-lOwF$mCwY zU9aIVO}5Rx=7|0b7xQ~bAhx9{ z%X?em=m+90?K7pazlR-RUP-B@WT~PuDJfo%Og`RPyu=M$<9V84Sv81Ln3Bs~%-amM zP$H)|+XJPCn1^xf4lvjJl!pb-yMnPC&f7W@msm6CoYoA4huyuo1G0$Co%mK%pus$C-~Wm(-=h zUj!*EEu4To#6D@!D=}xORJ!jk8RzMcoEm&bZ(6 zT~h8pLws&5z6ZRBOe$v<8{P4!KBHel$NpI%f3KBxS9N#&uTKfODTXq!6{gIUj?e)TxPaFmaCq{5-YMpf>Y#ls z1$y>4%BO z^^J`}R!Uo4eI=+0-L5gYFFs{4@UG1jdY(`)&a{dAq}aqhAamxkMZrm`ug#&eKd=@*zR)3;t_Tt%uC2;hSyX_0z%GhTXyY$VYsT|?) zfi1SPCuwsJjoCZO?JFkHC;F?rmPo)muht(nD?>}8fMWlP$flw+w`nPu{o_mE4=yu# zMRcipR42i0IBiC61(fA zIdc|9)Tw&a{;oxe^CJvU^Jy2cS_!bWKE_f5H+NM|l(fd^C|%M8&?C%uaY~D)hW6AX zFN8xpHlU$BA+Zk4FFD1-FHS(BHTG#Lc>z(%A`=!2Ri~YU24^8sdZar-K(kXk8eD}-U z{BS}0x{a=9pSOLfligpvsZL$t_I`ZrBd3llAEp8}YUmcuDE2RbaX%b9oWT7t7}#l=^0) zMZj)y$Z(H&!+&0k|ooLifR5X#bV+Al-_@~gWn_~38~q=?{#LgfPm_L zkDIpwZ(TLkafWy+I=Mh@yDElw`~IF*4;WXR#&dMq(G8!6+DyP*oG*nK>s4Ab<{OWcan^Bz_|QxoZvAstBw~ zyymVoT&p6mD)E}T)^M$gz^cS+?pnjODgvt#ueoat*QyAtO1$Q-HC(GAuqyGIyVh{6 ziomMGYwlXZwJHLu60f;y4cDp&tV+D*t~Fe%BCsm)n!DC;t%|^^#B1(a!?h{`s}ird zYYo?`2&_uH=B_ndt0J%}@tV8VaIK2Ks>EyVTEn#}0;>|QxoZvAstBw~yymVoT&p6m zD)E2mt}Xv`_i*)D>Ei)i>CDmmsYX^nK$vmm!r7ZEopI6;@#d}vaNw4GTM`uCoOtqO zOQZUm`Ok^!uW~%HGTZu<4OK3h*h;o+`*6z4@b&APr!R2lVmkfOza!SKywhavo$8b3 z`iUsJD~ab4u0>yCAM#om?vJR;q4Wh%Db?Y>$TOVO@&J5jJ7+AExR}m_AxVQn2i4?u zUVa9;BEOU6vS*ue{P8-0bx(KywLtsyUUcf}xay}%j!sWyNm+&LBf^HLxOH^`E$-r9 z+9gpNPX*w{HZ59dIDKsD?Zq%^*ja>kkBjf_l-6~(VzA#AqsC7lvdoNqU(em0QSKDo%TLTL>PGhSMegwMz+*Cozv1buvAV)yQt_(<@Z zqaH`@HPvR+`Z@;bq&Xyh0r{m{X9c5kZs^)IXx45VIZ`yIE`$?GyB`(*a7b8dtJbb8 ziDW^1_)=7PoRYln{xHjaa?`RPQJ_HpbqU_Rrxs*d`t(kCAEjq@YeYr~6ytdhcRx-R z2H(g!Iv<)%#ojxTP@;1rqfNZyrb&jX$9m-Y9YTuhFRhaniW8K--K-&~+c6j|L=iMG z7z-atniWnLi8k>0Cf|tQ326ODGA$pw^zs_Szu?=Q=M?e#Nq6`k1mrrn3g?*h*%*0* zYK4-`z4}_B;r3ysVA{P!+izk5=kKT1T5HB1yYJay==&ip-Lq;r@!p1u%c+++X#Cj8Vzk)F?Gji%e(X9x)yyngj!Mr!>KHIi8CUcF?8noultEh!{x0=kmM7`=0 zcPklc<&QL}6i&M_5>mI*+BGjV?*+x6d0#^lQx!A{txXx)Y6C8A0fV6#Io%`e!l`{W zZjAWUrMM|pRjLBh#k1Ax?0cTIT6lkJ^4`vT8!)eTGjSp`hRJggNwUJwPv9;6& zoZM0_HJ7~V^LEpyO~jHXrJ*S6)?5s<8k?G@R+y&WcgiyENv?JmQA15!`~)Sd}dGj*;I=JMb`H)Lx*_l0w-YXpzVfB8W zW+5lPsJ$CA&c=1tI*#mgGpNv!LXA^18cUyO)U?0|$un;@#R*xy zyAmeg9V1Yh{4qd-WXnwW{^Qe#rwwK z1p7U{n)BP{kIr9?tf<~E7d`+(?Bjv_lcC<5tQ{|9zP#DQjz!pF6&t*e!&L<~4VN7qIzKWRK1S#{FUhL3u z<>}~z#$Qr#$X4fsLfFY9j1VWS?&A2mA!d|oNs2K1(d6i+(;|r-77pHb6W&V3yqi6H zT%i0BOR`w9Ct^>5xI&X3D}k(h`cPznO~(xL{D^GPmK{$$oYm`z&$g}8c()0<R;21o-J(YSoAu3?LppHsI)h#qiJKM*sRW^~Q4l~mS#(z07X zQ+8HbG(kk5hMGYYLT{`Q?QWRd9oA-G`jc=QZ5K_uh7sU(e%m>uv+-S8#~!v~d~D-m zA+RvzcwwIPc=*Lc*0;{8z3>Z_Q8TP>kw0Y)dPNJt&mGgSxVp~k9KV5An-Y)p+hVwz zW5Up&yZs7&>8!IcFGQ@O!suS#6&aWu+IfSoCN)gePlXN+?b*eC7%Ek3&kwTjwp_p9=G{2kQ6Rjex_6oRdr*_ zX8wj+$Thg{j)ExE+YCzQ?IhmukOK?t^PVcI*B%5M@P_PTywTjdcx~MLxyAdwskug9 z3?;Cr*fv&{SX~S5IBe(e9@ddK^kBtAbb;ze7TsTEQZh#-?-H=(I%*whuPlo6@$#zZ z!yy}4YVm?KF+$n$9aonST;+!>j^Db2@{MxI#%g5f$#MF*s(oOU3NSRSntkpJ#o z956H;>}a8rhA4UP;V$cu4|Zon?U}ESMF0J&`upV-5QdY}jzu3GBL3DH^vXq(3+Qu> G5B?9KJX&7> literal 2096 zcmV-02+#M4P)LH)rZ3KBNO7>$3_$f6OAA`wJX42Fn7K!u>9f+CBR z#Y&;J>@CxF+Rk{+^n3R9a$jc(LZ`?{zI5izoBQrP>vzu75ex?DQp@g>e(JvR5LHz1 zvmF<_oUG7>k;Ul7$j0kb#vP2juq((mSP!>nBvJpg1e%cLp|(k})DYsL#wi{~SH?|@ zdtihnhWoA!YY_3riU2(~uqDmz)x5zE)|d>Ez!=CF&$t;;5l+J2;}6iB{@$oCMq@EZ z55@$>a7IQwzuU6TPdPG%b@b5OJ}si=unl97$m&)aV-DjH!#-t!BE|v6Uko23p3$Ar zNxRQ1T))yhv9u(o6}cSr|29a1%Slo)D?<7*YNG?=OGc)4y^yhv@h;;>#u@GN8yVj! z@5}2l$dvA>)H*S`l7zD%9(oOX=56VTY!O=r9;O*XqF@r(lccYW24jQ>9HT&af5y0a zWq@vI(}bpVOO3kx>};q9OWt<7opwn@RqE%AzKk~*C&Mf&pC3`)A2Z$+VC!~CA(xY` z7{rpEUN?=)N)8oPgQ!$>rKaQvx{80L#8k+0GLvY$Jp1BF6V$ZEV-S%S`gtimB`%cD zH4y`p;&s1zDnjM2Wu}{^bM3gub$ljcj8dmRW!xL}25Au=6Dq6*gGhwz$Lo=dt8JEu z)mTAOMzfm4q!~n_qirG$$xOW1M^ht24tJ1oI_eD~GPzqb%E?I7Q&$yZCtiC&ebrG( zJH|68^g+!))|o16u`C&naM4)M*Grd}<;q#6GB!j?d)vYzyMf2&GPdHn&rlfKf%R0N z@v1_u?vLJKFXJceJ26r=gka&`ZHyD44_G_%xWI49_mRee#UKw@S%%RX%I?kR%s9&E zqdlh-`y%`;Q=?;Oho&?jEkV~oN1R*E@eQc8ND|{J#veA#W}$MeE%qY2--NYP$-sGw zwLYsiCJ+)q+a;=<$agZ1cmf;ffiFD87-}%$^O9}wTINV|8BfDdWq3bZ^V(N&Z!r$^ z8V(VX9HyX?g@V?Ok{`4b@GxT{qYL9tsvaEXYkNDZFtGrlq}tH2PMX%^9GW{FdksKA z%b)|ob6z%_e-vYc^8RkdTZ}|Rr08;xQUgV1!67Xf%veg*15nY~{aC~8g13paAJrZl zNn|_VU859_*^GmE(M`|5-)EKYi9+W?!6BKLolFaNos<^Adh&MEk@o83iLo3Ve7<2n zW$?uIh^82oe3e!P_3ZFH<8>vH0!S}2B1}i^aqmb(tR(~Bh$hK|6O3jY#`_ z-JNJ-480kwVO(NhHpcw#ib%1EM9!%HSl(lb0u?%R>w#*>u_vh+& z4k}|d7yA9jQ7ibb+wz#GK6d49sw!R*&Ms3}lZOn4Yx{I~_?nyTx!_Qe{P52HAk=sVet@x>iIGp4RpC zP-2`$`39K`GMuTYp;45SGzFo)0E}*zf!nu1O0dX9k@fA)scwBukJhZY!Q8B3ycf#v zq80JGl=H7gO;8)xPB4<)q|B~5Pb2wpQ8(oM5lQq8prTYNfIve?Xy|U?Yy$&e- zKqX!;Lw;V3DXkk6@I%vXAG$7?R_rl0wNHXU%|jX+Yk2k`C1t&@eo%g{k!42qCRkDd zl%0#cT4#8Lv54_8t_QHLRj2lV8n46uB8DlhO@WShbVg7Eo z$Ac8;*GNeg_Hf8zYOXL0D+n(jn+d8f4E5AmL{YdpvipP|HN@5+2W+lS#Q{ZLs$GE` zwC|Lkb{#LLp5A!9k=&-OqdQljM(h0%oXsDBKKzJ~=$d7zvgS|;&Dc^{Jx{5hj8huV z#i$>(;ymaN(DuSIigt+_gRILtOC#3ilTTW8r_mrDq!V2vAHS{S^qF?Ce(+4i6@x?~ zK5n09Z7rgzDqCX^hM$YHYr;$xB43|Eq@1zid`EqiQE!l__=W$I{l&DSfa_meo&HgX z`Oh&hl;Ie3T5RtzFcn)8o`1ILia{cgRcw$5Mwxkl^dpnNQXF7=6AVq_ITC1qf17P| zDeG`aC2cz5i=>d3qL&eg$KLb6;aAXQA`KoPo4M~e%|;26t}I!CPFbk;Dl}jx=rWRj a1Q-BzrX;*g)nEJo0000 Date: Thu, 4 Dec 2014 15:23:37 -0500 Subject: [PATCH 04/80] Merged with Rune Header --- app/templates/header.php | 45 +++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/app/templates/header.php b/app/templates/header.php index 62c5dfaa..d5bbc24c 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -4,32 +4,29 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + uri(1)) OR ($this->uri(1) == 'playback')): ?> From 77763648f1e4723d7e034cf584fe0bd4bbe61dfc Mon Sep 17 00:00:00 2001 From: kdubious Date: Thu, 4 Dec 2014 15:24:14 -0500 Subject: [PATCH 05/80] Moved the Alphabet piece to its own function --- assets/js/runeui.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 3045feb1..89852eb6 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -409,6 +409,21 @@ function chkKey(key) { return (key !== undefined && key !== ''); } +function setupAlphabetNav() { + // + // look for the named Anchor tags to see which navigation letters to disable + setupAlphabetNav(); + $('.alphabetTag').each(function (index) { + console.log("alphabetTag index:" + index + " name: " + $(this).attr('name')); + var button = $("a[data-alphabet='" + $(this).attr('name') + "']")[0]; + if (button) { + $(button).removeClass('disabled') + } + }) + // +} + + // render the Library home screen function renderLibraryHome() { loadingSpinner('db'); @@ -1136,13 +1151,7 @@ function populateDB(options){ // // look for the named Anchor tags to see which navigation letters to disable - $('.alphabetTag').each(function (index) { - console.log("alphabetTag index:" + index + " name: " + $(this).attr('name')); - var button = $("a[data-alphabet='" + $(this).attr('name') + "']")[0]; - if (button) { - $(button).removeClass('disabled') - } - }) + setupAlphabetNav(); // From b054fb69156cc657b6d773ab86a0ca9d97fda457 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Tue, 9 Dec 2014 00:48:49 +0100 Subject: [PATCH 06/80] wolfosn.sh start script. (Thanks to Andrea Rizzato) --- command/wolfson.sh | 136 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100755 command/wolfson.sh diff --git a/command/wolfson.sh b/command/wolfson.sh new file mode 100755 index 00000000..78fe70d2 --- /dev/null +++ b/command/wolfson.sh @@ -0,0 +1,136 @@ +#!/bin/bash +# +# wolson.sh +# ---------------- +# Select the audio output for the Wolfson Audio Card in RuneAudio +# +# Set some standard paths +AMIXER=/usr/bin/amixer +MPC=/usr/bin/mpc +# +# Set variables +CARD="$1" +ENABLE_OUTPUT="$2" +# +function amixer_cset { + $AMIXER -c $CARD cset name="$1" $2 +} +# +# function wolfson_enable { +# $MPC enable only snd_rpi_wsp +# +# +function reset_paths { + # + # Switch everything off + # + amixer_cset 'TX Playback Switch' off + amixer_cset 'RX Playback Switch' off + amixer_cset 'AIF Playback Switch' off + amixer_cset 'SPDIF in Switch' off + amixer_cset 'SPDIF out Switch' off + #amixer_cset 'IN1 Digital Switch' off + #amixer_cset 'IN2 Digital Switch' off + #amixer_cset 'IN3 Digital Switch' off + amixer_cset 'IN3 High Performance Switch' off + amixer_cset 'Headset Mic Switch' off + amixer_cset 'DMIC Switch' off + amixer_cset 'Speaker Digital Switch' off + amixer_cset 'AIF1TX1 Input 1' None + amixer_cset 'AIF1TX2 Input 1' None + amixer_cset 'AIF2TX1 Input 1' None + amixer_cset 'AIF2TX2 Input 1' None + amixer_cset 'HPOUT1L Input 1' None + amixer_cset 'HPOUT1R Input 1' None + amixer_cset 'HPOUT1L Input 2' None + amixer_cset 'HPOUT1R Input 2' None + amixer_cset 'HPOUT2L Input 1' None + amixer_cset 'HPOUT2R Input 1' None + amixer_cset 'HPOUT2L Input 2' None + amixer_cset 'HPOUT2R Input 2' None + amixer_cset 'SPKOUTL Input 1' None + amixer_cset 'SPKOUTR Input 1' None + amixer_cset 'SPKOUTL Input 2' None + amixer_cset 'SPKOUTR Input 2' None +} +# +function line_out { + # + # Enable MPD output only to line_out + # $MPC enable only snd_rpi_wsp_1 + # + # Playback from AP to Lineout + # + amixer_cset 'HPOUT2 Digital Switch' on + amixer_cset 'HPOUT2L Input 1' AIF1RX1 + amixer_cset 'HPOUT2L Input 1 Volume' 32 + amixer_cset 'HPOUT2R Input 1' AIF1RX2 + amixer_cset 'HPOUT2R Input 1 Volume' 32 +} +# +function speakers_out { + # + # Enable MPD output only to speakers + # $MPC enable only snd_rpi_wsp_4 + # + # Playback from AP to Speakers + # + amixer_cset 'Speaker Digital Volume' 128 + # reset speaker mixer inputs + amixer_cset 'SPKOUTL Input 1' None + amixer_cset 'SPKOUTR Input 1' None + amixer_cset 'SPKOUTL Input 2' None + amixer_cset 'SPKOUTR Input 2' None + # Route AP to Speaker mixer + amixer_cset 'SPKOUTL Input 1' AIF1RX1 + amixer_cset 'SPKOUTL Input 1 Volume' 32 + amixer_cset 'SPKOUTR Input 1' AIF1RX2 + amixer_cset 'SPKOUTR Input 1 Volume' 32 + # Unmute speaker output + amixer_cset 'Speaker Digital Switch' on +} +# +function spdif_out { + # + # Enable MPD output only to SPDIF + # $MPC enable only snd_rpi_wsp_2 + # + # Playback from AP to SPDIF + # + amixer_cset 'SPDIF out Switch' on + amixer_cset 'TX Playback Switch' on + amixer_cset 'Input Source' AIF + amixer_cset 'AIF Playback Switch' on + amixer_cset 'AIF2TX1 Input 1' AIF1RX1 + amixer_cset 'AIF2TX1 Input 1 Volume' 32 + amixer_cset 'AIF2TX2 Input 1' AIF1RX2 + amixer_cset 'AIF2TX2 Input 1 Volume' 32 +} +function headset_out { + # + # Enable MPD output to headset only + # $MPC enable only snd_rpi_wsp_3 + # + # Playback from AP to Headset + # + # + amixer_cset 'HPOUT1 Digital Switch' on + # Set path gain to -6dB for safety. ie max 0.5Vrms output level + amixer_cset 'HPOUT1 Digital Volume' 116 + # Do we want to clear the HPOUT mixer inputs? + amixer_cset 'HPOUT1L Input 1' None + amixer_cset 'HPOUT1R Input 1' None + amixer_cset 'HPOUT1L Input 2' None + amixer_cset 'HPOUT1R Input 2' None + amixer_cset 'HPOUT1L Input 1' AIF1RX1 + amixer_cset 'HPOUT1L Input 1 Volume' 32 + amixer_cset 'HPOUT1R Input 1' AIF1RX2 + amixer_cset 'HPOUT1R Input 1 Volume' 32 +} +# +# +# MAIN +# +# wolfson_enable +reset_paths +$ENABLE_OUTPUT From af87a0c15d769f129c09c4a1bcc2088e9d86aa8d Mon Sep 17 00:00:00 2001 From: Orion1 Date: Tue, 9 Dec 2014 00:51:45 +0100 Subject: [PATCH 07/80] Improved AudioCards switch code. Better support of WAC. Improved support for autodetection of HW mixer controls --- app/libs/runeaudio.php | 79 ++++++++++++++++++++--------------------- command/rune_SY_wrk | 2 ++ db/redis_acards_details | 16 ++++----- 3 files changed, 49 insertions(+), 48 deletions(-) diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index b7657cbf..40fcd6d3 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -817,7 +817,7 @@ function _parseStatusResponse($resp) $plistFile = ""; $plCounter = -1; while ($plistLine) { - list ($element, $value) = explode(": ", $plistLine); + list ($element, $value) = explode(": ", $plistLine, 2); $plistArray[$element] = $value; $plistLine = strtok("\n"); } @@ -2042,8 +2042,8 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) // --- decoder plugin --- $output .="\n"; $output .="decoder {\n"; - $output .="plugin \t\"ffmpeg\"\n"; - $output .="enabled \"".$value."\"\n"; + $output .="\tplugin \t\"ffmpeg\"\n"; + $output .="\tenabled \"".$value."\"\n"; $output .="}\n"; continue; } @@ -2051,12 +2051,12 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) // --- input plugin --- $output .="\n"; $output .="input {\n"; - $output .="plugin \t\"curl\"\n"; + $output .="\tplugin \t\"curl\"\n"; if ($redis->hget('proxy','enable') === '1') { - $output .="proxy \t\"".($redis->hget('proxy', 'host'))."\"\n"; + $output .="\tproxy \t\"".($redis->hget('proxy', 'host'))."\"\n"; if ($redis->hget('proxy','user') !== '') { - $output .="proxy_user \t\"".($redis->hget('proxy', 'user'))."\"\n"; - $output .="proxy_password \t\"".($redis->hget('proxy', 'pass'))."\"\n"; + $output .="\tproxy_user \t\"".($redis->hget('proxy', 'user'))."\"\n"; + $output .="\tproxy_password \t\"".($redis->hget('proxy', 'pass'))."\"\n"; } } $output .="}\n"; @@ -2071,16 +2071,17 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) runelog('detected ACARDS ', $acards, __FUNCTION__); $ao = $redis->Get('ao'); $sub_count = 0; - foreach ($acards as $card) { + foreach ($acards as $main_acard_name => $main_acard_details) { $card_decoded = new stdClass(); - $card_decoded = json_decode($card); + $card_decoded = json_decode($main_acard_details); // debug - runelog('decoded ACARD ', $card_decoded, __FUNCTION__); + runelog('decoded ACARD '.$card_decoded->name, $card_decoded, __FUNCTION__); + // handle sub-interfaces if (isset($card_decoded->integrated_sub) && $card_decoded->integrated_sub === 1) { // record UI audio output name $current_card = $card_decoded->name; - if ($sub_count >= 1) continue; - $card_decoded = json_decode($card_decoded->real_interface); + // if ($sub_count >= 1) continue; + // $card_decoded = json_decode($card_decoded->real_interface); runelog('current AO ----> ', $ao, __FUNCTION__); // var_dump($ao); runelog('current card_name ----> ', $card_decoded->name, __FUNCTION__); @@ -2092,44 +2093,40 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) // debug runelog('this is a sub_interface', __FUNCTION__); $sub_interface = 1; + // debug $sub_count++; runelog('sub_count', $sub_count, __FUNCTION__); } $output .="\n"; $output .="audio_output {\n"; - $output .="name \t\t\"".$card_decoded->name."\"\n"; - $output .="type \t\t\"".$card_decoded->type."\"\n"; - $output .="device \t\t\"".$card_decoded->device."\"\n"; + // $output .="name \t\t\"".$card_decoded->name."\"\n"; + if (isset($sub_interface)) { + $output .="\tname \t\t\"".$card_decoded->name."\"\n"; + } else { + $output .= $main_acard_name; + } + $output .="\ttype \t\t\"".$card_decoded->type."\"\n"; + $output .="\tdevice \t\t\"".$card_decoded->device."\"\n"; if (isset($hwmixer)) { - $output .="mixer_type \t\"hardware\"\n"; - if (isset($card_decoded->mixer_device)) { - $output .="mixer_device \t\"".$card_decoded->mixer_device."\"\n"; + if (isset($card_decoded->mixer_control)) { + $output .="\tmixer_control \t\"".$card_decoded->mixer_control."\"\n"; + $output .="\tmixer_type \t\"hardware\"\n"; + $output .="\tmixer_device \t\"".substr($card_decoded->device, 0, 4)."\"\n"; } else { - $output .="mixer_device \t\"hw:".$card_decoded->device."\"\n"; - } - if (isset($card_decoded->mixer_control)) { - $output .="mixer_control \t\"".$card_decoded->mixer_control."\"\n"; - } else { - $output .="mixer_control \t\"".alsa_findHwMixerControl(substr($card_decoded->device, 4, 1)).",0\"\n"; + if (!isset($sub_interface)) { + $output .="\tmixer_control \t\"".alsa_findHwMixerControl(substr($card_decoded->device, 5, 1))."\"\n"; + } } - $output .="mixer_index \t\"0\"\n";"\t\t \t\"0\"\n"; - } - if ($mpdcfg['dsd_usb'] === 'yes') $output .="dsd_usb \t\"yes\"\n"; - $output .="auto_resample \t\"no\"\n"; - $output .="auto_format \t\"no\"\n"; - if (isset($sub_interface_selected)) { - // use UI selector name to enable a sub_interface (ex. switch between AnalogOut / HDMI on RaspberryPI) - $output .="enabled \t\"yes\"\n"; - } else { - // normal condition - if ($ao === $card_decoded->name) $output .="enabled \t\"yes\"\n"; + // $output .="\tmixer_index \t\"0\"\n";"\t\t \t\"0\"\n"; } + if ($mpdcfg['dsd_usb'] === 'yes') $output .="\tdsd_usb \t\"yes\"\n"; + $output .="\tauto_resample \t\"no\"\n"; + $output .="\tauto_format \t\"no\"\n"; + if ($ao === $main_acard_name) $output .="\tenabled \t\"yes\"\n"; $output .="}\n"; - // unset($current_card); - // unset($sub_interface); - // unset($card_decoded); + unset($sub_interface); // debug - runelog('conf output (in loop)', $output, __FUNCTION__); + // runelog('conf output (in loop)', $output, __FUNCTION__); } $output .="\n"; // debug @@ -2160,7 +2157,7 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) sysCmd($interface_details->route_cmd); // TODO: improove this function sysCmd('amixer -c 0 set PCM unmute'); - $mpdout = $interface_details->sysname; + // $mpdout = $interface_details->sysname; } wrk_mpdconf($redis, 'writecfg'); wrk_shairport($redis, $args); @@ -2644,6 +2641,8 @@ function alsa_findHwMixerControl($cardID) $cmd = "amixer -c ".$cardID." |grep \"mixer control\""; $str = sysCmd($cmd); $hwmixerdev = substr(substr($str[0], 0, -(strlen($str[0]) - strrpos($str[0], "'"))), strpos($str[0], "'")+1); + runelog('Try to find HwMixer control (str): ', $str); + runelog('Try to find HwMixer control: (output)', $hwmixerdev); return $hwmixerdev; } diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 125ac7aa..e9b3fb62 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -222,12 +222,14 @@ sysCmd("/var/www/command/orion_optimize.sh ".$redis->get('orionprofile')." ".$re // start php-fpm sysCmd('systemctl start php-fpm'); // PHP 5.5 OPCache +/* if ($redis->get('dev') === '0') { // prime PHP OPCache runelog('prime PHP OPCache'); // wrk_opcache('prime',$redis); sysCmdAsync("curl -s -X GET 'http://localhost/command/cachectl.php?action=prime'"); } +*/ // mount all sources wrk_sourcemount($redis, 'mountall'); runelog('--- NORMAL STARTUP'); diff --git a/db/redis_acards_details b/db/redis_acards_details index 0ba0aaf4..e14c35c5 100755 --- a/db/redis_acards_details +++ b/db/redis_acards_details @@ -49,7 +49,6 @@ $redis->hSet('acards_details', 'XMOS USB Audio 2.0', '{"sysname":"XMOS USB Audio $redis->hSet('acards_details', 'wm8731-audio', '{"sysname":"wm8731-audio","extlabel":"Utilite Analog Out","mixer_numid":"1","mixer_control":"Master","hwplatformid":"05","type":"integrated"}'); $redis->hSet('acards_details', 'imx-spdif', '{"sysname":"imx-spdif","extlabel":"Utilite Coax SPDIF Out","hwplatformid":"05","type":"integrated"}'); $redis->hSet('acards_details', 'imx-hdmi-soc', '{"sysname":"imx-hdmi-soc","extlabel":"Utilite HDMI Out","hwplatformid":"05","type":"integrated"}'); -$redis->hSet('acards_details', 'bcm2835 ALSA', '{"sysname":"bcm2835 ALSA","extlabel":"none","mixer_numid":"1","mixer_control":"PCM","hwplatformid":"01","type":"integrated_sub"}'); $redis->hSet('acards_details', 'SA9023 USB Audio', '{"sysname":"SA9023 USB Audio","extlabel":"HiFimeDIY SABRE U2","mixer_numid":"4","mixer_control":"PCM","type":"usb"}'); $redis->hSet('acards_details', 'UAC1 DAC', '{"sysname":"UAC1 DAC","extlabel":"ObjectiveDAC (ODAC)","mixer_numid":"3","mixer_control":"PCM","type":"usb"}'); $redis->hSet('acards_details', 'USB Sound Device', '{"sysname":"USB Sound Device","extlabel":"Cmedia CM2606","mixer_numid":"7","mixer_control":"Speaker","type":"usb"}'); @@ -61,12 +60,13 @@ $redis->hSet('acards_details', 'AudioQuest DragonFly', '{"sysname":"AudioQuest D $redis->hSet('acards_details', 'USB Audio CODEC', '{"sysname":"USB Audio CODEC","extlabel":"Behringer U-CONTROL UCA202","mixer_numid":"3","mixer_control":"PCM","type":"usb"}'); $redis->hSet('acards_details', 'NuForce USB Audio', '{"sysname":"NuForce USB Audio","extlabel":"NuForce DDA-100","mixer_numid":"4","mixer_control":"PCM","type":"usb"}'); $redis->hSet('acards_details', 'Rotel PC-USB', '{"sysname":"Rotel PC-USB","extlabel":"Rotel USB","type":"usb"}'); -$redis->hSet('acards_details', 'snd_rpi_wsp', '{"sysname":"snd_rpi_wsp","extlabel":"none","mixer_numid":"1","mixer_control":"HPOUT2 Digital","hwplatformid":"01","type":"integrated_sub"}'); -$redis->sAdd('bcm2835 ALSA', '{"id":"1","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi Analog Out","hwplatformid":"01","route_cmd":"amixer -c *CARDID* cset numid=3 1 > /dev/null"}'); -$redis->sAdd('bcm2835 ALSA', '{"id":"2","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi HDMI Out","hwplatformid":"01","route_cmd":"amixer -c *CARDID* cset numid=3 2 > /dev/null"}'); -$redis->sAdd('snd_rpi_wsp', '{"id":"1","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Line Out","hwplatformid":"01","route_cmd":"/srv/http/command/wolfson.sh *CARDID* line_out > /dev/null"}'); -$redis->sAdd('snd_rpi_wsp', '{"id":"2","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card S/PDIF Out","hwplatformid":"01","route_cmd":"/srv/http/command/wolfson.sh *CARDID* spdif_out > /dev/null"}'); -$redis->sAdd('snd_rpi_wsp', '{"id":"3","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Headset Out","hwplatformid":"01","route_cmd":"/srv/http/command/wolfson.sh *CARDID* headset_out > /dev/null"}'); -$redis->sAdd('snd_rpi_wsp', '{"id":"4","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Speakers Out","hwplatformid":"01","route_cmd":"/srv/http/command/wolfson.sh *CARDID* speakers_out > /dev/null"}'); +$redis->hSet('acards_details', 'bcm2835 ALSA', '{"sysname":"bcm2835 ALSA","extlabel":"none","hwplatformid":"01","type":"integrated_sub"}'); +$redis->hSet('acards_details', 'snd_rpi_wsp', '{"sysname":"snd_rpi_wsp","extlabel":"none","hwplatformid":"01","type":"integrated_sub"}'); +$redis->sAdd('bcm2835 ALSA', '{"id":"1","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi Analog Out","hwplatformid":"01","mixer_numid":"1","mixer_control":"PCM","route_cmd":"amixer -c *CARDID* cset numid=3 1 > /dev/null"}'); +$redis->sAdd('bcm2835 ALSA', '{"id":"2","sysname":"bcm2835 ALSA","extlabel":"RaspberryPi HDMI Out","hwplatformid":"01","mixer_numid":"1","mixer_control":"PCM","route_cmd":"amixer -c *CARDID* cset numid=3 2 > /dev/null"}'); +$redis->sAdd('snd_rpi_wsp', '{"id":"1","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Line Out","hwplatformid":"01","mixer_numid":"1","mixer_control":"HPOUT2 Digital","route_cmd":"/srv/http/command/wolfson.sh *CARDID* line_out > /dev/null"}'); +$redis->sAdd('snd_rpi_wsp', '{"id":"2","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card S/PDIF Out","hwplatformid":"01","mixer_numid":"1","route_cmd":"/srv/http/command/wolfson.sh *CARDID* spdif_out > /dev/null"}'); +$redis->sAdd('snd_rpi_wsp', '{"id":"3","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Headset Out","hwplatformid":"01","mixer_numid":"1","mixer_control":"HPOUT1 Digital","route_cmd":"/srv/http/command/wolfson.sh *CARDID* headset_out > /dev/null"}'); +$redis->sAdd('snd_rpi_wsp', '{"id":"4","sysname":"snd_rpi_wsp","extlabel":"Wolfson Card Speakers Out","hwplatformid":"01","mixer_numid":"1","mixer_control":"Speaker Digital","route_cmd":"/srv/http/command/wolfson.sh *CARDID* speakers_out > /dev/null"}'); echo "Audio Cards database initialized\n"; From f336884b3c150467015fbc4bf6bf0a2f0f6b3c43 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Tue, 9 Dec 2014 01:03:08 +0100 Subject: [PATCH 08/80] Solved some cases of SLOD (SpinningLoaderOfDeath) --- assets/js/runeui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 499d8b15..30beea61 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -1429,6 +1429,7 @@ function playbackChannel(){ pushstream.onstatuschange = function(status) { // console.log('[nginx pushtream module] status = ', status); if (status === 2) { + $('#loader').addClass('hide'); sendCmd('renderui'); // force UI rendering (backend-call) } else { // console.log('[nginx pushtream module] status change (' + status + ')'); From fd3da01389a3c8b9a0f2f77ef3d1f3b4155b5441 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Wed, 10 Dec 2014 22:45:02 +0100 Subject: [PATCH 09/80] .editorconfig file --- .editorconfig | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..7b09771a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true From 74be56705d9424c659908d3f38db010ad538984c Mon Sep 17 00:00:00 2001 From: ACXgit Date: Wed, 10 Dec 2014 22:45:39 +0100 Subject: [PATCH 10/80] Inclusion of Mithril.js framework --- assets/js/vendor/mithril.min.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 assets/js/vendor/mithril.min.js diff --git a/assets/js/vendor/mithril.min.js b/assets/js/vendor/mithril.min.js new file mode 100644 index 00000000..59acfa71 --- /dev/null +++ b/assets/js/vendor/mithril.min.js @@ -0,0 +1,8 @@ +/* +Mithril v0.1.26 +http://github.com/lhorie/mithril.js +(c) Leo Horie +License: MIT +*/ +var m=function a(b,c){function d(a){C=a.document,D=a.location,F=a.cancelAnimationFrame||a.clearTimeout,E=a.requestAnimationFrame||a.setTimeout}function e(){var a,b=[].slice.call(arguments),c=!(null==b[1]||K.call(b[1])!=G||"tag"in b[1]||"subtree"in b[1]),d=c?b[1]:{},e="class"in d?"class":"className",f={tag:"div",attrs:{}},g=[];if(K.call(b[0])!=I)throw new Error("selector in m(selector, attrs, children) should be a string");for(;a=L.exec(b[0]);)if(""==a[1]&&a[2])f.tag=a[2];else if("#"==a[1])f.attrs.id=a[2];else if("."==a[1])g.push(a[2]);else if("["==a[3][0]){var h=M.exec(a[3]);f.attrs[h[1]]=h[3]||(h[2]?"":!0)}g.length>0&&(f.attrs[e]=g.join(" "));var i=c?b[2]:b[1];f.children=K.call(i)==H?i:b.slice(c?2:1);for(var j in d)f.attrs[j]=j==e?(f.attrs[j]||"")+" "+d[j]:d[j];return f}function f(a,b,d,e,i,k,l,m,n,o,p){if(null==i&&(i=""),"retain"===i.subtree)return k;var q=K.call(k),r=K.call(i);if(null==k||q!=r){if(null!=k)if(d&&d.nodes){var s=m-e,t=s+(r==H?i:k.nodes).length;h(d.nodes.slice(s,t),d.slice(s,t))}else k.nodes&&h(k.nodes,k);k=new i.constructor,k.tag&&(k={}),k.nodes=[]}if(r==H){for(var u=0;u\s*[^<]/g)||[]).length:K.call(T)==H?T.length:1,k[S++]=T)}if(!w){for(var u=0;u("key"in i.attrs?1:0)}if((i.tag!=k.tag||V.join()!=Object.keys(k.attrs).join()||i.attrs.id!=k.attrs.id)&&(k.nodes.length&&h(k.nodes),k.configContext&&typeof k.configContext.onunload==J&&k.configContext.onunload()),K.call(i.tag)!=I)return;var U,W=0===k.nodes.length;if(i.attrs.xmlns?o=i.attrs.xmlns:"svg"===i.tag?o="http://www.w3.org/2000/svg":"math"===i.tag&&(o="http://www.w3.org/1998/Math/MathML"),W?(U=i.attrs.is?o===c?C.createElement(i.tag,i.attrs.is):C.createElementNS(o,i.tag,i.attrs.is):o===c?C.createElement(i.tag):C.createElementNS(o,i.tag),k={tag:i.tag,attrs:V.length?g(U,i.tag,i.attrs,{},o):{},children:null!=i.children&&i.children.length>0?f(U,i.tag,c,c,i.children,k.children,!0,0,i.attrs.contenteditable?U:n,o,p):i.children,nodes:[U]},k.children&&!k.children.nodes&&(k.children.nodes=[]),"select"==i.tag&&i.attrs.value&&g(U,i.tag,{value:i.attrs.value},{},o),a.insertBefore(U,a.childNodes[m]||null)):(U=k.nodes[0],V.length&&g(U,i.tag,i.attrs,k.attrs,o),k.children=f(U,i.tag,c,c,i.children,k.children,!1,0,i.attrs.contenteditable?U:n,o,p),k.nodes.intact=!0,l===!0&&null!=U&&a.insertBefore(U,a.childNodes[m]||null)),typeof i.attrs.config==J){var X=k.configContext=k.configContext||{},Y=function(a,b){return function(){return a.attrs.config.apply(a,b)}};p.push(Y(i,[U,!W,X,k]))}}else if(typeof r!=J){var v;0===k.nodes.length?(i.$trusted?v=j(a,m,i):(v=[C.createTextNode(i)],a.nodeName.match(N)||a.insertBefore(v[0],a.childNodes[m]||null)),k="string number boolean".indexOf(typeof i)>-1?new i.constructor(i):i,k.nodes=v):k.valueOf()!==i.valueOf()||l===!0?(v=k.nodes,n&&n===C.activeElement||(i.$trusted?(h(v,k),v=j(a,m,i)):"textarea"===b?a.value=i:n?n.innerHTML=i:((1==v[0].nodeType||v.length>1)&&(h(k.nodes,k),v=[C.createTextNode(i)]),a.insertBefore(v[0],a.childNodes[m]||null),v[0].nodeValue=i)),k=new i.constructor(i),k.nodes=v):k.nodes.intact=!0}return k}function g(a,b,c,d,e){for(var f in c){var g=c[f],h=d[f];if(f in d&&h===g)"value"===f&&"input"===b&&a.value!=g&&(a.value=g);else{d[f]=g;try{if("config"===f)continue;if(typeof g==J&&0==f.indexOf("on"))a[f]=k(g,a);else if("style"===f&&null!=g&&K.call(g)==G){for(var i in g)(null==h||h[i]!==g[i])&&(a.style[i]=g[i]);for(var i in h)i in g||(a.style[i]="")}else null!=e?"href"===f?a.setAttributeNS("http://www.w3.org/1999/xlink","href",g):"className"===f?a.setAttribute("class",g):a.setAttribute(f,g):f in a&&"list"!=f&&"style"!=f&&"form"!=f&&"type"!=f?a[f]!=g&&(a[f]=g):a.setAttribute(f,g)}catch(j){if(j.message.indexOf("Invalid argument")<0)throw j}}}return d}function h(a,b){for(var c=a.length-1;c>-1;c--)if(a[c]&&a[c].parentNode){try{a[c].parentNode.removeChild(a[c])}catch(d){}b=[].concat(b),b[c]&&i(b[c])}0!=a.length&&(a.length=0)}function i(a){if(a.configContext&&typeof a.configContext.onunload==J&&a.configContext.onunload(),a.children)if(K.call(a.children)==H)for(var b=0;bb?Q.push(a)-1:b}function m(a){var b=function(){return arguments.length&&(a=arguments[0]),a};return b.toJSON=function(){return a},b}function n(){for(var a=e.redraw.strategy(),b=0;b=200&&d.status<300?a.onload({type:"load",target:d}):a.onerror({type:"error",target:d}))},a.serialize==JSON.stringify&&a.data&&"GET"!=a.method&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),a.deserialize==JSON.parse&&d.setRequestHeader("Accept","application/json, text/*"),typeof a.config==J){var e=a.config(d,a);null!=e&&(d=e)}var f="GET"!=a.method&&a.data?a.data:"";if(f&&K.call(f)!=I&&f.constructor!=b.FormData)throw"Request data should be either be a string or FormData. Check the `serialize` option in `m.request`";return d.send(f),d}var g="mithril_callback_"+(new Date).getTime()+"_"+Math.round(1e16*Math.random()).toString(36),h=C.createElement("script");b[g]=function(d){C.body.removeChild(h),a.onload({type:"load",target:{responseText:d}}),b[g]=c},h.onerror=function(){return C.body.removeChild(h),a.onerror({type:"error",target:{status:500,responseText:JSON.stringify({error:"Error making jsonp request"})}}),b[g]=c,!1},h.onload=function(){return!1},h.src=a.url+(a.url.indexOf("?")>0?"&":"?")+(a.callbackKey?a.callbackKey:"callback")+"="+g+"&"+s(a.data||{}),C.body.appendChild(h)}function A(a,b,c){if("GET"==a.method&&"jsonp"!=a.dataType){var d=a.url.indexOf("?")<0?"?":"&",e=s(b);a.url=a.url+(e?d+e:"")}else a.data=c(b);return a}function B(a,b){var c=a.match(/:[a-z]\w+/gi);if(c&&b)for(var d=0;dc&&(c=T.length);var d=!1;if(V[c]&&typeof V[c].onunload==J){var f={preventDefault:function(){d=!0}};V[c].onunload(f)}if(!d){e.redraw.strategy("all"),e.startComputation(),T[c]=a;var g=S=b,h=new b.controller;return g==S&&(V[c]=h,U[c]=b),e.endComputation(),V[c]}},e.redraw=function(a){W&&a!==!0?(new Date-X>Z||E==b.requestAnimationFrame)&&(W>0&&F(W),W=E(n,Z)):(n(),W=E(function(){W=null},Z))},e.redraw.strategy=e.prop();var $=0;e.startComputation=function(){$++},e.endComputation=function(){$=Math.max($-1,0),0==$&&e.redraw()},e.withAttr=function(a,b){return function(c){c=c||event;var d=c.currentTarget||this;b(a in d?d[a]:d.getAttribute(a))}};var _,ab,bb={pathname:"",hash:"#",search:"?"},cb=function(){};return e.route=function(){if(0===arguments.length)return ab;if(3===arguments.length&&K.call(arguments[1])==I){var a=arguments[0],c=arguments[1],d=arguments[2];cb=function(b){var f=ab=o(b);p(a,d,f)||e.route(c,!0)};var f="hash"==e.route.mode?"onhashchange":"onpopstate";b[f]=function(){ab!=o(D[e.route.mode])&&cb(D[e.route.mode])},Y=r,b[f]()}else if(arguments[0].addEventListener){{var g=arguments[0];arguments[1],arguments[2]}g.href=("pathname"!==e.route.mode?D.pathname:"")+bb[e.route.mode]+this.attrs.href,g.removeEventListener("click",q),g.addEventListener("click",q)}else if(K.call(arguments[0])==I){ab=arguments[0];var h=arguments[1]||{},i=ab.indexOf("?"),j=i>-1?t(ab.slice(i+1)):{};for(var k in h)j[k]=h[k];var l=s(j),m=i>-1?ab.slice(0,i):ab;l&&(ab=m+(-1===m.indexOf("?")?"?":"&")+l);var n=(3==arguments.length?arguments[2]:arguments[1])===!0;b.history.pushState?(Y=function(){b.history[n?"replaceState":"pushState"](null,C.title,bb[e.route.mode]+ab),r()},cb(bb[e.route.mode]+ab)):D[e.route.mode]=ab}},e.route.param=function(a){if(!_)throw new Error("You must call m.route(element, defaultRoute, routes) before calling m.route.param()");return _[a]},e.route.mode="search",e.deferred=function(){var a=new x;return a.promise=w(a.promise),a},e.deferred.onerror=function(a){if("[object Error]"==K.call(a)&&!a.constructor.toString().match(/ Error/))throw a},e.sync=function(a){function b(a,b){return function(e){return g[a]=e,b||(c="reject"),0==--f&&(d.promise(g),d[c](g)),e}}var c="resolve",d=e.deferred(),f=a.length,g=new Array(f);if(a.length>0)for(var h=0;h Date: Thu, 11 Dec 2014 02:47:05 +0100 Subject: [PATCH 11/80] Queue rendered with Mithril.js Introduction of Mithril framework in the RuneUI and first implementation of the queue rendering --- app/templates/footer.php | 1 + app/templates/playback.php | 8 ++- assets/js/runeui.js | 111 ++++++++++++++++++++++++++++++++++++- assets/js/runeui.min.js | 4 +- 4 files changed, 117 insertions(+), 7 deletions(-) diff --git a/app/templates/footer.php b/app/templates/footer.php index 612cead5..c7d09f6a 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -21,6 +21,7 @@ + section == 'debug'): ?> diff --git a/app/templates/playback.php b/app/templates/playback.php index 01422b8b..100928dd 100755 --- a/app/templates/playback.php +++ b/app/templates/playback.php @@ -92,9 +92,11 @@ 2143 entries

    -
      - -
    +
    +
      + +
    +
    diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 49506a96..51f49b28 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -703,7 +703,64 @@ function getPlaylistPlain(data){ $('#pl-count').removeClass('hide').html(pos + ((pos !== 1) ? ' entries' : ' entry')); } +// format the queue data response in JSON +function parseQueue(data){ + var current = parseInt(GUI.json.song) + 1; + var state = GUI.json.state; + var i, line, lines = data.split('\n'); + var pos = 1; + var songs = []; // array che conterrà tutte le songs + var song = {}; // modello base + for (i = 0; (line = lines[i]); i += 1) { + var infos = line.split(': '); + if ( 'file' === infos[0] ) { + song.file = infos[1]; + song.fileExt = infos[1].split('.').pop(); + } + else if ( 'Name' === infos[0] ) { + song.name = infos[1]; + } + else if ( 'Last-Modified' === infos[0] ) { + song.lastModified = infos[1]; + } + else if ( 'Time' === infos[0] ) { + song.time = parseInt(infos[1]); + song.timeFormatted = timeConvert(song.time); + } + else if ( 'Artist' === infos[0] ) { + song.artist = infos[1]; + } + else if ( 'Title' === infos[0] ) { + song.title = infos[1]; + } + else if ( 'Album' === infos[0] ) { + song.album = infos[1]; + //song.albumArtist = infos[1]; + } + else if ( 'Track' === infos[0] ) { + song.track = infos[1]; + } + else if ( 'Date' === infos[0] ) { + song.date = infos[1]; + } + else if ( 'Genre' === infos[0] ) { + song.genre = infos[1]; + } + else if ( 'Id' === infos[0] ) { + song.id = infos[1]; + song.pos = pos++; + if (song.name) { + song.webradio = true; // marchiamo che è una web radio + } + songs.push(song); + song = {}; + } + } + return songs; +} + // refresh the queue (TODO: improve in PushStream mode) +var queueTracks = ''; function getPlaylistCmd(){ loadingSpinner('pl'); $.ajax({ @@ -713,8 +770,9 @@ function getPlaylistCmd(){ $('.playlist').addClass('hide'); $('#playlist-entries').removeClass('hide'); // console.time('getPlaylistPlain timer'); - getPlaylistPlain(data); + queueTracks = parseQueue(data); // console.timeEnd('getPlaylistPlain timer'); + m.redraw(); var current = parseInt(GUI.json.song); if ($('#panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { @@ -2626,4 +2684,53 @@ if ($('#section-index').length) { }); -} \ No newline at end of file +} + + + +// QUEUE RENDERING VIA MITHRIL +// ---------------------------------------------------------------------------------------------------- + +var queueEntryHeight = 49; +var pageY = 0, pageHeight = 0; +window.onscroll = function(e) { + pageY = Math.max(e.pageY || window.pageYOffset, 0); + pageHeight = window.innerHeight; + m.redraw(); +}; +$(window).trigger('scroll'); + +m.module(document.getElementById('playlist-entries-container'), { + controller: function() {}, + view: function() { + var begin = pageY / queueEntryHeight || 0; + var end = begin + (pageHeight / queueEntryHeight || 0 + 2); + var offset = pageY % queueEntryHeight; + return m('div', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ + m('ul#playlist-entries.playlist', {style: 'position:relative;top:' + pageY + 'px'}, [ + (queueTracks)?queueTracks.slice(begin, end).map(function(song) { + var icon = null; + var bottom = null; + + if (song.webradio) { + icon = m('i.fa.fa-microphone'); + bottom = 'URL: ' + song.file; + } else if (song.artist) { + bottom = song.artist + ' - ' + song.album; + } else { + bottom = 'path: ' + song.filename.split('/').pop(); + } + + return m('li', {id: 'pl-' + song.id}, [ + m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'), + m('span.sn', [ + song.title, + m('span', song.timeFormatted) + ]), + m('span.bl', bottom) + ]); + }):null + ]) + ]); + } +}); \ No newline at end of file diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index 3818ed3c..8f57359a 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ -function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",$("#playlist-entries").find("li").eq(b).addClass("active")),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="
    ",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image","url(/coverart/?v="+h+")")}else $("#cover-art").css("background-image","url(assets/img/cover-radio.jpg");GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){if(a.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(a);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;b
    back')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}}); \ No newline at end of file +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",$("#playlist-entries").find("li").eq(b).addClass("active")),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image","url(/coverart/?v="+h+")")}else $("#cover-art").css("background-image","url(assets/img/cover-radio.jpg");GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){if(a.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),m.redraw();var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=pageY/queueEntryHeight||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(a){var b=null,c=null;return a.webradio?(b=m("i.fa.fa-microphone"),c="URL: "+a.file):c=a.artist?a.artist+" - "+a.album:"path: "+a.filename.split("/").pop(),m("li",{id:"pl-"+a.id},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",c)])}):null])])}}); \ No newline at end of file From 51f747e257f3780ce7ff43b53344a4f1bafb03c9 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Fri, 12 Dec 2014 18:30:23 +0100 Subject: [PATCH 12/80] Retrieve track position in the queue --- assets/js/runeui.js | 19 +++++++++---------- assets/js/runeui.min.js | 4 ++-- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 51f49b28..6be1c3c7 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -236,7 +236,7 @@ function customScroll(list, destination, speed) { scrollcalc = parseInt((destination + 2)*entryheight - centerheight); scrolloffset = Math.abs(scrollcalc - scrolltop); scrolloffset = (scrollcalc > scrolltop ? '+':'-') + '=' + scrolloffset + 'px'; - $('#playlist-entries').find('li').eq(destination).addClass('active'); + $('[data-queuepos="' + destination + '"]').addClass('active'); } // debug // console.log('-------------------------------------------'); @@ -750,7 +750,7 @@ function parseQueue(data){ song.id = infos[1]; song.pos = pos++; if (song.name) { - song.webradio = true; // marchiamo che è una web radio + song.webradio = true; // mark it as webradio } songs.push(song); song = {}; @@ -1830,7 +1830,7 @@ if ($('#section-index').length) { sendCmd(cmd); } else { // play queue entry - var pos = $('li', '#playlist-entries').index(this); + var pos = $(this).data('queuepos'); cmd = 'play ' + pos; sendCmd(cmd); $('li.active', '#playlist-entries').removeClass('active'); @@ -2703,15 +2703,15 @@ $(window).trigger('scroll'); m.module(document.getElementById('playlist-entries-container'), { controller: function() {}, view: function() { - var begin = pageY / queueEntryHeight || 0; + var begin = Math.ceil(pageY / queueEntryHeight) || 0; var end = begin + (pageHeight / queueEntryHeight || 0 + 2); var offset = pageY % queueEntryHeight; - return m('div', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ + m('#pl-count', queueTracks.length); // [TODO] check this + return m('div', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ m('ul#playlist-entries.playlist', {style: 'position:relative;top:' + pageY + 'px'}, [ - (queueTracks)?queueTracks.slice(begin, end).map(function(song) { + (queueTracks)?queueTracks.slice(begin, end).map(function(song, idx) { var icon = null; var bottom = null; - if (song.webradio) { icon = m('i.fa.fa-microphone'); bottom = 'URL: ' + song.file; @@ -2720,8 +2720,7 @@ m.module(document.getElementById('playlist-entries-container'), { } else { bottom = 'path: ' + song.filename.split('/').pop(); } - - return m('li', {id: 'pl-' + song.id}, [ + return m('li', {id: 'pl-' + song.id, 'data-queuepos': begin + idx}, [ m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'), m('span.sn', [ song.title, @@ -2730,7 +2729,7 @@ m.module(document.getElementById('playlist-entries-container'), { m('span.bl', bottom) ]); }):null - ]) + ]), ]); } }); \ No newline at end of file diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index 8f57359a..ef11822a 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ -function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",$("#playlist-entries").find("li").eq(b).addClass("active")),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image","url(/coverart/?v="+h+")")}else $("#cover-art").css("background-image","url(assets/img/cover-radio.jpg");GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){if(a.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),m.redraw();var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=pageY/queueEntryHeight||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(a){var b=null,c=null;return a.webradio?(b=m("i.fa.fa-microphone"),c="URL: "+a.file):c=a.artist?a.artist+" - "+a.album:"path: "+a.filename.split("/").pop(),m("li",{id:"pl-"+a.id},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",c)])}):null])])}}); \ No newline at end of file +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",$('[data-queuepos="'+b+'"]').addClass("active")),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image","url(/coverart/?v="+h+")")}else $("#cover-art").css("background-image","url(assets/img/cover-radio.jpg");GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){if(a.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),m.redraw();var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=Math.ceil(pageY/queueEntryHeight)||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("#pl-count",queueTracks.length),m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(b,c){var d=null,e=null;return b.webradio?(d=m("i.fa.fa-microphone"),e="URL: "+b.file):e=b.artist?b.artist+" - "+b.album:"path: "+b.filename.split("/").pop(),m("li",{id:"pl-"+b.id,"data-queuepos":a+c},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[b.title,m("span",b.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file From b323570ab72d75fd0cdddbecdba78635017e4680 Mon Sep 17 00:00:00 2001 From: kdubious Date: Fri, 12 Dec 2014 15:46:28 -0500 Subject: [PATCH 13/80] Cleanup --- app/templates/settings.php | 3 +++ command/info.php | 1 + 2 files changed, 4 insertions(+) diff --git a/app/templates/settings.php b/app/templates/settings.php index 308ac5a5..7727bfa4 100755 --- a/app/templates/settings.php +++ b/app/templates/settings.php @@ -21,6 +21,9 @@
    + Set your reference time sync server (NTP server).
    diff --git a/command/info.php b/command/info.php index 61ace196..968c8df7 100755 --- a/command/info.php +++ b/command/info.php @@ -1,2 +1,3 @@ \ No newline at end of file From df5208cc48930918c22622f9cab26a4f1a9b060e Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sat, 13 Dec 2014 00:37:09 +0100 Subject: [PATCH 14/80] Current track highlighted in queue --- assets/js/runeui.js | 56 +++++++++++++++++++++++++---------------- assets/js/runeui.min.js | 4 +-- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 6be1c3c7..bd684f25 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -46,6 +46,7 @@ var GUI = { currentknob: null, currentpath: '', currentsong: null, + currentqueuepos: 0, json: 0, libraryhome: '', mode: 'websocket', @@ -59,6 +60,7 @@ var GUI = { visibility: 'visible', volume: null }; +var queueTracks = []; @@ -216,7 +218,16 @@ function volumeStepSet() { setvol(GUI.stepVolumeDelta); // console.log('set volume to = ', GUI.stepVolumeDelta); } - + +// highlight the current track in the queue +function setQueuePos() { + if (queueTracks.length !== 0 && GUI.currentqueuepos !== parseInt(GUI.json.song)) { + queueTracks[GUI.currentqueuepos].current = false; + GUI.currentqueuepos = parseInt(GUI.json.song); + queueTracks[GUI.currentqueuepos].current = true; + } +} + // custom scrolling function customScroll(list, destination, speed) { // console.log('list = ' + list + ', destination = ' + destination + ', speed = ' + speed); @@ -232,11 +243,16 @@ function customScroll(list, destination, speed) { scrollcalc = parseInt((destination)*entryheight - centerheight); scrolloffset = scrollcalc; } else if (list === 'pl') { - //var scrolloffset = parseInt((destination + 2)*entryheight - centerheight); - scrollcalc = parseInt((destination + 2)*entryheight - centerheight); - scrolloffset = Math.abs(scrollcalc - scrolltop); - scrolloffset = (scrollcalc > scrolltop ? '+':'-') + '=' + scrolloffset + 'px'; - $('[data-queuepos="' + destination + '"]').addClass('active'); + if (queueTracks.length !== 0) { + //var scrolloffset = parseInt((destination + 2)*entryheight - centerheight); + scrollcalc = parseInt((destination + 2)*entryheight - centerheight); + scrolloffset = Math.abs(scrollcalc - scrolltop); + scrolloffset = (scrollcalc > scrolltop ? '+':'-') + '=' + scrolloffset + 'px'; + // $('[data-queuepos="' + destination + '"]').addClass('active'); + // queueTracks[destination].current = true; + console.log(queueTracks[destination].current); + console.log(GUI.currentqueuepos); + } } // debug // console.log('-------------------------------------------'); @@ -587,6 +603,8 @@ function updateGUI() { // check song update // console.log('A = ', GUI.json.currentsong); console.log('B = ', GUI.currentsong); if (GUI.currentsong !== GUI.json.currentsong) { + setQueuePos(); + console.log('607 currentqueuepos = ', GUI.currentqueuepos); countdownRestart(0); if ($('#panel-dx').hasClass('active')) { var current = parseInt(GUI.json.song); @@ -631,9 +649,9 @@ function updateGUI() { if (GUI.currentalbum !== currentalbumstring) { if (radioname === null || radioname === undefined || radioname === '') { var covercachenum = Math.floor(Math.random()*1001); - $('#cover-art').css('background-image','url(/coverart/?v=' + covercachenum + ')'); + $('#cover-art').css('background-image','url("/coverart/?v=' + covercachenum + '")'); } else { - $('#cover-art').css('background-image','url(assets/img/cover-radio.jpg'); + $('#cover-art').css('background-image','url("assets/img/cover-radio.jpg")'); } } GUI.currentalbum = currentalbumstring; @@ -760,24 +778,23 @@ function parseQueue(data){ } // refresh the queue (TODO: improve in PushStream mode) -var queueTracks = ''; function getPlaylistCmd(){ loadingSpinner('pl'); $.ajax({ url: '/db/?cmd=playlist', success: function(data){ - if ( data.length > 4) { + if (data.length > 4) { $('.playlist').addClass('hide'); $('#playlist-entries').removeClass('hide'); // console.time('getPlaylistPlain timer'); queueTracks = parseQueue(data); // console.timeEnd('getPlaylistPlain timer'); - m.redraw(); - - var current = parseInt(GUI.json.song); - if ($('#panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { - customScroll('pl', current, 200); // highlight current song in playlist + setQueuePos(); + // console.log('793 currentqueuepos = ', GUI.currentqueuepos); + if ($('#open-panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { + customScroll('pl', GUI.currentqueuepos, 500); // [TODO] remove this when we find a way to highlight the current track at first draw } + m.redraw(); } else { $('.playlist').addClass('hide'); $('#playlist-warning').removeClass('hide'); @@ -1707,9 +1724,6 @@ if ($('#section-index').length) { libraryChannel(); // startChannel(queueChannel()); - // first GUI update - // updateGUI(); - // PNotify init options PNotify.prototype.options.styling = 'fontawesome'; PNotify.prototype.options.stack.dir1 = 'up'; @@ -1840,6 +1854,7 @@ if ($('#section-index').length) { // on ready playlist tab $('a', '#open-panel-dx').click(function(){ + // check if the Queue tab is visible if ($('#open-panel-dx').hasClass('active')) { var current = parseInt(GUI.json.song); customScroll('pl', current, 500); @@ -2416,9 +2431,6 @@ if ($('#section-index').length) { // open UI rendering channel; playbackChannel(); - // first GUI update - // updateGUI(); - // PNotify init options PNotify.prototype.options.styling = 'fontawesome'; PNotify.prototype.options.stack.dir1 = 'up'; @@ -2720,7 +2732,7 @@ m.module(document.getElementById('playlist-entries-container'), { } else { bottom = 'path: ' + song.filename.split('/').pop(); } - return m('li', {id: 'pl-' + song.id, 'data-queuepos': begin + idx}, [ + return m('li', {id: 'pl-' + song.id, 'data-queuepos': begin + idx, 'class': song.current ? 'active' : ''}, [ m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'), m('span.sn', [ song.title, diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index ef11822a..5dfcf40a 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ -function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",$('[data-queuepos="'+b+'"]').addClass("active")),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image","url(/coverart/?v="+h+")")}else $("#cover-art").css("background-image","url(assets/img/cover-radio.jpg");GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){if(a.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),m.redraw();var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=Math.ceil(pageY/queueEntryHeight)||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("#pl-count",queueTracks.length),m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(b,c){var d=null,e=null;return b.webradio?(d=m("i.fa.fa-microphone"),e="URL: "+b.file):e=b.artist?b.artist+" - "+b.album:"path: "+b.filename.split("/").pop(),m("li",{id:"pl-"+b.id,"data-queuepos":a+c},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[b.title,m("span",b.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&0!==queueTracks.length&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",console.log(queueTracks[b].current),console.log(GUI.currentqueuepos)),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),console.log("607 currentqueuepos = ",GUI.currentqueuepos),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close"); +transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=Math.ceil(pageY/queueEntryHeight)||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("#pl-count",queueTracks.length),m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(b,c){var d=null,e=null;return b.webradio?(d=m("i.fa.fa-microphone"),e="URL: "+b.file):e=b.artist?b.artist+" - "+b.album:"path: "+b.filename.split("/").pop(),m("li",{id:"pl-"+b.id,"data-queuepos":a+c,"class":b.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[b.title,m("span",b.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file From fa479a95a6b82b7d6ff42e6681fede58a6deffb0 Mon Sep 17 00:00:00 2001 From: kdubious Date: Sat, 13 Dec 2014 00:21:58 -0500 Subject: [PATCH 15/80] Mithril Implementation --- app/templates/footer.php | 3 +- app/templates/playback.php | 111 +--- assets/css/runeui.css | 2 +- assets/js/runeui.js | 1064 +++++++++++++++---------------- assets/js/vendor/mithril.min.js | 4 +- 5 files changed, 521 insertions(+), 663 deletions(-) diff --git a/app/templates/footer.php b/app/templates/footer.php index c7d09f6a..b705d627 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -45,4 +45,5 @@ - \ No newline at end of file + + \ No newline at end of file diff --git a/app/templates/playback.php b/app/templates/playback.php index ff124a49..0ae52849 100755 --- a/app/templates/playback.php +++ b/app/templates/playback.php @@ -66,10 +66,6 @@
    - - - - @@ -96,11 +92,9 @@ 2143 entries
    -
    -
      - -
    -
    + + +
    @@ -320,7 +314,7 @@
    -
    +
    -
    +
    -
    - -
    - -
    - +
    \ No newline at end of file diff --git a/assets/css/runeui.css b/assets/css/runeui.css index bc931693..c616bd94 100644 --- a/assets/css/runeui.css +++ b/assets/css/runeui.css @@ -7,4 +7,4 @@ * * Copyright 2013 bootstrap-select * Licensed under the MIT license - */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file + */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 82ce225b..cc1cb136 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -36,16 +36,17 @@ // ==================================================================================================== var GUI = { - DBentry: ['','',''], + DBentry: ['', '', ''], DBupdate: 0, activePlayer: '', browsemode: 'file', - currentDBpos: [0,0,0,0,0,0,0,0,0,0,0], - currentDBpath: ['','','','','','','','','','',''], + currentDBpos: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + currentDBpath: ['', '', '', '', '', '', '', '', '', '', ''], currentalbum: null, currentknob: null, currentpath: '', currentsong: null, + currentqueuepos: 0, json: 0, libraryhome: '', mode: 'websocket', @@ -59,6 +60,8 @@ var GUI = { visibility: 'visible', volume: null }; +var queueTracks = []; +var isCustomScroll = false; @@ -69,11 +72,11 @@ var GUI = { // send a MPD playback control command function sendCmd(inputcmd) { var request = new XMLHttpRequest(); - request.open('GET', '/command/?cmd='+inputcmd, true); - request.onreadystatechange = function() { - if (this.readyState === 4){ - // TODO: check this - if (this.status >= 200 && this.status < 400){ + request.open('GET', '/command/?cmd=' + inputcmd, true); + request.onreadystatechange = function () { + if (this.readyState === 4) { + // TODO: check this + if (this.status >= 200 && this.status < 400) { // Success! resp = this.responseText; } else { // Error @@ -85,37 +88,35 @@ function sendCmd(inputcmd) { } // check WebSocket support -function checkWebSocket(){ - if (window.WebSocket){ +function checkWebSocket() { + if (window.WebSocket) { // console.log('WebSockets supported'); return 'websocket'; - console.log('websocket'); } else { // console.log('WebSockets not supported'); - console.log('longpolling'); return 'longpolling'; } } // check HTML5 Workers support -function checkWorkers(){ +function checkWorkers() { if ((window.Worker && window.Blob) || (Modernizr.webworkers && Modernizr.blobconstructor)) { - console.log('WebWorkers supported'); + // console.log('WebWorkers supported'); return true; } else { - console.log('WebWorkers not supported'); + // console.log('WebWorkers not supported'); return false; } } // recover the path from input string function parsePath(str) { - var cutpos = str && str.length? str.lastIndexOf('/'):0; + var cutpos = str && str.length ? str.lastIndexOf('/') : 0; // console.log('parsePath.cutpos', cutpos) //-- verify this switch! (Orion) var songpath = ''; - if (cutpos && cutpos !== -1){ - songpath = str.slice(0,cutpos); + if (cutpos && cutpos !== -1) { + songpath = str.slice(0, cutpos); } return songpath; } @@ -126,8 +127,8 @@ function refreshTimer(startFrom, stopTo, state) { // console.log('state = ', state); var display = $('#countdown-display'); display.countdown('destroy'); - display.countdown({ since: ((state !== 'stop' || state !== undefined)? -(startFrom) : 0), compact: true, format: 'MS' }); - if (state !== 'play'){ + display.countdown({ since: ((state !== 'stop' || state !== undefined) ? -(startFrom) : 0), compact: true, format: 'MS' }); + if (state !== 'play') { // console.log('startFrom = ', startFrom); display.countdown('pause'); } @@ -136,14 +137,14 @@ function refreshTimer(startFrom, stopTo, state) { // update playback progress knob function refreshKnob() { window.clearInterval(GUI.currentKnob); - var initTime = parseInt(GUI.json.song_percent)*10; + var initTime = parseInt(GUI.json.song_percent) * 10; var delta = parseInt(GUI.json.time); - var step = parseInt(1000/delta); + var step = parseInt(1000 / delta); // console.log('initTime = ' + initTime + ', delta = ' + delta + ', step = ' + step); var time = $('#time'); time.val(initTime, false).trigger('update'); if (GUI.state === 'play') { - GUI.currentKnob = setInterval(function() { + GUI.currentKnob = setInterval(function () { // console.log('initTime = ', initTime); initTime = initTime + ((GUI.visibility !== 'visible') ? step : 1); time.val(initTime, false).trigger('update'); @@ -161,11 +162,11 @@ function timeConvert(seconds) { return mm + ':' + ss; } function timeConvert2(ss) { - var hr = Math.floor(ss/3600); - var mm = Math.floor((ss -(hr * 3600))/60); - ss = Math.floor(ss -(hr*3600) -(mm * 60)); + var hr = Math.floor(ss / 3600); + var mm = Math.floor((ss - (hr * 3600)) / 60); + ss = Math.floor(ss - (hr * 3600) - (mm * 60)); if (hr > 0) { - if (hr < 10){ + if (hr < 10) { hr = '0' + hr; } hr += ':'; @@ -180,7 +181,7 @@ function timeConvert2(ss) { // reset countdown function countdownRestart(startFrom) { var display = $('#countdown-display').countdown('destroy'); - display.countdown({since: -(startFrom), compact: true, format: 'MS'}); + display.countdown({ since: -(startFrom), compact: true, format: 'MS' }); } // set volume with knob @@ -196,7 +197,7 @@ function volumeStepCalc(direction) { var i = 0; var way = direction; GUI.volume = parseInt($('#volume').val()); - var volumeStep = function volumeStepCycle(way){ + var volumeStep = function volumeStepCycle(way) { i++; if (direction === 'up') { GUI.stepVolumeDelta = parseInt(GUI.volume) + i; @@ -208,8 +209,8 @@ function volumeStepCalc(direction) { }; volumeStep(); // console.log('GUI.volume = ', GUI.volume); - - GUI.stepVolumeInt = window.setInterval(function() { + + GUI.stepVolumeInt = window.setInterval(function () { volumeStep(); }, 200); } @@ -218,27 +219,38 @@ function volumeStepSet() { setvol(GUI.stepVolumeDelta); // console.log('set volume to = ', GUI.stepVolumeDelta); } - + +// highlight the current track in the queue +function setQueuePos() { + if (queueTracks.length !== 0 && GUI.currentqueuepos !== parseInt(GUI.json.song)) { + queueTracks[GUI.currentqueuepos].current = false; + GUI.currentqueuepos = parseInt(GUI.json.song); + queueTracks[GUI.currentqueuepos].current = true; + } +} + // custom scrolling function customScroll(list, destination, speed) { + isCustomScroll = true; // console.log('list = ' + list + ', destination = ' + destination + ', speed = ' + speed); - if (typeof(speed) === 'undefined') { + if (typeof (speed) === 'undefined') { speed = 500; } var entryheight = 49; - var centerheight = parseInt($(window).height()/2); + var centerheight = parseInt($(window).height() / 2); var scrolltop = $(window).scrollTop(); var scrollcalc = 0; var scrolloffset = 0; if (list === 'db') { - scrollcalc = parseInt((destination)*entryheight - centerheight); + scrollcalc = parseInt((destination) * entryheight - centerheight); scrolloffset = scrollcalc; } else if (list === 'pl') { - //var scrolloffset = parseInt((destination + 2)*entryheight - centerheight); - scrollcalc = parseInt((destination + 2)*entryheight - centerheight); - scrolloffset = Math.abs(scrollcalc - scrolltop); - scrolloffset = (scrollcalc > scrolltop ? '+':'-') + '=' + scrolloffset + 'px'; - $('[data-queuepos="' + destination + '"]').addClass('active'); + if (queueTracks.length !== 0) { + //var scrolloffset = parseInt((destination + 2)*entryheight - centerheight); + scrollcalc = parseInt((destination + 2) * entryheight - centerheight); + scrolloffset = Math.abs(scrollcalc - scrolltop); + scrolloffset = (scrollcalc > scrolltop ? '+' : '-') + '=' + scrolloffset + 'px'; + } } // debug // console.log('-------------------------------------------'); @@ -246,7 +258,8 @@ function customScroll(list, destination, speed) { // console.log('scrolltop = ', scrolltop); // console.log('scrollcalc = ', scrollcalc); // console.log('scrolloffset = ', scrolloffset); - $.scrollTo( (scrollcalc >0? scrolloffset:0), speed); + $.scrollTo((scrollcalc > 0 ? scrolloffset : 0), speed); + isCustomScroll = false; } // [!] scrolling debug purpose only @@ -295,8 +308,8 @@ function customNotify(notify) { buttons: [{ text: notify.btntext, addClass: 'btn-default btn-block uppercase', - click: function() { - $.post('/settings/', { 'syscmd' : 'reboot' }); + click: function () { + $.post('/settings/', { 'syscmd': 'reboot' }); toggleLoader(); } }, @@ -387,21 +400,21 @@ function setPlaybackSource() { $('#playsource-' + source).removeClass('inactive'); // update volume knob and control buttons if (activePlayer === 'Spotify' || activePlayer === 'Airplay') { - $('#volume').trigger('configure', {'readOnly': true, 'fgColor': '#1A242F'}).css({'color': '#1A242F'}); + $('#volume').trigger('configure', { 'readOnly': true, 'fgColor': '#1A242F' }).css({ 'color': '#1A242F' }); $('.volume button').prop('disabled', true); $('#single').addClass('disabled'); } else { - $('#volume').trigger('configure', {'readOnly': false, 'fgColor': '#0095D8'}).css({'color': '#0095D8'}); + $('#volume').trigger('configure', { 'readOnly': false, 'fgColor': '#0095D8' }).css({ 'color': '#0095D8' }); $('.volume button').prop('disabled', false); $('#single').removeClass('disabled'); } // style the queue - $('#playlist-entries').removeClass(function(index, css) { - return (css.match (/(^|\s)playlist-\S+/g) || []).join(' '); + $('#playlist-entries').removeClass(function (index, css) { + return (css.match(/(^|\s)playlist-\S+/g) || []).join(' '); }).addClass('playlist-' + source); // toggle queue buttons - $('#pl-manage').removeClass(function(index, css) { - return (css.match (/(^|\s)pl-manage-\S+/g) || []).join(' '); + $('#pl-manage').removeClass(function (index, css) { + return (css.match(/(^|\s)pl-manage-\S+/g) || []).join(' '); }).addClass('pl-manage-' + source); } @@ -409,34 +422,12 @@ function chkKey(key) { return (key !== undefined && key !== ''); } -function setupAlphabetNav() { - // - // look for the named Anchor tags to see which navigation letters to disable - setupAlphabetNav(); - $('.alphabetTag').each(function (index) { - console.log("alphabetTag index:" + index + " name: " + $(this).attr('name')); - var button = $("a[data-alphabet='" + $(this).attr('name') + "']")[0]; - if (button) { - $(button).removeClass('disabled') - } - }) - // -} - - // render the Library home screen function renderLibraryHome() { loadingSpinner('db'); $('#database-entries').addClass('hide'); $('#db-level-up').addClass('hide'); $('#db-homeSetup').removeClass('hide').removeClass('btn-primary').addClass('btn-default'); - - // - // by default, the Library panel does not need the Alphabet nav - $('#overlay-alphabet-open').addClass('hide'); - // - - $('#home-blocks').removeClass('hide'); var obj = GUI.libraryhome, i = 0, @@ -450,14 +441,14 @@ function renderLibraryHome() { // Set active player setPlaybackSource(); if (notMPD) { - toggleMPD = ' inactive'; + toggleMPD = ' inactive'; } // bookmarks blocks - for (i = 0; (bookmark = obj.bookmarks[i]); i += 1) { + for (i = 0; (bookmark = obj.bookmarks[i]) ; i += 1) { content += divOpen + '

    ' + bookmark.name + '

    bookmark
    ' + divClose; } if (chkKey(obj.networkMounts)) { - // network mounts block + // network mounts block if (obj.networkMounts === 0) { if (notMPD) { content += divOpen + '

    Network mounts (0)

    network attached storages
    ' + divClose; @@ -469,7 +460,7 @@ function renderLibraryHome() { } } if (chkKey(obj.localStorages)) { - // local storages block + // local storages block if (obj.localStorages === 0) { content += ''; } else { @@ -477,7 +468,7 @@ function renderLibraryHome() { } } if (chkKey(obj.USBMounts)) { - // USB mounts block + // USB mounts block if (obj.USBMounts === 0) { if (notMPD) { content += divOpen + '

    USB storage (0)

    no USB storage plugged
    ' + divClose; @@ -489,7 +480,7 @@ function renderLibraryHome() { } } if (chkKey(obj.webradio)) { - // webradios block + // webradios block if (obj.webradio === 0) { if (notMPD) { content += divOpen + '

    My Webradios (0)

    webradio local playlists
    ' + divClose; @@ -501,7 +492,7 @@ function renderLibraryHome() { } } if (chkKey(obj.Spotify)) { - // Spotify block + // Spotify block if (obj.Spotify === '0') { content += divOpen + '

    Spotify

    click to configure
    ' + divClose; } else { @@ -513,7 +504,7 @@ function renderLibraryHome() { } } if (chkKey(obj.Dirble)) { - // Dirble block + // Dirble block content += divOpen + '

    Dirble (' + obj.Dirble + ')

    radio stations open directory
    ' + divClose; } // Jamendo (static) @@ -550,9 +541,9 @@ function refreshState() { $('#countdown-display').countdown('destroy'); } // if (GUI.stream === 'radio') { - // $('#elapsed').html('∞'); + // $('#elapsed').html('∞'); // } else { - // $('#elapsed').html('00:00'); + // $('#elapsed').html('00:00'); // } if (GUI.stream === 'radio') { $('#total').html(''); @@ -569,9 +560,9 @@ function refreshState() { if (GUI.stream === 'radio') { $('#total').html(''); } else { - $('#total').html((GUI.json.time !== undefined)? timeConvert(GUI.json.time) : '00:00'); + $('#total').html((GUI.json.time !== undefined) ? timeConvert(GUI.json.time) : '00:00'); } - var fileinfo = (GUI.json.audio_channels && GUI.json.audio_sample_depth && GUI.json.audio_sample_rate) ? (GUI.json.audio_channels + ', ' + GUI.json.audio_sample_depth + ' bit, ' + GUI.json.audio_sample_rate +' kHz, '+GUI.json.bitrate+' kbps') : ' '; + var fileinfo = (GUI.json.audio_channels && GUI.json.audio_sample_depth && GUI.json.audio_sample_rate) ? (GUI.json.audio_channels + ', ' + GUI.json.audio_sample_depth + ' bit, ' + GUI.json.audio_sample_rate + ' kHz, ' + GUI.json.bitrate + ' kbps') : ' '; $('#format-bitrate').html(fileinfo); $('li', '#playlist-entries').removeClass('active'); var current = parseInt(GUI.json.song); @@ -611,6 +602,7 @@ function updateGUI() { // check song update // console.log('A = ', GUI.json.currentsong); console.log('B = ', GUI.currentsong); if (GUI.currentsong !== GUI.json.currentsong) { + setQueuePos(); countdownRestart(0); if ($('#panel-dx').hasClass('active')) { var current = parseInt(GUI.json.song); @@ -649,15 +641,15 @@ function updateGUI() { } else { $('#single').removeClass('btn-primary'); } - + GUI.currentsong = currentsong; var currentalbumstring = currentartist + ' - ' + currentalbum; if (GUI.currentalbum !== currentalbumstring) { if (radioname === null || radioname === undefined || radioname === '') { - var covercachenum = Math.floor(Math.random()*1001); - $('#cover-art').css('background-image','url(/coverart/?v=' + covercachenum + ')'); + var covercachenum = Math.floor(Math.random() * 1001); + $('#cover-art').css('background-image', 'url("/coverart/?v=' + covercachenum + '")'); } else { - $('#cover-art').css('background-image','url(assets/img/cover-radio.jpg'); + $('#cover-art').css('background-image', 'url("assets/img/cover-radio.jpg")'); } } GUI.currentalbum = currentalbumstring; @@ -665,32 +657,32 @@ function updateGUI() { } // render the playing queue from the data response -function getPlaylistPlain(data){ +function getPlaylistPlain(data) { var current = parseInt(GUI.json.song) + 1; var state = GUI.json.state; - var content = '', time = '', artist = '', album = '', title = '', name='', str = '', filename = '', path = '', id = 0, songid = '', bottomline = '', totaltime = '', pos = 0; - var i, line, lines = data.split('\n'), infos=[]; - for (i = 0; (line = lines[i]); i += 1) { + var content = '', time = '', artist = '', album = '', title = '', name = '', str = '', filename = '', path = '', id = 0, songid = '', bottomline = '', totaltime = '', pos = 0; + var i, line, lines = data.split('\n'), infos = []; + for (i = 0; (line = lines[i]) ; i += 1) { infos = line.split(': '); - if ( 'Time' === infos[0] ) { + if ('Time' === infos[0]) { time = parseInt(infos[1]); } - else if ( 'Artist' === infos[0] ) { + else if ('Artist' === infos[0]) { artist = infos[1]; } - else if ( 'Title' === infos[0] ) { + else if ('Title' === infos[0]) { title = infos[1]; } - else if ( 'Name' === infos[0] ) { + else if ('Name' === infos[0]) { name = infos[1]; } - else if ( 'Album' === infos[0] ) { + else if ('Album' === infos[0]) { album = infos[1]; } - else if ( 'file' === infos[0] ) { + else if ('file' === infos[0]) { str = infos[1]; } - else if ( 'Id' === infos[0] ) { + else if ('Id' === infos[0]) { songid = infos[1]; if (title === '' || album === '') { path = parsePath(str); @@ -720,7 +712,7 @@ function getPlaylistPlain(data){ $('#playlist-entries').removeClass('hide'); //$('#playlist-entries').html(content); var pl_entries = document.getElementById('playlist-entries'); - if( pl_entries ){ pl_entries.innerHTML = content; } + if (pl_entries) { pl_entries.innerHTML = content; } $('#pl-filter-results').addClass('hide').html(''); $('#pl-filter').val(''); $('#pl-manage').removeClass('hide'); @@ -728,49 +720,49 @@ function getPlaylistPlain(data){ } // format the queue data response in JSON -function parseQueue(data){ +function parseQueue(data) { var current = parseInt(GUI.json.song) + 1; var state = GUI.json.state; var i, line, lines = data.split('\n'); var pos = 1; var songs = []; // array che conterrà tutte le songs var song = {}; // modello base - for (i = 0; (line = lines[i]); i += 1) { + for (i = 0; (line = lines[i]) ; i += 1) { var infos = line.split(': '); - if ( 'file' === infos[0] ) { + if ('file' === infos[0]) { song.file = infos[1]; song.fileExt = infos[1].split('.').pop(); } - else if ( 'Name' === infos[0] ) { + else if ('Name' === infos[0]) { song.name = infos[1]; } - else if ( 'Last-Modified' === infos[0] ) { + else if ('Last-Modified' === infos[0]) { song.lastModified = infos[1]; } - else if ( 'Time' === infos[0] ) { + else if ('Time' === infos[0]) { song.time = parseInt(infos[1]); song.timeFormatted = timeConvert(song.time); } - else if ( 'Artist' === infos[0] ) { + else if ('Artist' === infos[0]) { song.artist = infos[1]; } - else if ( 'Title' === infos[0] ) { + else if ('Title' === infos[0]) { song.title = infos[1]; } - else if ( 'Album' === infos[0] ) { + else if ('Album' === infos[0]) { song.album = infos[1]; //song.albumArtist = infos[1]; } - else if ( 'Track' === infos[0] ) { + else if ('Track' === infos[0]) { song.track = infos[1]; } - else if ( 'Date' === infos[0] ) { + else if ('Date' === infos[0]) { song.date = infos[1]; } - else if ( 'Genre' === infos[0] ) { + else if ('Genre' === infos[0]) { song.genre = infos[1]; } - else if ( 'Id' === infos[0] ) { + else if ('Id' === infos[0]) { song.id = infos[1]; song.pos = pos++; if (song.name) { @@ -784,24 +776,24 @@ function parseQueue(data){ } // refresh the queue (TODO: improve in PushStream mode) -var queueTracks = ''; -function getPlaylistCmd(){ +function getPlaylistCmd() { loadingSpinner('pl'); $.ajax({ url: '/db/?cmd=playlist', - success: function(data){ - if ( data.length > 4) { + success: function (data) { + if (data.length > 4) { $('.playlist').addClass('hide'); $('#playlist-entries').removeClass('hide'); // console.time('getPlaylistPlain timer'); queueTracks = parseQueue(data); + $('#playlist').height(queueTracks.length * 49); // console.timeEnd('getPlaylistPlain timer'); - m.redraw(); - - var current = parseInt(GUI.json.song); - if ($('#panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { - customScroll('pl', current, 200); // highlight current song in playlist + setQueuePos(); + // console.log('793 currentqueuepos = ', GUI.currentqueuepos); + if ($('#open-panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { + customScroll('pl', GUI.currentqueuepos, 500); // [TODO] remove this when we find a way to highlight the current track at first draw } + m.redraw(); } else { $('.playlist').addClass('hide'); $('#playlist-warning').removeClass('hide'); @@ -817,13 +809,13 @@ function getPlaylistCmd(){ function getPlaylist(text) { data = text[0]; // console.log(data); - if ( data.length > 4) { + if (data.length > 4) { $('.playlist').addClass('hide'); $('#playlist-entries').removeClass('hide'); // console.time('getPlaylistPlain timer'); getPlaylistPlain(data); // console.timeEnd('getPlaylistPlain timer'); - + var current = parseInt(GUI.json.song); if ($('#panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { customScroll('pl', current, 200); // center the scroll and highlight current song in playlist @@ -838,7 +830,7 @@ function getPlaylist(text) { } // launch the Playback UI refresh from the data response -function renderUI(text){ +function renderUI(text) { toggleLoader('close'); // update global GUI array GUI.json = text[0]; @@ -850,8 +842,8 @@ function renderUI(text){ // console.log('GUI.json.time = ', GUI.json.time); // console.log('GUI.json.state = ', GUI.json.state); if ($('#section-index').length) { - var elapsed = (GUI.json.elapsed !== '' && GUI.json.elapsed !== undefined)? GUI.json.elapsed : 0; - var time = (GUI.json.time !== '' && GUI.json.time !== undefined && GUI.json.time !== null)? GUI.json.time : 0; + var elapsed = (GUI.json.elapsed !== '' && GUI.json.elapsed !== undefined) ? GUI.json.elapsed : 0; + var time = (GUI.json.time !== '' && GUI.json.time !== undefined && GUI.json.time !== null) ? GUI.json.time : 0; refreshTimer(parseInt(elapsed), parseInt(time), GUI.json.state); if (GUI.stream !== 'radio') { refreshKnob(); @@ -868,12 +860,12 @@ function renderUI(text){ } // render saved playlists -function renderPlaylists(data){ +function renderPlaylists(data) { var content = '', playlistname = ''; - var i, line, lines=data.split('\n'), infos=[]; - for (i = 0; (line = lines[i]); i += 1 ) { + var i, line, lines = data.split('\n'), infos = []; + for (i = 0; (line = lines[i]) ; i += 1) { infos = line.split(': '); - if( 'playlist' === infos[0] ) { + if ('playlist' === infos[0]) { playlistname = infos[1]; content += '
  • ' + playlistname + '
  • '; playlistname = ''; @@ -891,11 +883,11 @@ function renderPlaylists(data){ } // get saved playlists -function getPlaylists(){ +function getPlaylists() { loadingSpinner('pl'); $.ajax({ url: '/command/?cmd=listplaylists', - success: function(data){ + success: function (data) { renderPlaylists(data); } }); @@ -910,20 +902,20 @@ function parseResponse(options) { inpath = options.inpath || '', querytype = options.querytype || '', content = ''; - + // DEBUG // console.log('parseResponse OPTIONS: inputArr = ' + inputArr + ', respType = ' + respType + ', i = ' + i + ', inpath = ' + inpath +', querytype = ' + querytype); // console.log(inputArr); - + switch (respType) { case 'playlist': // code placeholder - break; - + break; + case 'db': - // normal MPD browsing by file + // normal MPD browsing by file if (GUI.browsemode === 'file') { - // browse by file + // browse by file if (inpath === '' && inputArr.file !== undefined) { inpath = parsePath(inputArr.file); } @@ -935,17 +927,17 @@ function parseResponse(options) { // console.log('inputArr.Album: ', inputArr.Album); content = '
  • '; content += inputArr.Title + ' ' + timeConvert(inputArr.Time) + ''; content += ' '; - content += inputArr.Artist; + content += inputArr.Artist; content += ' - '; - content += inputArr.Album; + content += inputArr.Album; } else { if (inpath !== 'Webradio') { - // files with no tags + // files with no tags content += inputArr.file; content += '">'; content += inputArr.file.replace(inpath + '/', '') + ' ' + timeConvert(inputArr.Time) + ''; @@ -953,17 +945,17 @@ function parseResponse(options) { content += ' path: '; content += inpath; } else { - // webradio playlists + // webradio playlists content += inputArr.playlist; content += '">'; - content += '' + inputArr.playlist.replace(inpath + '/', '').replace('.' + inputArr.fileext , ''); + content += '' + inputArr.playlist.replace(inpath + '/', '').replace('.' + inputArr.fileext, ''); content += 'webradio'; } } content += '
  • '; } else if (inputArr.playlist !== undefined) { if (inputArr.fileext === 'cue') { - // CUE files + // CUE files content = '
  • '; @@ -974,7 +966,7 @@ function parseResponse(options) { content += '
  • '; } } else { - // folders + // folders content = '
  • '; } content += inputArr.directory.replace(inpath + '/', ''); - - // - // Add an Anchor tag to manage navigation to the first letter when the PHP returns it to us - if (inputArr.firstLetter) { - content += ''; - } - // - content += '
  • '; } } else if (GUI.browsemode === 'album' || GUI.browsemode === 'albumfilter') { - // browse by album + // browse by album if (inputArr.file !== undefined) { content = '
  • '; content += inputArr.Title + ' ' + timeConvert(inputArr.Time) + ''; content += ' '; - content += inputArr.Artist; + content += inputArr.Artist; content += ' - '; - content += inputArr.Album; + content += inputArr.Album; content += '
  • '; } else if (inputArr.album !== '') { content = '
  • '; @@ -1058,32 +1041,32 @@ function parseResponse(options) { content += inputArr.tracks; content += ')
  • '; } else if (querytype === 'tracks') { - // playlists + // playlists content = '
  • '; - content += inputArr.title + ' ' + timeConvert(inputArr.duration/1000) + ''; + content += inputArr.title + ' ' + timeConvert(inputArr.duration / 1000) + ''; content += ' '; - content += inputArr.artist; + content += inputArr.artist; content += ' - '; - content += inputArr.album; + content += inputArr.album; content += '
  • '; } - break; - + break; + case 'Dirble': - // Dirble plugin + // Dirble plugin if (querytype === '') { - // folders + // folders content = '
  • '; content += inputArr.name; content += '
  • '; } else if (querytype === 'stations') { - // stations + // stations content = '
  • '; @@ -1092,24 +1075,24 @@ function parseResponse(options) { content += inputArr.website; content += '
  • '; } - break; - + break; + case 'Jamendo': - // Jamendo plugin + // Jamendo plugin // if (querytype === 'radio') { - content = '
  • '; - content += inputArr.dispname + '
  • '; + content = '
  • '; + content += inputArr.dispname + '
  • '; // } - break; - + break; + } return content; } // end parseResponse() // populate the Library view lists with entries -function populateDB(options){ +function populateDB(options) { // DEFAULTS var data = options.data || '', path = options.path || '', @@ -1121,14 +1104,14 @@ function populateDB(options){ content = '', i = 0, row = []; - + // DEBUG // console.log('populateDB OPTIONS: data = ' + data + ', path = ' + path + ', uplevel = ' + uplevel + ', keyword = ' + keyword +', querytype = ' + querytype); if (plugin !== '') { - // plugins + // plugins if (plugin === 'Spotify') { - // Spotify plugin + // Spotify plugin $('#database-entries').removeClass('hide'); $('#db-level-up').removeClass('hide'); $('#home-blocks').addClass('hide'); @@ -1137,7 +1120,7 @@ function populateDB(options){ } document.getElementById('database-entries').innerHTML = ''; data = (querytype === 'tracks') ? data.tracks : data.playlists; - for (i = 0; (row = data[i]); i += 1) { + for (i = 0; (row = data[i]) ; i += 1) { content += parseResponse({ inputArr: row, respType: 'Spotify', @@ -1149,7 +1132,7 @@ function populateDB(options){ document.getElementById('database-entries').innerHTML = content; } if (plugin === 'Dirble') { - // Dirble plugin + // Dirble plugin $('#database-entries').removeClass('hide'); $('#db-level-up').removeClass('hide'); $('#home-blocks').addClass('hide'); @@ -1158,7 +1141,7 @@ function populateDB(options){ } document.getElementById('database-entries').innerHTML = ''; // console.log(data); - for (i = 0; (row = data[i]); i += 1) { + for (i = 0; (row = data[i]) ; i += 1) { content += parseResponse({ inputArr: row, respType: 'Dirble', @@ -1169,7 +1152,7 @@ function populateDB(options){ document.getElementById('database-entries').innerHTML = content; } if (plugin === 'Jamendo') { - // Jamendo plugin + // Jamendo plugin $('#database-entries').removeClass('hide'); $('#db-level-up').removeClass('hide'); $('#home-blocks').addClass('hide'); @@ -1177,7 +1160,7 @@ function populateDB(options){ GUI.currentpath = path; } document.getElementById('database-entries').innerHTML = ''; - for (i = 0; (row = data[i]); i += 1) { + for (i = 0; (row = data[i]) ; i += 1) { content += parseResponse({ inputArr: row, respType: 'Jamendo', @@ -1188,13 +1171,13 @@ function populateDB(options){ document.getElementById('database-entries').innerHTML = content; } } else { - // normal MPD browsing + // normal MPD browsing if (path === '' && keyword === '') { - // Library home + // Library home renderLibraryHome(); return; } else { - // browsing + // browsing $('#database-entries').removeClass('hide'); $('#db-level-up').removeClass('hide'); $('#home-blocks').addClass('hide'); @@ -1204,13 +1187,13 @@ function populateDB(options){ // console.log(' new GUI.currentpath = ', GUI.currentpath); document.getElementById('database-entries').innerHTML = ''; if (keyword !== '') { - // search results + // search results var results = (data.length) ? data.length : '0'; var s = (data.length === 1) ? '' : 's'; $('#db-level-up').addClass('hide'); $('#db-search-results').removeClass('hide').html('back'); } - for (i = 0; (row = data[i]); i += 1) { + for (i = 0; (row = data[i]) ; i += 1) { content += parseResponse({ inputArr: row, respType: 'db', @@ -1222,15 +1205,6 @@ function populateDB(options){ content += '
  • add newadd a webradio to your library
  • '; } document.getElementById('database-entries').innerHTML = content; - - - // - // look for the named Anchor tags to see which navigation letters to disable - setupAlphabetNav(); - // - - - // DEBUG // console.log('GUI.currentDBpos = ', GUI.currentDBpos); // console.log('level = ', GUI.currentDBpos[10]); @@ -1260,13 +1234,6 @@ function populateDB(options){ breadcrumb.html(path); } $('#db-homeSetup').addClass('hide'); - - // - // Show the Alphabet nav button - $('#overlay-alphabet-open').removeClass('hide'); - // - - if (uplevel) { var position = GUI.currentDBpos[GUI.currentDBpos[10]]; $('#db-' + position).addClass('active'); @@ -1278,7 +1245,7 @@ function populateDB(options){ } // end populateDB() // launch the right AJAX call for Library rendering -function getDB(options){ +function getDB(options) { // DEFAULTS var cmd = options.cmd || 'browse', path = options.path || '', @@ -1287,18 +1254,18 @@ function getDB(options){ plugin = options.plugin || '', querytype = options.querytype || '', args = options.args || ''; - + // DEBUG // console.log('OPTIONS: cmd = ' + cmd + ', path = ' + path + ', browsemode = ' + browsemode + ', uplevel = ' + uplevel + ', plugin = ' + plugin); - + loadingSpinner('db'); GUI.browsemode = browsemode; - + if (plugin !== '') { - // plugins + // plugins if (plugin === 'Spotify') { - // Spotify plugin - $.post('/db/?cmd=spotify', { 'plid': args }, function(data){ + // Spotify plugin + $.post('/db/?cmd=spotify', { 'plid': args }, function (data) { populateDB({ data: data, path: path, @@ -1310,8 +1277,8 @@ function getDB(options){ }, 'json'); } else if (plugin === 'Dirble') { - // Dirble plugin - $.post('/db/?cmd=dirble', { 'querytype': (querytype === '') ? 'categories' : querytype, 'args': args }, function(data){ + // Dirble plugin + $.post('/db/?cmd=dirble', { 'querytype': (querytype === '') ? 'categories' : querytype, 'args': args }, function (data) { populateDB({ data: data, path: path, @@ -1322,8 +1289,8 @@ function getDB(options){ }, 'json'); } else if (plugin === 'Jamendo') { - // Jamendo plugin - $.post('/db/?cmd=jamendo', { 'querytype': (querytype === '') ? 'radio' : querytype, 'args': args }, function(data){ + // Jamendo plugin + $.post('/db/?cmd=jamendo', { 'querytype': (querytype === '') ? 'radio' : querytype, 'args': args }, function (data) { populateDB({ data: data.results, path: path, @@ -1333,10 +1300,10 @@ function getDB(options){ }, 'json'); } } else { - // normal browsing + // normal browsing if (cmd === 'search') { var keyword = $('#db-search-keyword').val(); - $.post('/db/?querytype=' + GUI.browsemode + '&cmd=search', { 'query': keyword }, function(data) { + $.post('/db/?querytype=' + GUI.browsemode + '&cmd=search', { 'query': keyword }, function (data) { populateDB({ data: data, path: path, @@ -1345,7 +1312,7 @@ function getDB(options){ }); }, 'json'); } else if (cmd === 'browse') { - $.post('/db/?cmd=browse', { 'path': path, 'browsemode': GUI.browsemode }, function(data) { + $.post('/db/?cmd=browse', { 'path': path, 'browsemode': GUI.browsemode }, function (data) { populateDB({ data: data, path: path, @@ -1353,9 +1320,9 @@ function getDB(options){ }); }, 'json'); } else { - // EXAMPLE: cmd === 'update', 'addplay', 'addreplaceplay', 'update' + // EXAMPLE: cmd === 'update', 'addplay', 'addreplaceplay', 'update' loadingSpinner('db', 'hide'); - $.post('/db/?cmd='+cmd, { 'path': path, 'querytype': querytype }, function(path) { + $.post('/db/?cmd=' + cmd, { 'path': path, 'querytype': querytype }, function (path) { // console.log('add= ', path); }, 'json'); } @@ -1374,7 +1341,7 @@ function onreleaseKnob(value) { // console.log('seekto = ', seekto); $('#time').val(value); $('#countdown-display').countdown('destroy'); - $('#countdown-display').countdown({since: -seekto, compact: true, format: 'MS'}); + $('#countdown-display').countdown({ since: -seekto, compact: true, format: 'MS' }); } else { $('#time').val(0).trigger('change'); } @@ -1396,7 +1363,7 @@ function commandButton(el) { $('#total').html('00:00'); } } - // play/pause + // play/pause else if (dataCmd === 'play') { var state = GUI.state; //if (json.currentsong != null) { @@ -1413,7 +1380,7 @@ function commandButton(el) { } else if (state === 'stop') { cmd = 'play'; if ($('#section-index').length) { - $('#countdown-display').countdown({since: 0, compact: true, format: 'MS'}); + $('#countdown-display').countdown({ since: 0, compact: true, format: 'MS' }); } } //$(this).find('i').toggleClass('fa fa-play').toggleClass('fa fa-pause'); @@ -1422,24 +1389,24 @@ function commandButton(el) { // console.log('sendCmd(' + cmd + ');'); return; // } else { - // $(this).addClass('btn-primary'); - // $('#stop').removeClass('btn-primary'); - // $('#time').val(0, false).trigger('update'); - // $('#countdown-display').countdown({since: 0, compact: true, format: 'MS'}); + // $(this).addClass('btn-primary'); + // $('#stop').removeClass('btn-primary'); + // $('#time').val(0, false).trigger('update'); + // $('#countdown-display').countdown({since: 0, compact: true, format: 'MS'}); // } } - // previous/next + // previous/next else if (dataCmd === 'previous' || dataCmd === 'next') { if ($('#section-index').length) { $('#countdown-display').countdown('pause'); window.clearInterval(GUI.currentKnob); } } - // step volume control + // step volume control else if (el.hasClass('btn-volume')) { var vol; var knobvol = parseInt($('#volume').val()); - if (GUI.volume === null ) { + if (GUI.volume === null) { GUI.volume = knobvol; } if (dataCmd === 'volumedn' && parseInt(GUI.volume) > 0) { @@ -1451,7 +1418,7 @@ function commandButton(el) { GUI.volume = vol; $('#volumemute').removeClass('btn-primary'); } else if (dataCmd === 'volumemute') { - if (knobvol !== 0 ) { + if (knobvol !== 0) { GUI.volume = knobvol; el.addClass('btn-primary'); vol = 0; @@ -1469,9 +1436,9 @@ function commandButton(el) { // toggle buttons if (el.hasClass('btn-toggle')) { - cmd = dataCmd + (el.hasClass('btn-primary')? ' 0':' 1'); + cmd = dataCmd + (el.hasClass('btn-primary') ? ' 0' : ' 1'); el.toggleClass('btn-primary'); - // send command + // send command } else { cmd = dataCmd; } @@ -1489,7 +1456,7 @@ function libraryHome(text) { function listWLANs(text) { var i = 0, content = '', inrange = '', stored = '', wlans = text[0]; // console.log(wlans); - $.each(wlans, function(i) { + $.each(wlans, function (i) { content += '

    '; if (wlans[i].connected !== 0) { content += ''; @@ -1500,8 +1467,8 @@ function listWLANs(text) { if (wlans[i].encryption === 'on') { content += ''; } else { - if (wlans[i].storedprofile !== 1 ) { - content += ''; + if (wlans[i].storedprofile !== 1) { + content += ''; } } } @@ -1518,14 +1485,14 @@ function listWLANs(text) { } document.getElementById('wifiNetworks').innerHTML = inrange; document.getElementById('wifiStored').innerHTML = stored; - $.ajax({url: '/command/?cmd=wifiscan'}); + $.ajax({ url: '/command/?cmd=wifiscan' }); } // draw the NICs details table function nicsDetails(text) { var i = 0, content = '', nics = text[0]; // console.log(nics); - $.each(nics, function(i) { + $.each(nics, function (i) { if (i === $('#nic-details').data('name')) { content += 'Name:' + i + ''; content += 'Type:wireless'; @@ -1535,7 +1502,7 @@ function nicsDetails(text) { content += 'Status:connected'; content += 'Associated SSID:' + nics[i].currentssid + ''; } - + content += 'Assigned IP:' + ((nics[i].ip !== null) ? ('' + nics[i].ip + '') : 'none') + ''; content += 'Speed:' + ((nics[i].speed !== null) ? nics[i].speed : 'unknown') + ''; // content += 'Netmask:' + nics[i].netmask + ''; @@ -1548,7 +1515,7 @@ function nicsDetails(text) { } // open the Playback UI refresh channel -function playbackChannel(){ +function playbackChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1556,7 +1523,7 @@ function playbackChannel(){ reconnectOnChannelUnavailableInterval: 5000 }); pushstream.onmessage = renderUI; - pushstream.onstatuschange = function(status) { + pushstream.onstatuschange = function (status) { // console.log('[nginx pushtream module] status = ', status); if (status === 2) { $('#loader').addClass('hide'); @@ -1570,15 +1537,15 @@ function playbackChannel(){ } }; // pushstream.onerror = function() { - // toggleLoader(); - // console.log('[nginx pushtream module] error'); + // toggleLoader(); + // console.log('[nginx pushtream module] error'); // }; pushstream.addChannel('playback'); pushstream.connect(); } // open the playing queue channel -function queueChannel(){ +function queueChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1587,14 +1554,14 @@ function queueChannel(){ pushstream.onmessage = getPlaylist; // pushstream.onstatuschange = function(status) { // force queue rendering (backend-call) - // if (status === 2) sendCmd('renderpl'); + // if (status === 2) sendCmd('renderpl'); // }; pushstream.addChannel('queue'); pushstream.connect(); } // open the library channel -function libraryChannel(){ +function libraryChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1606,7 +1573,7 @@ function libraryChannel(){ } // open the notify messages channel -function notifyChannel(){ +function notifyChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1618,7 +1585,7 @@ function notifyChannel(){ } // open the in range Wi-Fi networks list channel -function wlansChannel(){ +function wlansChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1627,11 +1594,11 @@ function wlansChannel(){ pushstream.onmessage = listWLANs; pushstream.addChannel('wlans'); pushstream.connect(); - $.ajax({url: '/command/?cmd=wifiscan'}); + $.ajax({ url: '/command/?cmd=wifiscan' }); } // open the NIC details channel -function nicsChannel(){ +function nicsChannel() { var pushstream = new PushStream({ host: window.location.hostname, port: window.location.port, @@ -1645,38 +1612,38 @@ function nicsChannel(){ // trigger home overlays function overlayTrigger(overlayID) { // var triggerBttn = $('#overlay-social-open'), - // overlay = $('#overlay-social'), - // closeBttn = $('button.overlay-close'); + // overlay = $('#overlay-social'), + // closeBttn = $('button.overlay-close'); var overlay = $(overlayID), triggerBttn = $(overlayID + '-open'), closeBttn = $(overlayID + '-close'); - transEndEventNames = { - 'WebkitTransition': 'webkitTransitionEnd', - 'MozTransition': 'transitionend', - 'OTransition': 'oTransitionEnd', - 'msTransition': 'MSTransitionEnd', - 'transition': 'transitionend' - }; - // transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], - // support = { transitions : Modernizr.csstransitions }; + transEndEventNames = { + 'WebkitTransition': 'webkitTransitionEnd', + 'MozTransition': 'transitionend', + 'OTransition': 'oTransitionEnd', + 'msTransition': 'MSTransitionEnd', + 'transition': 'transitionend' + }; + // transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], + // support = { transitions : Modernizr.csstransitions }; function toggleOverlay() { if (overlay.hasClass('open')) { overlay.removeClass('open'); overlay.addClass('closed'); - var onEndTransitionFn = function(ev) { + var onEndTransitionFn = function (ev) { if (support.transitions) { if (ev.propertyName !== 'visibility') { return; } - this.removeEventListener( transEndEventName, onEndTransitionFn ); + this.removeEventListener(transEndEventName, onEndTransitionFn); } overlay.removeClass('closed'); }; // if (support.transitions) { - // overlay.addEventListener( transEndEventName, onEndTransitionFn ); + // overlay.addEventListener( transEndEventName, onEndTransitionFn ); // } // else { - // onEndTransitionFn(); + // onEndTransitionFn(); // } } else if (overlay.hasClass('closed')) { @@ -1691,23 +1658,23 @@ function overlayTrigger(overlayID) { } } } - triggerBttn.click(function(){ + triggerBttn.click(function () { toggleOverlay(); }); - closeBttn.click(function(){ + closeBttn.click(function () { toggleOverlay(); }); } // check visibility of the window -function getHiddenProp(){ - var prefixes = ['webkit','moz','ms','o']; +function getHiddenProp() { + var prefixes = ['webkit', 'moz', 'ms', 'o']; // if 'hidden' is natively supported just return it if ('hidden' in document) { return 'hidden'; } // otherwise loop over all the known prefixes until we find one - for (var i = 0; i < prefixes.length; i++){ + for (var i = 0; i < prefixes.length; i++) { if ((prefixes[i] + 'Hidden') in document) { return prefixes[i] + 'Hidden'; } @@ -1736,29 +1703,27 @@ function visChange() { if ($('#section-index').length) { -// ==================================================================================================== -// PLAYBACK SECTION -// ==================================================================================================== + // ==================================================================================================== + // PLAYBACK SECTION + // ==================================================================================================== - jQuery(document).ready(function($){ 'use strict'; + jQuery(document).ready(function ($) { + 'use strict'; // INITIALIZATION // ---------------------------------------------------------------------------------------------------- - + // check WebSocket support GUI.mode = checkWebSocket(); - + // first connection with MPD daemon // open UI rendering channel; playbackChannel(); - + // open library channel libraryChannel(); // startChannel(queueChannel()); - - // first GUI update - // updateGUI(); - + // PNotify init options PNotify.prototype.options.styling = 'fontawesome'; PNotify.prototype.options.stack.dir1 = 'up'; @@ -1769,45 +1734,45 @@ if ($('#section-index').length) { PNotify.prototype.options.stack.spacing2 = 10; // open notify channel notifyChannel(); - + // use the property name to generate the prefixed event name var visProp = getHiddenProp(); if (visProp) { - var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange'; + var evtname = visProp.replace(/[H|h]idden/, '') + 'visibilitychange'; document.addEventListener(evtname, visChange); } // BUTTONS // ---------------------------------------------------------------------------------------------------- - + // playback buttons - $('.btn-cmd').click(function(){ + $('.btn-cmd').click(function () { var el = $(this); commandButton(el); }); - + $('#volume-step-dn').on({ - mousedown : function () { + mousedown: function () { volumeStepCalc('dn'); }, - mouseup : function () { + mouseup: function () { volumeStepSet(); } }); - + $('#volume-step-up').on({ - mousedown : function () { + mousedown: function () { volumeStepCalc('up'); }, - mouseup : function () { + mouseup: function () { volumeStepSet(); } }); - - + + // KNOBS // ---------------------------------------------------------------------------------------------------- - + // playback knob $('#time').knob({ inline: false, @@ -1832,7 +1797,7 @@ if ($('#section-index').length) { release: function (value) { setvol(value); }, - draw: function() { + draw: function () { // "tron" case if (this.$.data('skin') === 'tron') { this.cursorExt = 0.05; @@ -1846,13 +1811,13 @@ if ($('#section-index').length) { this.g.stroke(); } this.g.beginPath(); - this.g.strokeStyle = r ? this.o.fgColor : this.fgColor ; + this.g.strokeStyle = r ? this.o.fgColor : this.fgColor; this.g.arc(this.xy, this.xy, this.radius - this.lineWidth, a.s, a.e, a.d); this.g.stroke(); this.g.lineWidth = 2; this.g.beginPath(); this.g.strokeStyle = this.o.fgColor; - this.g.arc( this.xy, this.xy, this.radius - this.lineWidth + 13 + this.lineWidth, 0, 2 * Math.PI, false); + this.g.arc(this.xy, this.xy, this.radius - this.lineWidth + 13 + this.lineWidth, 0, 2 * Math.PI, false); this.g.stroke(); return false; } @@ -1864,9 +1829,9 @@ if ($('#section-index').length) { // ---------------------------------------------------------------------------------------------------- var playlist = $('#playlist-entries'); - + // click on queue entry - playlist.on('click', 'li', function(e) { + playlist.on('click', 'li', function (e) { var cmd = ''; if ($(e.target).hasClass('pl-action')) { // remove queue entry @@ -1888,7 +1853,8 @@ if ($('#section-index').length) { }); // on ready playlist tab - $('a', '#open-panel-dx').click(function(){ + $('a', '#open-panel-dx').click(function () { + // check if the Queue tab is visible if ($('#open-panel-dx').hasClass('active')) { var current = parseInt(GUI.json.song); customScroll('pl', current, 500); @@ -1900,16 +1866,16 @@ if ($('#section-index').length) { }); // open Library tab - $('#open-library').click(function(){ + $('#open-library').click(function () { $('#open-panel-dx').removeClass('active'); $('#open-panel-sx').addClass('active'); }); // Queue on the fly filtering - $('#pl-filter').keyup(function(){ - $.scrollTo(0 , 500); + $('#pl-filter').keyup(function () { + $.scrollTo(0, 500); var filter = $(this).val(), count = 0; - $('li', '#playlist-entries').each(function(){ + $('li', '#playlist-entries').each(function () { var el = $(this); if (el.text().search(new RegExp(filter, 'i')) < 0) { el.hide(); @@ -1928,9 +1894,9 @@ if ($('#section-index').length) { $('#pl-filter-results').addClass('hide').html(''); } }); - + // close filter results - $('#pl-filter-results').click(function(){ + $('#pl-filter-results').click(function () { $(this).addClass('hide'); $('#pl-count').removeClass('hide'); if ($(this).hasClass('back-to-queue')) { @@ -1939,7 +1905,7 @@ if ($('#section-index').length) { $('#pl-currentpath').addClass('hide'); $('#pl-manage').removeClass('hide'); } else { - $('li', '#playlist-entries').each(function(){ + $('li', '#playlist-entries').each(function () { var el = $(this); el.show(); }); @@ -1948,48 +1914,48 @@ if ($('#section-index').length) { } customScroll('pl', parseInt(GUI.json.song), 500); }); - + // playlists management - $('#pl-manage-list').click(function(){ + $('#pl-manage-list').click(function () { getPlaylists(); }); - + // save current Queue to playlist - $('#modal-pl-save-btn').click(function(){ + $('#modal-pl-save-btn').click(function () { var playlistname = $('#pl-save-name').val(); sendCmd('save "' + playlistname + '"'); }); - + // playlists management - actions context menu - $('#pl-editor').on('click', '.pl-action', function(e) { + $('#pl-editor').on('click', '.pl-action', function (e) { e.preventDefault(); var path = $(this).parent().attr('data-path'); GUI.DBentry[0] = path; }); - + // playlist rename action - $('#pl-rename-button').click(function(){ + $('#pl-rename-button').click(function () { var oldname = $('#pl-rename-oldname').text(); var newname = $('#pl-rename-name').val(); sendCmd('rename "' + oldname + '" "' + newname + '"'); getPlaylists(); }); - + // sort Queue entries var sortlist = document.getElementById('playlist-entries'); new Sortable(sortlist, { ghostClass: 'sortable-ghost', - onUpdate: function (evt){ + onUpdate: function (evt) { sortOrder(evt.item.getAttribute('id')); } }); - - + + // LIBRARY // ---------------------------------------------------------------------------------------------------- - + // on ready Library tab - $('a', '#open-panel-sx').click(function(){ + $('a', '#open-panel-sx').click(function () { if ($('#open-panel-sx').hasClass('active')) { customScroll('pl', parseInt(GUI.json.song), 500); } @@ -1997,9 +1963,9 @@ if ($('#section-index').length) { .on('shown.bs.tab', function (e) { customScroll('db', GUI.currentDBpos[GUI.currentDBpos[10]], 0); }); - + // click on Library home block - $('#home-blocks').on('click', '.home-block', function(e) { + $('#home-blocks').on('click', '.home-block', function (e) { if (!$(this).hasClass('inactive')) { if ($(this).is('#home-spotify-switch')) { $('#overlay-playsource-open').trigger('click'); @@ -2007,7 +1973,7 @@ if ($('#section-index').length) { var bookmarkID = $(this).attr('id'); bookmarkID = bookmarkID.replace('home-bookmark-', ''); var bookmarkName = $(this).find('h3').text(); - $.post('/db/?cmd=bookmark', { 'id' : bookmarkID, 'name' : bookmarkName }); + $.post('/db/?cmd=bookmark', { 'id': bookmarkID, 'name': bookmarkName }); } else { ++GUI.currentDBpos[10]; getDB({ @@ -2021,9 +1987,9 @@ if ($('#section-index').length) { $('#overlay-playsource-open').trigger('click'); } }); - + // setup Library home - $('#db-homeSetup').click(function(){ + $('#db-homeSetup').click(function () { var editbtn = $(this); if (editbtn.hasClass('btn-primary')) { editbtn.removeClass('btn-primary').addClass('btn-default'); @@ -2033,16 +1999,16 @@ if ($('#section-index').length) { $('.home-block.home-bookmark').append('

    '); } }); - + var db = $('#database-entries'); - + // click on Library list entry - db.on('click', 'li', function(e) { + db.on('click', 'li', function (e) { var path = '', browsemode = ''; var el = $(this); if ($(e.target).hasClass('db-action')) { - // actions context menu + // actions context menu e.preventDefault(); if (el.data('type') === 'spotify-track') { path = el.data('plid') + '-' + el.data('path'); @@ -2052,13 +2018,13 @@ if ($('#section-index').length) { GUI.DBentry[0] = path; // console.log('getDB path = ', GUI.DBentry); } else { - // list browsing + // list browsing $('li.active', '#database-entries').removeClass('active'); el.addClass('active'); if (el.hasClass('db-folder')) { path = el.data('path'); if (el.hasClass('db-album')) { - // browse by album + // browse by album if (path !== '') { getDB({ path: path, @@ -2074,22 +2040,22 @@ if ($('#section-index').length) { }); } } else if (el.hasClass('db-artist')) { - // browse by album + // browse by album getDB({ path: path, uplevel: 0, browsemode: 'artist' }); } else if (el.hasClass('db-genre')) { - // browse by genre + // browse by genre getDB({ path: path, uplevel: 0, browsemode: 'genre' }); } else if (el.hasClass('db-spotify')) { - // Spotify playlists - path = GUI.currentpath + '/' + el.find('span').text(); + // Spotify playlists + path = GUI.currentpath + '/' + el.find('span').text(); getDB({ path: path, plugin: 'Spotify', @@ -2098,8 +2064,8 @@ if ($('#section-index').length) { }); GUI.plugin = 'Spotify'; } else if (el.hasClass('db-dirble')) { - // Dirble folders - path = GUI.currentpath + '/' + el.find('span').text(); + // Dirble folders + path = GUI.currentpath + '/' + el.find('span').text(); getDB({ path: path, plugin: 'Dirble', @@ -2108,18 +2074,18 @@ if ($('#section-index').length) { }); GUI.plugin = 'Dirble'; } else if (el.hasClass('db-jamendo')) { - // Jamendo folders + // Jamendo folders // path = GUI.currentpath + '/' + el.find('span').text(); // var querytype = 'radio'; // var args = el.data('path'); // getDB({ - // path: path, - // plugin: 'Jamendo', - // querytype: querytype, - // args : args + // path: path, + // plugin: 'Jamendo', + // querytype: querytype, + // args : args // }); } else { - // browse by file (default) + // browse by file (default) browsemode = el.data('browsemode'); //GUI.currentDBpos[GUI.currentDBpos[10]] = $('.database .db-entry').index(this); getDB({ @@ -2129,7 +2095,7 @@ if ($('#section-index').length) { }); } var entryID = el.attr('id'); - entryID = entryID.replace('db-',''); + entryID = entryID.replace('db-', ''); GUI.currentDBpos[GUI.currentDBpos[10]] = entryID; GUI.currentDBpath[GUI.currentDBpos[10]] = path; ++GUI.currentDBpos[10]; @@ -2140,7 +2106,7 @@ if ($('#section-index').length) { } }); // double click on Library list entry - db.on('dblclick', 'li', function(e) { + db.on('dblclick', 'li', function (e) { var el = $(this); if (!$(e.target).hasClass('db-action')) { $('li.active', '#database-entries').removeClass('active'); @@ -2165,7 +2131,7 @@ if ($('#section-index').length) { }); // browse level up (back arrow) - $('#db-level-up').click(function(){ + $('#db-level-up').click(function () { --GUI.currentDBpos[10]; var path = GUI.currentpath; if (GUI.currentDBpos[10] === 0) { @@ -2173,7 +2139,7 @@ if ($('#section-index').length) { } else { if (GUI.browsemode === 'file') { var cutpos = path.lastIndexOf('/'); - path = (cutpos !== -1) ? path.slice(0,cutpos):''; + path = (cutpos !== -1) ? path.slice(0, cutpos) : ''; } else { if (GUI.browsemode === 'album') { path = GUI.currentDBpath[GUI.currentDBpos[10] - 1]; @@ -2209,7 +2175,7 @@ if ($('#section-index').length) { }); // close search results - $('#db-search-results').click(function(){ + $('#db-search-results').click(function () { $(this).addClass('hide'); $('#db-level-up').removeClass('hide'); getDB({ @@ -2218,7 +2184,7 @@ if ($('#section-index').length) { }); // context dropdown menu - $('a', '.context-menu').click(function(){ + $('a', '.context-menu').click(function () { var dataCmd = $(this).data('cmd'); var dataType = $(this).data('type'); var path = GUI.DBentry[0]; @@ -2227,26 +2193,26 @@ if ($('#section-index').length) { case 'pl-add': sendCmd('load "' + path + '"'); break; - + case 'pl-replace': sendCmd('clear'); sendCmd('load "' + path + '"'); break; - + case 'pl-rename': $('#modal-pl-rename').modal(); $('#pl-rename-oldname').text(path); break; - + case 'pl-rm': $.ajax({ url: '/command/?cmd=rm%20%22' + path + '%22', - success: function(data){ + success: function (data) { getPlaylists(data); } }); break; - + case 'wradd': path = path.split(' | ')[1]; getDB({ @@ -2254,7 +2220,7 @@ if ($('#section-index').length) { path: path }); break; - + case 'wraddplay': path = path.split(' | ')[1]; getDB({ @@ -2262,7 +2228,7 @@ if ($('#section-index').length) { path: path }); break; - + case 'wraddreplaceplay': path = path.split(' | ')[1]; getDB({ @@ -2270,12 +2236,12 @@ if ($('#section-index').length) { path: path }); break; - + case 'wredit': $('#modal-webradio-edit').modal(); $.post('/db/?cmd=readradio', { filename: path - }, function(data){ + }, function (data) { // get parsed content of .pls file and populate the form fields var name = $('#webradio-edit-name'); name.val(data.name); @@ -2283,17 +2249,17 @@ if ($('#section-index').length) { $('#webradio-edit-url').val(data.url); }, 'json'); break; - + case 'wrdelete': $('#modal-webradio-delete').modal(); $('#webradio-delete-name').text(path.replace('Webradio/', '')); break; - + case 'wrsave': var parameters = path.split(' | '); - $.post('/db/?cmd=addradio', { 'radio[label]' : parameters[0], 'radio[url]' : parameters[1] }); + $.post('/db/?cmd=addradio', { 'radio[label]': parameters[0], 'radio[url]': parameters[1] }); break; - + default: getDB({ cmd: dataCmd, @@ -2306,13 +2272,13 @@ if ($('#section-index').length) { }); // add webradio - $('#webradio-add-button').click(function(){ + $('#webradio-add-button').click(function () { var radioname = $('#webradio-add-name').val(); var radiourl = $('#webradio-add-url').val(); if (radioname === '' || radiourl === '') { - renderMSG([{'title': 'Missing fields', 'text': 'Please fill both fields to continue', 'icon': 'fa fa-warning'}]); + renderMSG([{ 'title': 'Missing fields', 'text': 'Please fill both fields to continue', 'icon': 'fa fa-warning' }]); } else { - $.post('/db/?cmd=addradio', { 'radio[label]' : radioname, 'radio[url]' : radiourl }, function(data){ + $.post('/db/?cmd=addradio', { 'radio[label]': radioname, 'radio[url]': radiourl }, function (data) { // console.log('SENT'); }, 'json'); $('#modal-webradio-add').modal('hide'); @@ -2320,150 +2286,119 @@ if ($('#section-index').length) { $('#webradio-add-url').val(''); } }); - + // edit webradio - $('#webradio-edit-button').click(function(){ + $('#webradio-edit-button').click(function () { var name = $('#webradio-edit-name'); $.post('/db/?cmd=editradio', { 'radio[newlabel]': name.val(), 'radio[label]': name.data('file-name'), 'radio[url]': $('#webradio-edit-url').val() - }, function(data){ + }, function (data) { // console.log('editedradio', data); }, 'json'); }); - + // delete webradio - $('#webradio-delete-button').click(function(){ - // console.log( $('#webradio-delete-name').text() ); + $('#webradio-delete-button').click(function () { + // console.log( $('#webradio-delete-name').text() ); var radioname = $('#webradio-delete-name').text(); - $.post('/db/?cmd=deleteradio', { 'radio[label]' : radioname }, function(data){ + $.post('/db/?cmd=deleteradio', { 'radio[label]': radioname }, function (data) { // console.log('SENT'); }, 'json'); }); - - + + // GENERAL // ---------------------------------------------------------------------------------------------------- - + // scroll buttons - $('#db-alphabet').click(function () { - //$(window)[0].location.hash = "R"; - $('#overlay-alphabet-open').trigger('click'); + $('#db-firstPage').click(function () { + $.scrollTo(0, 500); }); - $('#db-firstPage').click(function(){ - $.scrollTo(0 , 500); - }); - $('#db-prevPage').click(function(){ + $('#db-prevPage').click(function () { var scrolloffset = '-=' + $(window).height() + 'px'; - $.scrollTo(scrolloffset , 500); + $.scrollTo(scrolloffset, 500); }); - $('#db-nextPage').click(function(){ + $('#db-nextPage').click(function () { var scrolloffset = '+=' + $(window).height() + 'px'; - $.scrollTo(scrolloffset , 500); + $.scrollTo(scrolloffset, 500); }); - $('#db-lastPage').click(function(){ + $('#db-lastPage').click(function () { $.scrollTo('100%', 500); }); - $('#pl-firstPage').click(function(){ - $.scrollTo(0 , 500); + $('#pl-firstPage').click(function () { + $.scrollTo(0, 500); }); - $('#pl-prevPage').click(function(){ + $('#pl-prevPage').click(function () { var scrollTop = $(window).scrollTop(); var scrolloffset = scrollTop - $(window).height(); - $.scrollTo(scrolloffset , 500); + $.scrollTo(scrolloffset, 500); }); - $('#pl-nextPage').click(function(){ + $('#pl-nextPage').click(function () { var scrollTop = $(window).scrollTop(); var scrolloffset = scrollTop + $(window).height(); - $.scrollTo(scrolloffset , 500); + $.scrollTo(scrolloffset, 500); }); - $('#pl-lastPage').click(function(){ + $('#pl-lastPage').click(function () { $.scrollTo('100%', 500); }); - + // open tab from external link var url = document.location.toString(); // console.log('url = ', url); - if ( url.match('#') ) { + if (url.match('#')) { $('#menu-bottom a[href="/#' + url.split('#')[1] + '"]').tab('show'); } // do not scroll with HTML5 history API - $('#menu-bottom a').on('shown', function(e) { - if(history.pushState) { + $('#menu-bottom a').on('shown', function (e) { + if (history.pushState) { history.pushState(null, null, e.target.hash); } else { window.location.hash = e.target.hash; // Polyfill for old browsers } - }).on('click', function() { + }).on('click', function () { if ($('#overlay-social').hasClass('open')) { $('.overlay-close').trigger('click'); } }); - + // tooltips if ($('.ttip').length) { $('.ttip').tooltip(); } - + // remove the 300ms click delay on mobile browsers FastClick.attach(document.body); - + // system poweroff - $('#syscmd-poweroff').click(function(){ - $.post('/settings/', { 'syscmd' : 'poweroff' }); + $('#syscmd-poweroff').click(function () { + $.post('/settings/', { 'syscmd': 'poweroff' }); toggleLoader(); }); // system reboot - $('#syscmd-reboot').click(function(){ - $.post('/settings/', { 'syscmd' : 'reboot' }); + $('#syscmd-reboot').click(function () { + $.post('/settings/', { 'syscmd': 'reboot' }); toggleLoader(); }); - + // social share overlay overlayTrigger('#overlay-social'); // play source overlay overlayTrigger('#overlay-playsource'); - - - - // - // alphabet library navigation overlay setup - overlayTrigger('#overlay-alphabet'); - - // implement a means of scrolling to the selected letter, - // plus a little to accomdate the fixed header - $('#overlay-alphabet a').click(function () { - $('#overlay-alphabet-close').trigger("click"); - - // ** - // this may need to be tweaked to play well with other hash tags - if (window.location.hash.length == 0) { - window.location.hash = '#' + $(this).attr('data-alphabet'); // navigate to the letter - } else { - window.location.hash = $(this).attr('data-alphabet'); // navigate to the letter - } - - var scrollTop = $(window).scrollTop(); - var scrolloffset = scrollTop - 80; // use the actual height of "header" - $.scrollTo(scrolloffset, 500); - }) - // - - // play source manual switch - $('#playsource-mpd').click(function(){ + $('#playsource-mpd').click(function () { if ($(this).hasClass('inactive')) { - $.ajax({url: '/command/?switchplayer=MPD'}); + $.ajax({ url: '/command/?switchplayer=MPD' }); // close switch buttons layer $('#overlay-playsource-close').trigger('click'); } }); - $('#playsource-spotify').click(function(){ + $('#playsource-spotify').click(function () { if ($(this).hasClass('inactive')) { if (GUI.libraryhome.Spotify === '1') { - $.ajax({url: '/command/?switchplayer=Spotify'}); + $.ajax({ url: '/command/?switchplayer=Spotify' }); // close switch buttons layer $('#overlay-playsource-close').trigger('click'); } else { @@ -2475,30 +2410,28 @@ if ($('#section-index').length) { } } }); - + }); - + } else { -// ==================================================================================================== -// OTHER SECTIONS -// ==================================================================================================== + // ==================================================================================================== + // OTHER SECTIONS + // ==================================================================================================== + + jQuery(document).ready(function ($) { + 'use strict'; - jQuery(document).ready(function($){ 'use strict'; - // INITIALIZATION // ---------------------------------------------------------------------------------------------------- - + // check WebSocket support GUI.mode = checkWebSocket(); - + // first connection with MPD daemon // open UI rendering channel; playbackChannel(); - - // first GUI update - // updateGUI(); - + // PNotify init options PNotify.prototype.options.styling = 'fontawesome'; PNotify.prototype.options.stack.dir1 = 'up'; @@ -2509,46 +2442,46 @@ if ($('#section-index').length) { PNotify.prototype.options.stack.spacing2 = 10; // open notify channel notifyChannel(); - - + + // BUTTONS // ---------------------------------------------------------------------------------------------------- - + // playback buttons - $('.btn-cmd').click(function(){ + $('.btn-cmd').click(function () { var el = $(this); commandButton(el); }); - + // system poweroff - $('#syscmd-poweroff').click(function(){ - $.post('/settings/', { 'syscmd' : 'poweroff' }); + $('#syscmd-poweroff').click(function () { + $.post('/settings/', { 'syscmd': 'poweroff' }); toggleLoader(); }); // system reboot - $('#syscmd-reboot').click(function(){ - $.post('/settings/', { 'syscmd' : 'reboot' }); + $('#syscmd-reboot').click(function () { + $.post('/settings/', { 'syscmd': 'reboot' }); toggleLoader(); }); - - + + // COMMON // ---------------------------------------------------------------------------------------------------- - + // Bootstrap-select $('.selectpicker').selectpicker(); - + // SOURCES // ---------------------------------------------------------------------------------------------------- - + if ($('#section-sources').length) { - + // enable/disable CIFS auth section if ($('#mount-type').val() === 'nfs') { $('#mount-cifs').addClass('disabled').children('.disabler').removeClass('hide'); } - $('#mount-type').change(function(){ + $('#mount-type').change(function () { if ($(this).val() === 'cifs' || $(this).val() === 'osx') { $('#mount-cifs').removeClass('disabled').children('.disabler').addClass('hide'); } @@ -2556,9 +2489,9 @@ if ($('#section-index').length) { $('#mount-cifs').addClass('disabled').children('.disabler').removeClass('hide'); } }); - + // enable/disable CIFS user and password fields - $('#nas-guest').change(function(){ + $('#nas-guest').change(function () { if ($(this).prop('checked')) { //console.log('checked'); $('#mount-auth').addClass('disabled').children('.disabler').removeClass('hide'); @@ -2567,17 +2500,17 @@ if ($('#section-index').length) { $('#mount-auth').removeClass('disabled').children('.disabler').addClass('hide'); } }); - + // show advanced options - $('#nas-advanced').change(function(){ + $('#nas-advanced').change(function () { if ($(this).prop('checked')) { $('#mount-advanced-config').removeClass('hide'); } else { $('#mount-advanced-config').addClass('hide'); } }); - - $('#show-mount-advanced-config').click(function(e){ + + $('#show-mount-advanced-config').click(function (e) { e.preventDefault(); if ($(this).hasClass('active')) { $('#mount-advanced-config').toggleClass('hide'); @@ -2591,22 +2524,22 @@ if ($('#section-index').length) { $(this).find('span').html('hide advanced options'); } }); - - $('#usb-mount-list a').click(function(){ + + $('#usb-mount-list a').click(function () { var mountName = $(this).data('mount'); $('#usb-umount-name').html(mountName); $('#usb-umount').val(mountName); }); } - - + + // SETTINGS // ---------------------------------------------------------------------------------------------------- - + if ($('#section-settings').length) { - + // show/hide AirPlay name form - $('#airplay').change(function(){ + $('#airplay').change(function () { if ($(this).prop('checked')) { $('#airplayName').removeClass('hide'); $('#airplayBox').addClass('boxed-group'); @@ -2615,9 +2548,9 @@ if ($('#section-index').length) { $('#airplayBox').removeClass('boxed-group'); } }); - + // show/hide Last.fm auth form - $('#scrobbling-lastfm').change(function(){ + $('#scrobbling-lastfm').change(function () { if ($(this).prop('checked')) { $('#lastfmAuth').removeClass('hide'); $('#lastfmBox').addClass('boxed-group'); @@ -2626,9 +2559,9 @@ if ($('#section-index').length) { $('#lastfmBox').removeClass('boxed-group'); } }); - + // show/hide proxy settings form - $('#proxy').change(function(){ + $('#proxy').change(function () { if ($(this).prop('checked')) { $('#proxyAuth').removeClass('hide'); $('#proxyBox').addClass('boxed-group'); @@ -2637,9 +2570,9 @@ if ($('#section-index').length) { $('#proxyBox').removeClass('boxed-group'); } }); - + // show/hide UPnP/dlna name form - $('#dlna').change(function(){ + $('#dlna').change(function () { if ($(this).prop('checked')) { $('#dlnaName').removeClass('hide'); $('#dlnaBox').addClass('boxed-group'); @@ -2648,9 +2581,9 @@ if ($('#section-index').length) { $('#dlnaBox').removeClass('boxed-group'); } }); - + // show/hide Spotify auth form - $('#spotify').change(function(){ + $('#spotify').change(function () { if ($(this).prop('checked')) { $('#spotifyAuth').removeClass('hide'); $('#spotifyBox').addClass('boxed-group'); @@ -2661,19 +2594,19 @@ if ($('#section-index').length) { }); } - - + + // NETWORK // ---------------------------------------------------------------------------------------------------- - + if ($('#section-network').length) { - + // show/hide static network configuration based on select value var netManualConf = $('#network-manual-config'); if ($('#dhcp').val() === '0') { netManualConf.removeClass('hide'); } - $('#dhcp').change(function(){ + $('#dhcp').change(function () { if ($(this).val() === '0') { netManualConf.removeClass('hide'); } @@ -2681,13 +2614,13 @@ if ($('#section-index').length) { netManualConf.addClass('hide'); } }); - + // show/hide WiFi security configuration based on select value var WiFiKey = $('#wifi-security-key'); if ($('#wifi-security').val() !== 'open') { WiFiKey.removeClass('hide'); } - $('#wifi-security').change(function(){ + $('#wifi-security').change(function () { if ($(this).val() !== 'open') { WiFiKey.removeClass('hide'); } @@ -2695,18 +2628,18 @@ if ($('#section-index').length) { WiFiKey.addClass('hide'); } }); - + // refresh in range Wi-Fi networks list if ($('#wifiNetworks').length) { // open wlans channel wlansChannel(); - + // open nics channel nicsChannel(); } - + // show/hide WiFi stored profile box - $('#wifiProfiles').change(function(){ + $('#wifiProfiles').change(function () { if ($(this).prop('checked')) { $('#wifiProfilesBox').addClass('hide'); } else { @@ -2715,16 +2648,16 @@ if ($('#section-index').length) { }); } - + // MPD // ---------------------------------------------------------------------------------------------------- - + if ($('#section-mpd').length) { - + // output interface select - $('#audio-output-interface').change(function(){ - renderMSG([{'title': 'Switching audio output', 'text': 'Please wait for the config update...', 'icon': 'fa fa-cog fa-spin', 'delay': 5000 }]); + $('#audio-output-interface').change(function () { + renderMSG([{ 'title': 'Switching audio output', 'text': 'Please wait for the config update...', 'icon': 'fa fa-cog fa-spin', 'delay': 5000 }]); var output = $(this).val(); $.ajax({ type: 'POST', @@ -2732,25 +2665,25 @@ if ($('#section-index').length) { data: { ao: output } }); }); - + // MPD config manual edit - $('.manual-edit-confirm').find('.btn-primary').click(function(){ + $('.manual-edit-confirm').find('.btn-primary').click(function () { $('#mpdconf_editor').removeClass('hide'); $('#manual-edit-warning').addClass('hide'); }); } - - + + // DEBUG // ---------------------------------------------------------------------------------------------------- - + if ($('#section-debug').length) { - ZeroClipboard.config({swfPath: '/assets/js/vendor/ZeroClipboard.swf'}); + ZeroClipboard.config({ swfPath: '/assets/js/vendor/ZeroClipboard.swf' }); var client = new ZeroClipboard(document.getElementById('copy-to-clipboard')); - client.on('ready', function(readyEvent){ + client.on('ready', function (readyEvent) { // alert('ZeroClipboard SWF is ready!'); - client.on('aftercopy', function(event){ + client.on('aftercopy', function (event) { // alert('Copied text to clipboard: ' + event.data['text/plain']); new PNotify({ title: 'Copied to clipboard', @@ -2761,7 +2694,7 @@ if ($('#section-index').length) { }); } - + }); } @@ -2772,44 +2705,67 @@ if ($('#section-index').length) { // ---------------------------------------------------------------------------------------------------- var queueEntryHeight = 49; -var pageY = 0, pageHeight = 0; -window.onscroll = function(e) { - pageY = Math.max(e.pageY || window.pageYOffset, 0); - pageHeight = window.innerHeight; - m.redraw(); +var pageY = 0, + pageHeight = window.innerHeight, + pageOldY = 0; +window.resize = function () { + pageHeight = window.innerHeight; }; -$(window).trigger('scroll'); - -m.module(document.getElementById('playlist-entries-container'), { - controller: function() {}, - view: function() { - var begin = Math.ceil(pageY / queueEntryHeight) || 0; - var end = begin + (pageHeight / queueEntryHeight || 0 + 2); - var offset = pageY % queueEntryHeight; - m('#pl-count', queueTracks.length); // [TODO] check this - return m('div', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ - m('ul#playlist-entries.playlist', {style: 'position:relative;top:' + pageY + 'px'}, [ - (queueTracks)?queueTracks.slice(begin, end).map(function(song, idx) { - var icon = null; - var bottom = null; - if (song.webradio) { - icon = m('i.fa.fa-microphone'); - bottom = 'URL: ' + song.file; - } else if (song.artist) { - bottom = song.artist + ' - ' + song.album; - } else { - bottom = 'path: ' + song.filename.split('/').pop(); - } - return m('li', {id: 'pl-' + song.id, 'data-queuepos': begin + idx}, [ +window.onscroll = function (e) { + pageY = Math.max(window.pageYOffset, 0); // the pixels the current document has been scrolled from the upper left corner of the window + var diff = Math.abs(pageOldY - (pageY - pageHeight * 0.5)); + console.log('pageY=' + pageY + ', pageOldY=' + pageOldY + ', diff=' + diff + ', pageHeight=' + pageHeight); + if (diff > pageHeight) { + pageOldY = pageY; + m.redraw(); + } +}; +// $(window).trigger('scroll'); + +m.module(document.getElementById('playlist'), { + controller: function () { }, + view: function () { + var begin = Math.ceil(pageY / queueEntryHeight) || 0; // first visible entry + var visibleEntries = (Math.floor(pageHeight / queueEntryHeight || 0 + 2)); + var end = begin + visibleEntries; // last visible entry + var offset = pageY % queueEntryHeight; + // var offset = 0; + var next = visibleEntries * 2; // amount of following blocks + var previous = visibleEntries * 2; // amount of preceeding blocks + var start = Math.max(begin - previous, 0); // max index of the future block + var finish = Math.min(end + next, Math.max(queueTracks.length - 1, 0)); // min index of the prior block + // console.log('visibleEntries=' + visibleEntries + ', next=' + next + ', previous=' + previous); + console.log('begin=' + begin + ', end=' + end + ', offset=' + offset + ', start=' + start + ', finish=' + finish + ', total=' + queueTracks.length); + console.log('count=' + parseInt(finish - start)); + + // return m('#queue-entries-container', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ + return m('#queue-entries-container', [ + m('ul#playlist-entries', { style: 'position:relative;top:' + pageY + 'px' }, [ + (queueTracks) ? queueTracks.slice(start, finish).map(function (song, idx) { + var icon = null; + var bottom = null; + if (song.webradio) { + icon = m('i.fa.fa-microphone'); + bottom = 'URL: ' + song.file; + } else if (song.artist) { + bottom = song.artist + ' - ' + song.album; + } else { + if (song.file) { + bottom = 'path: ' + song.file.split('/').pop(); + } else { + console.log(song); + } + } + return m('li', { id: 'pl-' + song.id, 'data-queuepos': start + idx, 'class': song.current ? 'active' : '' }, [ m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'), m('span.sn', [ song.title, m('span', song.timeFormatted) ]), m('span.bl', bottom) - ]); - }):null + ]); + }) : null ]), - ]); - } -}); + ]); + } +}); \ No newline at end of file diff --git a/assets/js/vendor/mithril.min.js b/assets/js/vendor/mithril.min.js index 59acfa71..fe86ac2c 100644 --- a/assets/js/vendor/mithril.min.js +++ b/assets/js/vendor/mithril.min.js @@ -1,8 +1,8 @@ /* -Mithril v0.1.26 +Mithril v0.1.27 http://github.com/lhorie/mithril.js (c) Leo Horie License: MIT */ -var m=function a(b,c){function d(a){C=a.document,D=a.location,F=a.cancelAnimationFrame||a.clearTimeout,E=a.requestAnimationFrame||a.setTimeout}function e(){var a,b=[].slice.call(arguments),c=!(null==b[1]||K.call(b[1])!=G||"tag"in b[1]||"subtree"in b[1]),d=c?b[1]:{},e="class"in d?"class":"className",f={tag:"div",attrs:{}},g=[];if(K.call(b[0])!=I)throw new Error("selector in m(selector, attrs, children) should be a string");for(;a=L.exec(b[0]);)if(""==a[1]&&a[2])f.tag=a[2];else if("#"==a[1])f.attrs.id=a[2];else if("."==a[1])g.push(a[2]);else if("["==a[3][0]){var h=M.exec(a[3]);f.attrs[h[1]]=h[3]||(h[2]?"":!0)}g.length>0&&(f.attrs[e]=g.join(" "));var i=c?b[2]:b[1];f.children=K.call(i)==H?i:b.slice(c?2:1);for(var j in d)f.attrs[j]=j==e?(f.attrs[j]||"")+" "+d[j]:d[j];return f}function f(a,b,d,e,i,k,l,m,n,o,p){if(null==i&&(i=""),"retain"===i.subtree)return k;var q=K.call(k),r=K.call(i);if(null==k||q!=r){if(null!=k)if(d&&d.nodes){var s=m-e,t=s+(r==H?i:k.nodes).length;h(d.nodes.slice(s,t),d.slice(s,t))}else k.nodes&&h(k.nodes,k);k=new i.constructor,k.tag&&(k={}),k.nodes=[]}if(r==H){for(var u=0;u\s*[^<]/g)||[]).length:K.call(T)==H?T.length:1,k[S++]=T)}if(!w){for(var u=0;u("key"in i.attrs?1:0)}if((i.tag!=k.tag||V.join()!=Object.keys(k.attrs).join()||i.attrs.id!=k.attrs.id)&&(k.nodes.length&&h(k.nodes),k.configContext&&typeof k.configContext.onunload==J&&k.configContext.onunload()),K.call(i.tag)!=I)return;var U,W=0===k.nodes.length;if(i.attrs.xmlns?o=i.attrs.xmlns:"svg"===i.tag?o="http://www.w3.org/2000/svg":"math"===i.tag&&(o="http://www.w3.org/1998/Math/MathML"),W?(U=i.attrs.is?o===c?C.createElement(i.tag,i.attrs.is):C.createElementNS(o,i.tag,i.attrs.is):o===c?C.createElement(i.tag):C.createElementNS(o,i.tag),k={tag:i.tag,attrs:V.length?g(U,i.tag,i.attrs,{},o):{},children:null!=i.children&&i.children.length>0?f(U,i.tag,c,c,i.children,k.children,!0,0,i.attrs.contenteditable?U:n,o,p):i.children,nodes:[U]},k.children&&!k.children.nodes&&(k.children.nodes=[]),"select"==i.tag&&i.attrs.value&&g(U,i.tag,{value:i.attrs.value},{},o),a.insertBefore(U,a.childNodes[m]||null)):(U=k.nodes[0],V.length&&g(U,i.tag,i.attrs,k.attrs,o),k.children=f(U,i.tag,c,c,i.children,k.children,!1,0,i.attrs.contenteditable?U:n,o,p),k.nodes.intact=!0,l===!0&&null!=U&&a.insertBefore(U,a.childNodes[m]||null)),typeof i.attrs.config==J){var X=k.configContext=k.configContext||{},Y=function(a,b){return function(){return a.attrs.config.apply(a,b)}};p.push(Y(i,[U,!W,X,k]))}}else if(typeof r!=J){var v;0===k.nodes.length?(i.$trusted?v=j(a,m,i):(v=[C.createTextNode(i)],a.nodeName.match(N)||a.insertBefore(v[0],a.childNodes[m]||null)),k="string number boolean".indexOf(typeof i)>-1?new i.constructor(i):i,k.nodes=v):k.valueOf()!==i.valueOf()||l===!0?(v=k.nodes,n&&n===C.activeElement||(i.$trusted?(h(v,k),v=j(a,m,i)):"textarea"===b?a.value=i:n?n.innerHTML=i:((1==v[0].nodeType||v.length>1)&&(h(k.nodes,k),v=[C.createTextNode(i)]),a.insertBefore(v[0],a.childNodes[m]||null),v[0].nodeValue=i)),k=new i.constructor(i),k.nodes=v):k.nodes.intact=!0}return k}function g(a,b,c,d,e){for(var f in c){var g=c[f],h=d[f];if(f in d&&h===g)"value"===f&&"input"===b&&a.value!=g&&(a.value=g);else{d[f]=g;try{if("config"===f)continue;if(typeof g==J&&0==f.indexOf("on"))a[f]=k(g,a);else if("style"===f&&null!=g&&K.call(g)==G){for(var i in g)(null==h||h[i]!==g[i])&&(a.style[i]=g[i]);for(var i in h)i in g||(a.style[i]="")}else null!=e?"href"===f?a.setAttributeNS("http://www.w3.org/1999/xlink","href",g):"className"===f?a.setAttribute("class",g):a.setAttribute(f,g):f in a&&"list"!=f&&"style"!=f&&"form"!=f&&"type"!=f?a[f]!=g&&(a[f]=g):a.setAttribute(f,g)}catch(j){if(j.message.indexOf("Invalid argument")<0)throw j}}}return d}function h(a,b){for(var c=a.length-1;c>-1;c--)if(a[c]&&a[c].parentNode){try{a[c].parentNode.removeChild(a[c])}catch(d){}b=[].concat(b),b[c]&&i(b[c])}0!=a.length&&(a.length=0)}function i(a){if(a.configContext&&typeof a.configContext.onunload==J&&a.configContext.onunload(),a.children)if(K.call(a.children)==H)for(var b=0;bb?Q.push(a)-1:b}function m(a){var b=function(){return arguments.length&&(a=arguments[0]),a};return b.toJSON=function(){return a},b}function n(){for(var a=e.redraw.strategy(),b=0;b=200&&d.status<300?a.onload({type:"load",target:d}):a.onerror({type:"error",target:d}))},a.serialize==JSON.stringify&&a.data&&"GET"!=a.method&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),a.deserialize==JSON.parse&&d.setRequestHeader("Accept","application/json, text/*"),typeof a.config==J){var e=a.config(d,a);null!=e&&(d=e)}var f="GET"!=a.method&&a.data?a.data:"";if(f&&K.call(f)!=I&&f.constructor!=b.FormData)throw"Request data should be either be a string or FormData. Check the `serialize` option in `m.request`";return d.send(f),d}var g="mithril_callback_"+(new Date).getTime()+"_"+Math.round(1e16*Math.random()).toString(36),h=C.createElement("script");b[g]=function(d){C.body.removeChild(h),a.onload({type:"load",target:{responseText:d}}),b[g]=c},h.onerror=function(){return C.body.removeChild(h),a.onerror({type:"error",target:{status:500,responseText:JSON.stringify({error:"Error making jsonp request"})}}),b[g]=c,!1},h.onload=function(){return!1},h.src=a.url+(a.url.indexOf("?")>0?"&":"?")+(a.callbackKey?a.callbackKey:"callback")+"="+g+"&"+s(a.data||{}),C.body.appendChild(h)}function A(a,b,c){if("GET"==a.method&&"jsonp"!=a.dataType){var d=a.url.indexOf("?")<0?"?":"&",e=s(b);a.url=a.url+(e?d+e:"")}else a.data=c(b);return a}function B(a,b){var c=a.match(/:[a-z]\w+/gi);if(c&&b)for(var d=0;dc&&(c=T.length);var d=!1;if(V[c]&&typeof V[c].onunload==J){var f={preventDefault:function(){d=!0}};V[c].onunload(f)}if(!d){e.redraw.strategy("all"),e.startComputation(),T[c]=a;var g=S=b,h=new b.controller;return g==S&&(V[c]=h,U[c]=b),e.endComputation(),V[c]}},e.redraw=function(a){W&&a!==!0?(new Date-X>Z||E==b.requestAnimationFrame)&&(W>0&&F(W),W=E(n,Z)):(n(),W=E(function(){W=null},Z))},e.redraw.strategy=e.prop();var $=0;e.startComputation=function(){$++},e.endComputation=function(){$=Math.max($-1,0),0==$&&e.redraw()},e.withAttr=function(a,b){return function(c){c=c||event;var d=c.currentTarget||this;b(a in d?d[a]:d.getAttribute(a))}};var _,ab,bb={pathname:"",hash:"#",search:"?"},cb=function(){};return e.route=function(){if(0===arguments.length)return ab;if(3===arguments.length&&K.call(arguments[1])==I){var a=arguments[0],c=arguments[1],d=arguments[2];cb=function(b){var f=ab=o(b);p(a,d,f)||e.route(c,!0)};var f="hash"==e.route.mode?"onhashchange":"onpopstate";b[f]=function(){ab!=o(D[e.route.mode])&&cb(D[e.route.mode])},Y=r,b[f]()}else if(arguments[0].addEventListener){{var g=arguments[0];arguments[1],arguments[2]}g.href=("pathname"!==e.route.mode?D.pathname:"")+bb[e.route.mode]+this.attrs.href,g.removeEventListener("click",q),g.addEventListener("click",q)}else if(K.call(arguments[0])==I){ab=arguments[0];var h=arguments[1]||{},i=ab.indexOf("?"),j=i>-1?t(ab.slice(i+1)):{};for(var k in h)j[k]=h[k];var l=s(j),m=i>-1?ab.slice(0,i):ab;l&&(ab=m+(-1===m.indexOf("?")?"?":"&")+l);var n=(3==arguments.length?arguments[2]:arguments[1])===!0;b.history.pushState?(Y=function(){b.history[n?"replaceState":"pushState"](null,C.title,bb[e.route.mode]+ab),r()},cb(bb[e.route.mode]+ab)):D[e.route.mode]=ab}},e.route.param=function(a){if(!_)throw new Error("You must call m.route(element, defaultRoute, routes) before calling m.route.param()");return _[a]},e.route.mode="search",e.deferred=function(){var a=new x;return a.promise=w(a.promise),a},e.deferred.onerror=function(a){if("[object Error]"==K.call(a)&&!a.constructor.toString().match(/ Error/))throw a},e.sync=function(a){function b(a,b){return function(e){return g[a]=e,b||(c="reject"),0==--f&&(d.promise(g),d[c](g)),e}}var c="resolve",d=e.deferred(),f=a.length,g=new Array(f);if(a.length>0)for(var h=0;h0&&(f.attrs[e]=g.join(" "));var i=c?b[2]:b[1];f.children=K.call(i)===H?i:b.slice(c?2:1);for(var j in d)f.attrs[j]=j===e?(f.attrs[j]||"")+" "+d[j]:d[j];return f}function f(a,b,d,e,i,k,l,m,n,o,p){if((null==i||null==i.toString())&&(i=""),"retain"===i.subtree)return k;var q=K.call(k),r=K.call(i);if(null==k||q!==r){if(null!=k)if(d&&d.nodes){var s=m-e,t=s+(r===H?i:k.nodes).length;h(d.nodes.slice(s,t),d.slice(s,t))}else k.nodes&&h(k.nodes,k);k=new i.constructor,k.tag&&(k={}),k.nodes=[]}if(r===H){for(var u=0,v=i.length;v>u;u++)K.call(i[u])===H&&(i=i.concat.apply([],i),u--);for(var w=[],x=k.length===i.length,y=0,z=1,A=2,B=3,D={},E=[],F=!1,u=0,v=k.length;v>u;u++)k[u]&&k[u].attrs&&null!=k[u].attrs.key&&(F=!0,D[k[u].attrs.key]={action:z,index:u});if(F){i.indexOf(null)>-1&&(i=i.filter(function(a){return null!=a}));for(var u=0,v=i.length;v>u;u++)if(i[u]&&i[u].attrs)if(null!=i[u].attrs.key){var L=i[u].attrs.key;D[L]=D[L]?{action:B,index:u,from:D[L].index,element:a.childNodes[D[L].index]||C.createElement("div")}:{action:A,index:u}}else E.push({index:u,element:a.childNodes[u]||C.createElement("div")});for(var M,O=Object.keys(D).map(function(a){return D[a]}),P=O.sort(function(a,b){return a.action-b.action||a.index-b.index}),Q=k.slice(),u=0;M=P[u];u++){if(M.action===z&&(h(k[M.index].nodes,k[M.index]),Q.splice(M.index,1)),M.action===A){var R=C.createElement("div");R.key=i[M.index].attrs.key,a.insertBefore(R,a.childNodes[M.index]||null),Q.splice(M.index,0,{attrs:{key:i[M.index].attrs.key},nodes:[R]})}M.action===B&&(a.childNodes[M.index]!==M.element&&null!==M.element&&a.insertBefore(M.element,a.childNodes[M.index]||null),Q[M.index]=k[M.from])}for(var u=0,v=E.length;v>u;u++){var M=E[u];a.insertBefore(M.element,a.childNodes[M.index]||null),Q[M.index]=k[M.index]}k=Q,k.nodes=[];for(var S,u=0;S=a.childNodes[u];u++)k.nodes.push(S)}for(var u=0,T=0,v=i.length;v>u;u++){var U=f(a,b,k,m,i[u],k[T],l,m+y||y,n,o,p);U!==c&&(U.nodes.intact||(x=!1),y+=U.$trusted?(U.match(/<[^\/]|\>\s*[^<]/g)||[]).length:K.call(U)===H?U.length:1,k[T++]=U)}if(!x){for(var u=0,v=i.length;v>u;u++)null!=k[u]&&w.push.apply(w,k[u].nodes);for(var V,u=0;V=k.nodes[u];u++)null!=V.parentNode&&w.indexOf(V)<0&&h([V],[k[u]]);i.length("key"in i.attrs?1:0)}if((i.tag!=k.tag||W.join()!=Object.keys(k.attrs).join()||i.attrs.id!=k.attrs.id)&&(k.nodes.length&&h(k.nodes),k.configContext&&typeof k.configContext.onunload===J&&k.configContext.onunload()),K.call(i.tag)!=I)return;var V,X=0===k.nodes.length;if(i.attrs.xmlns?o=i.attrs.xmlns:"svg"===i.tag?o="http://www.w3.org/2000/svg":"math"===i.tag&&(o="http://www.w3.org/1998/Math/MathML"),X?(V=i.attrs.is?o===c?C.createElement(i.tag,i.attrs.is):C.createElementNS(o,i.tag,i.attrs.is):o===c?C.createElement(i.tag):C.createElementNS(o,i.tag),k={tag:i.tag,attrs:W.length?g(V,i.tag,i.attrs,{},o):{},children:null!=i.children&&i.children.length>0?f(V,i.tag,c,c,i.children,k.children,!0,0,i.attrs.contenteditable?V:n,o,p):i.children,nodes:[V]},k.children&&!k.children.nodes&&(k.children.nodes=[]),"select"===i.tag&&i.attrs.value&&g(V,i.tag,{value:i.attrs.value},{},o),a.insertBefore(V,a.childNodes[m]||null)):(V=k.nodes[0],W.length&&g(V,i.tag,i.attrs,k.attrs,o),k.children=f(V,i.tag,c,c,i.children,k.children,!1,0,i.attrs.contenteditable?V:n,o,p),k.nodes.intact=!0,l===!0&&null!=V&&a.insertBefore(V,a.childNodes[m]||null)),typeof i.attrs.config===J){var Y=k.configContext=k.configContext||{},Z=function(a,b){return function(){return a.attrs.config.apply(a,b)}};p.push(Z(i,[V,!X,Y,k]))}}else if(typeof r!=J){var w;0===k.nodes.length?(i.$trusted?w=j(a,m,i):(w=[C.createTextNode(i)],a.nodeName.match(N)||a.insertBefore(w[0],a.childNodes[m]||null)),k="string number boolean".indexOf(typeof i)>-1?new i.constructor(i):i,k.nodes=w):k.valueOf()!==i.valueOf()||l===!0?(w=k.nodes,n&&n===C.activeElement||(i.$trusted?(h(w,k),w=j(a,m,i)):"textarea"===b?a.value=i:n?n.innerHTML=i:((1===w[0].nodeType||w.length>1)&&(h(k.nodes,k),w=[C.createTextNode(i)]),a.insertBefore(w[0],a.childNodes[m]||null),w[0].nodeValue=i)),k=new i.constructor(i),k.nodes=w):k.nodes.intact=!0}return k}function g(a,b,c,d,e){for(var f in c){var g=c[f],h=d[f];if(f in d&&h===g)"value"===f&&"input"===b&&a.value!=g&&(a.value=g);else{d[f]=g;try{if("config"===f)continue;if(typeof g===J&&0===f.indexOf("on"))a[f]=k(g,a);else if("style"===f&&null!=g&&K.call(g)===G){for(var i in g)(null==h||h[i]!==g[i])&&(a.style[i]=g[i]);for(var i in h)i in g||(a.style[i]="")}else null!=e?"href"===f?a.setAttributeNS("http://www.w3.org/1999/xlink","href",g):"className"===f?a.setAttribute("class",g):a.setAttribute(f,g):f in a&&"list"!==f&&"style"!==f&&"form"!==f&&"type"!==f?("input"!=f||a[f]!==g)&&(a[f]=g):a.setAttribute(f,g)}catch(j){if(j.message.indexOf("Invalid argument")<0)throw j}}}return d}function h(a,b){for(var c=a.length-1;c>-1;c--)if(a[c]&&a[c].parentNode){try{a[c].parentNode.removeChild(a[c])}catch(d){}b=[].concat(b),b[c]&&i(b[c])}0!=a.length&&(a.length=0)}function i(a){if(a.configContext&&typeof a.configContext.onunload===J&&a.configContext.onunload(),a.children)if(K.call(a.children)===H)for(var b,c=0;b=a.children[c];c++)i(b);else a.children.tag&&i(a.children)}function j(a,b,c){var d=a.childNodes[b];if(d){var e=1!=d.nodeType,f=C.createElement("span");e?(a.insertBefore(f,d||null),f.insertAdjacentHTML("beforebegin",c),a.removeChild(f)):d.insertAdjacentHTML("beforebegin",c)}else a.insertAdjacentHTML("beforeend",c);for(var g=[];a.childNodes[b]!==d;)g.push(a.childNodes[b]),b++;return g}function k(a,b){return function(c){c=c||event,e.redraw.strategy("diff"),e.startComputation();try{return a.call(b,c)}finally{_()}}}function l(a){var b=Q.indexOf(a);return 0>b?Q.push(a)-1:b}function m(a){var b=function(){return arguments.length&&(a=arguments[0]),a};return b.toJSON=function(){return a},b}function n(){for(var a,b="all"===e.redraw.strategy(),c=0;a=T[c];c++)V[c]&&e.render(a,U[c].view(V[c]),b);Y&&(Y(),Y=null),W=null,X=new Date,e.redraw.strategy("diff")}function o(a){return a.slice(cb[e.route.mode].length)}function p(a,b,c){ab={};var d=c.indexOf("?");-1!==d&&(ab=t(c.substr(d+1,c.length)),c=c.substr(0,d));for(var f in b){if(f===c)return e.module(a,b[f]),!0;var g=new RegExp("^"+f.replace(/:[^\/]+?\.{3}/g,"(.*?)").replace(/:[^\/]+/g,"([^\\/]+)")+"/?$");if(g.test(c))return c.replace(g,function(){for(var c=f.match(/:[^\/]+/g)||[],d=[].slice.call(arguments,1,-2),g=0,h=c.length;h>g;g++)ab[c[g].replace(/:|\./g,"")]=decodeURIComponent(d[g]);e.module(a,b[f])}),!0}}function q(a){if(a=a||event,!a.ctrlKey&&!a.metaKey&&2!==a.which){a.preventDefault?a.preventDefault():a.returnValue=!1;var b=a.currentTarget||this,c="pathname"===e.route.mode&&b.search?t(b.search.slice(1)):{};e.route(b[e.route.mode].slice(cb[e.route.mode].length),c)}}function r(){"hash"!=e.route.mode&&D.hash?D.hash=D.hash:b.scrollTo(0,0)}function s(a,b){var c=[];for(var d in a){var e=b?b+"["+d+"]":d,f=a[d];c.push(null!=f&&K.call(f)===G?s(f,e):encodeURIComponent(e)+"="+encodeURIComponent(f))}return c.join("&")}function t(a){for(var b=a.split("&"),c={},d=0,e=b.length;e>d;d++){var f=b[d].split("=");c[u(f[0])]=f[1]?u(f[1]):""}return c}function u(a){return decodeURIComponent(a.replace(/\+/g," "))}function v(a){var b=l(a);h(a.childNodes,R[b]),R[b]=c}function w(a){var b=e.prop();return a.then(b),b.then=function(b,c){return w(a.then(b,c))},b}function x(a,b){function c(a){l=a||j,n.map(function(a){l===i&&a.resolve(m)||a.reject(m)})}function d(a,b,c,d){if((null!=m&&K.call(m)===G||typeof m===J)&&typeof a===J)try{var f=0;a.call(m,function(a){f++||(m=a,b())},function(a){f++||(m=a,c())})}catch(g){e.deferred.onerror(g),m=g,c()}else d()}function f(){var j;try{j=m&&m.then}catch(n){return e.deferred.onerror(n),m=n,l=h,f()}d(j,function(){l=g,f()},function(){l=h,f()},function(){try{l===g&&typeof a===J?m=a(m):l===h&&"function"==typeof b&&(m=b(m),l=g)}catch(f){return e.deferred.onerror(f),m=f,c()}m===k?(m=TypeError(),c()):d(j,function(){c(i)},c,function(){c(l===g&&i)})})}var g=1,h=2,i=3,j=4,k=this,l=0,m=0,n=[];k.promise={},k.resolve=function(a){return l||(m=a,l=g,f()),this},k.reject=function(a){return l||(m=a,l=h,f()),this},k.promise.then=function(a,b){var c=new x(a,b);return l===i?c.resolve(m):l===j?c.reject(m):n.push(c),c.promise}}function y(a){return a}function z(a){if(!a.dataType||"jsonp"!==a.dataType.toLowerCase()){var d=new b.XMLHttpRequest;if(d.open(a.method,a.url,!0,a.user,a.password),d.onreadystatechange=function(){4===d.readyState&&(d.status>=200&&d.status<300?a.onload({type:"load",target:d}):a.onerror({type:"error",target:d}))},a.serialize===JSON.stringify&&a.data&&"GET"!==a.method&&d.setRequestHeader("Content-Type","application/json; charset=utf-8"),a.deserialize===JSON.parse&&d.setRequestHeader("Accept","application/json, text/*"),typeof a.config===J){var e=a.config(d,a);null!=e&&(d=e)}var f="GET"!==a.method&&a.data?a.data:"";if(f&&K.call(f)!=I&&f.constructor!=b.FormData)throw"Request data should be either be a string or FormData. Check the `serialize` option in `m.request`";return d.send(f),d}var g="mithril_callback_"+(new Date).getTime()+"_"+Math.round(1e16*Math.random()).toString(36),h=C.createElement("script");b[g]=function(d){C.body.removeChild(h),a.onload({type:"load",target:{responseText:d}}),b[g]=c},h.onerror=function(){return C.body.removeChild(h),a.onerror({type:"error",target:{status:500,responseText:JSON.stringify({error:"Error making jsonp request"})}}),b[g]=c,!1},h.onload=function(){return!1},h.src=a.url+(a.url.indexOf("?")>0?"&":"?")+(a.callbackKey?a.callbackKey:"callback")+"="+g+"&"+s(a.data||{}),C.body.appendChild(h)}function A(a,b,c){if("GET"===a.method&&"jsonp"!=a.dataType){var d=a.url.indexOf("?")<0?"?":"&",e=s(b);a.url=a.url+(e?d+e:"")}else a.data=c(b);return a}function B(a,b){var c=a.match(/:[a-z]\w+/gi);if(c&&b)for(var d=0;dk;k++)e[k]()},e.trust=function(a){return a=new String(a),a.$trusted=!0,a},e.prop=function(a){return(null!=a&&K.call(a)===G||typeof a===J)&&typeof a.then===J?w(a):m(a)};var S,T=[],U=[],V=[],W=null,X=0,Y=null,Z=16;e.module=function(a,b){var c=T.indexOf(a);0>c&&(c=T.length);var d=!1;if(V[c]&&typeof V[c].onunload===J){var f={preventDefault:function(){d=!0}};V[c].onunload(f)}if(!d){e.redraw.strategy("all"),e.startComputation(),T[c]=a;var g=S=b,h=new b.controller;return g===S&&(V[c]=h,U[c]=b),_(),V[c]}},e.redraw=function(a){W&&a!==!0?(new Date-X>Z||E===b.requestAnimationFrame)&&(W>0&&F(W),W=E(n,Z)):(n(),W=E(function(){W=null},Z))},e.redraw.strategy=e.prop();var $=0;e.startComputation=function(){$++},e.endComputation=function(){$=Math.max($-1,0),0===$&&e.redraw()};var _=function(){"none"==e.redraw.strategy()?($--,e.redraw.strategy("diff")):e.endComputation()};e.withAttr=function(a,b){return function(c){c=c||event;var d=c.currentTarget||this;b(a in d?d[a]:d.getAttribute(a))}};var ab,bb,cb={pathname:"",hash:"#",search:"?"},db=function(){};return e.route=function(){if(0===arguments.length)return bb;if(3===arguments.length&&K.call(arguments[1])===I){var a=arguments[0],c=arguments[1],d=arguments[2];db=function(b){var f=bb=o(b);p(a,d,f)||e.route(c,!0)};var f="hash"===e.route.mode?"onhashchange":"onpopstate";b[f]=function(){bb!=o(D[e.route.mode])&&db(D[e.route.mode])},Y=r,b[f]()}else if(arguments[0].addEventListener){{var g=arguments[0];arguments[1],arguments[2]}g.href=("pathname"!==e.route.mode?D.pathname:"")+cb[e.route.mode]+this.attrs.href,g.removeEventListener("click",q),g.addEventListener("click",q)}else if(K.call(arguments[0])===I){bb=arguments[0];var h=arguments[1]||{},i=bb.indexOf("?"),j=i>-1?t(bb.slice(i+1)):{};for(var k in h)j[k]=h[k];var l=s(j),m=i>-1?bb.slice(0,i):bb;l&&(bb=m+(-1===m.indexOf("?")?"?":"&")+l);var n=(3===arguments.length?arguments[2]:arguments[1])===!0;b.history.pushState?(Y=function(){b.history[n?"replaceState":"pushState"](null,C.title,cb[e.route.mode]+bb),r()},db(cb[e.route.mode]+bb)):D[e.route.mode]=bb}},e.route.param=function(a){if(!ab)throw new Error("You must call m.route(element, defaultRoute, routes) before calling m.route.param()");return ab[a]},e.route.mode="search",e.deferred=function(){var a=new x;return a.promise=w(a.promise),a},e.deferred.onerror=function(a){if("[object Error]"===K.call(a)&&!a.constructor.toString().match(/ Error/))throw a},e.sync=function(a){function b(a,b){return function(e){return g[a]=e,b||(c="reject"),0===--f&&(d.promise(g),d[c](g)),e}}var c="resolve",d=e.deferred(),f=a.length,g=new Array(f);if(a.length>0)for(var h=0;h Date: Sat, 13 Dec 2014 12:00:50 +0100 Subject: [PATCH 16/80] added Git branch in DEV section --- app/dev_ctl.php | 1 + app/libs/runeaudio.php | 2 ++ app/templates/dev.php | 7 +++++++ command/rune_SY_wrk | 4 ++++ 4 files changed, 14 insertions(+) diff --git a/app/dev_ctl.php b/app/dev_ctl.php index 8bee4b72..b361e581 100755 --- a/app/dev_ctl.php +++ b/app/dev_ctl.php @@ -87,6 +87,7 @@ $template->debug = $redis->get('debug'); $template->playerid = $redis->get('playerid'); $template->opcache = $redis->get('opcache'); +$template->gitbranch = $redis->hGet('git', 'branch'); // debug // var_dump($template->dev); // var_dump($template->debug); diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index a9ecb1c4..473f57a9 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -1383,6 +1383,7 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) } //// if ($scanwifi) sysCmdAsync('/var/www/command/refresh_nics'); // check wpa_supplicant auto-start and purge interface list + /* TODO marked for deletion $wpa_supplicant_start = sysCmd("ls -lah /etc/systemd/system/multi-user.target.wants/wpa_supplicant@*.service | cut -d '@' -f 2 | cut -d '.' -f 1"); $disable_wpa_supplicant = array_diff($wpa_supplicant_start, $interfaces); if (!empty($disable_wpa_supplicant)) { @@ -1390,6 +1391,7 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) unlink('/etc/systemd/system/multi-user.target.wants/wpa_supplicant@'.$interface_name.'.service'); } } + */ $transaction->exec(); break; case 'getnics': diff --git a/app/templates/dev.php b/app/templates/dev.php index 585fc5b7..f3bcc7ef 100755 --- a/app/templates/dev.php +++ b/app/templates/dev.php @@ -50,6 +50,13 @@ Current detected HW fingerprint. +
    + +
    + + Current Git branch. +
    +
    "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close"); -transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height();a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height();a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var queueEntryHeight=49,pageY=0,pageHeight=0;window.onscroll=function(a){pageY=Math.max(a.pageY||window.pageYOffset,0),pageHeight=window.innerHeight,m.redraw()},$(window).trigger("scroll"),m.module(document.getElementById("playlist-entries-container"),{controller:function(){},view:function(){var a=Math.ceil(pageY/queueEntryHeight)||0,b=a+(pageHeight/queueEntryHeight||2),c=pageY%queueEntryHeight;return m("#pl-count",queueTracks.length),m("div",{style:"height:"+queueTracks.length*queueEntryHeight+"px;position:relative;top:"+-c+"px"},[m("ul#playlist-entries.playlist",{style:"position:relative;top:"+pageY+"px"},[queueTracks?queueTracks.slice(a,b).map(function(b,c){var d=null,e=null;return b.webradio?(d=m("i.fa.fa-microphone"),e="URL: "+b.file):e=b.artist?b.artist+" - "+b.album:"path: "+b.filename.split("/").pop(),m("li",{id:"pl-"+b.id,"data-queuepos":a+c,"class":b.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[b.title,m("span",b.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0)}function customScroll(a,b,c){isCustomScroll=!0,"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),$.scrollTo(f>0?g:0,c),isCustomScroll=!1}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b() +}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()-160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=pageY%listEntryHeight,d=2,e=Math.max(a-visibleEntries*d,0),f=Math.min(b+visibleEntries*d,Math.max(queueTracks.length-1,0)),g=e*listEntryHeight;return console.log("visible:"+a+"->"+b+"("+visibleEntries+"), loaded:"+e+"->"+f+"("+parseInt(f-e)+") of "+queueTracks.length+", offset:"+c+", offsetUL:"+g+"px"),m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+g+"px"},[queueTracks?queueTracks.slice(e,f).map(function(a,b){var c=null,d=null;return a.webradio?(c=m("i.fa.fa-microphone"),d="URL: "+a.file):a.artist?d=a.artist+" - "+a.album:a.file?d="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":e+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",d)])}):null])])}}); \ No newline at end of file diff --git a/assets/less/runeui-custom.less b/assets/less/runeui-custom.less index 59f5e686..fe99d7f0 100644 --- a/assets/less/runeui-custom.less +++ b/assets/less/runeui-custom.less @@ -558,7 +558,7 @@ html, body { .list-li { display: block; // position: relative; - height: 49px; + height: 50px; line-height: 19px; // margin: 0; // background: @body-bg; @@ -720,6 +720,9 @@ html, body { font-size: 12px; color: lighten(@brand-alt, 20%); } +} +#playlist-entries-container { + position: relative; } #pl-editor { .list-main; From c629dbae9d72ef83966e15d9dc865aa2bc17ab02 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sat, 13 Dec 2014 18:45:00 +0100 Subject: [PATCH 19/80] Fixed pagination offset --- assets/js/runeui.js | 7 ++++--- assets/js/runeui.min.js | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 927b79ae..d1c9f4a9 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -237,7 +237,6 @@ function customScroll(list, destination, speed) { if (typeof(speed) === 'undefined') { speed = 500; } - var entryheight = 50; var centerheight = parseInt($(window).height()/2); var scrolltop = $(window).scrollTop(); var scrollcalc = 0; @@ -2333,12 +2332,14 @@ if ($('#section-index').length) { }); $('#pl-prevPage').click(function(){ var scrollTop = $(window).scrollTop(); - var scrolloffset = scrollTop - $(window).height() - 160; + var scrolloffset = scrollTop - $(window).height() + 160; + // console.log('scrolloffset = ', scrolloffset); $.scrollTo(scrolloffset , 500); }); $('#pl-nextPage').click(function(){ var scrollTop = $(window).scrollTop(); var scrolloffset = scrollTop + $(window).height() - 160; + // console.log('scrolloffset = ', scrolloffset); $.scrollTo(scrolloffset , 500); }); $('#pl-lastPage').click(function(){ @@ -2734,7 +2735,7 @@ m.module(document.getElementById('playlist'), { // var offsetUL = pageY - (listEntryHeight * (begin - start)); var offsetUL = start * listEntryHeight; // console.log('visibleEntries=' + visibleEntries + ', next=' + next + ', previous=' + previous); - console.log('visible:' + begin + '->' + end + '(' + visibleEntries + '), loaded:' + start + '->' + finish + '(' + parseInt(finish - start) + ') of ' + queueTracks.length + ', offset:' + offset + ', offsetUL:' + offsetUL + 'px'); + // console.log('visible:' + begin + '->' + end + '(' + visibleEntries + '), loaded:' + start + '->' + finish + '(' + parseInt(finish - start) + ') of ' + queueTracks.length + ', offset:' + offset + ', offsetUL:' + offsetUL + 'px'); // return m('#queue-entries-container', {style: 'height:' + (queueTracks.length * listEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ return m('#queue-entries-container', [ diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index ff56046c..6060de74 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0)}function customScroll(a,b,c){isCustomScroll=!0,"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),$.scrollTo(f>0?g:0,c),isCustomScroll=!1}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b() -}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()-160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=pageY%listEntryHeight,d=2,e=Math.max(a-visibleEntries*d,0),f=Math.min(b+visibleEntries*d,Math.max(queueTracks.length-1,0)),g=e*listEntryHeight;return console.log("visible:"+a+"->"+b+"("+visibleEntries+"), loaded:"+e+"->"+f+"("+parseInt(f-e)+") of "+queueTracks.length+", offset:"+c+", offsetUL:"+g+"px"),m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+g+"px"},[queueTracks?queueTracks.slice(e,f).map(function(a,b){var c=null,d=null;return a.webradio?(c=m("i.fa.fa-microphone"),d="URL: "+a.file):a.artist?d=a.artist+" - "+a.album:a.file?d="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":e+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",d)])}):null])])}}); \ No newline at end of file +}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=2,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file From d119e981798406bd67ede7373b61cc4f88db6ba1 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Sat, 13 Dec 2014 21:40:40 +0100 Subject: [PATCH 20/80] fixed PHP OPcache functions --- app/libs/runeaudio.php | 46 ++++++++++++++++---------------- command/cachectl.php | 2 +- command/cmd_async | 57 ++++++++++++++++++++++++++++++++++++++++ command/rune_SY_wrk | 15 ++++------- command/ui_notify.php | 33 +++-------------------- db/redis_datastore_setup | 1 - 6 files changed, 90 insertions(+), 64 deletions(-) create mode 100755 command/cmd_async diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 1e4b1f60..e9b39671 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -750,11 +750,17 @@ function sysCmd($syscmd) return $output; } -function sysCmdAsync($syscmd) { -exec($syscmd." > /dev/null 2>&1 &", $output); -// runelog('sysCmdAsync($str)',$syscmd); -// runelog('sysCmdAsync() output:',$output); -return $output; +function sysCmdAsync($syscmd, $waitsec = null) { + if (isset($waitsec)) { + $cmdstr = "/var/www/command/cmd_async ".base64_encode($syscmd); + } else { + $cmdstr = "/var/www/command/cmd_async ".base64_encode($syscmd); + } + exec($cmdstr." > /dev/null 2>&1 &", $output); + runelog('sysCmdAsync($cmdstr) decoded', $syscmd, __FUNCTION__); + runelog('sysCmdAsync($cmdstr) encoded', $cmdstr, __FUNCTION__); + runelog('sysCmdAsync() output:', $output, __FUNCTION__); + return $output; } function getMpdDaemonDetalis() @@ -1298,29 +1304,24 @@ function wrk_backup($bktype) function wrk_opcache($action, $redis) { +// debug +runelog('wrk_opcache ', $action); switch ($action) { case 'prime': - if ($redis->get('opcache') == 1) { - $ch = curl_init('http://localhost/command/cachectl.php?action=prime'); - curl_exec($ch); - curl_close($ch); - } - runelog('wrk_opcache ', $action); + opcache_reset(); + if ($redis->get('opcache') == 1) sysCmd('curl http://127.0.0.1/command/cachectl.php?action=prime'); break; case 'forceprime': - $ch = curl_init('http://localhost/command/cachectl.php?action=prime'); - curl_exec($ch); - curl_close($ch); - runelog('wrk_opcache ', $action); + opcache_reset(); + sysCmd('curl http://127.0.0.1/command/cachectl.php?action=prime'); break; case 'reset': - $ch = curl_init('http://localhost/command/cachectl.php?action=reset'); - curl_exec($ch); - curl_close($ch); - runelog('wrk_opcache ', $action); + // sysCmd('curl http://127.0.0.1/clear'); + // reset cache + OpCacheCtl('reset', '/srv/http/'); + opcache_reset(); break; case 'enable': - wrk_opcache('reset'); // opcache.ini $file = '/etc/php/conf.d/opcache.ini'; $newArray = wrk_replaceTextLine($file, '', 'opcache.enable', 'opcache.enable=1', 'zend_extension', 1); @@ -1328,10 +1329,9 @@ function wrk_opcache($action, $redis) $fp = fopen($file, 'w'); fwrite($fp, implode("", $newArray)); fclose($fp); - runelog('wrk_opcache ', $action); + $redis->set('opcache', 1); break; case 'disable': - wrk_opcache('reset'); // opcache.ini // -- REWORK NEEDED -- $file = '/etc/php/conf.d/opcache.ini'; @@ -1340,7 +1340,7 @@ function wrk_opcache($action, $redis) $fp = fopen($file, 'w'); fwrite($fp, implode("", $newArray)); fclose($fp); - runelog('wrk_opcache ', $action); + $redis->set('opcache', 0); break; } } diff --git a/command/cachectl.php b/command/cachectl.php index 0cb6ae97..7f442eb0 100755 --- a/command/cachectl.php +++ b/command/cachectl.php @@ -44,9 +44,9 @@ OpCacheCtl('primeall', '/srv/http/'); break; case 'reset': + runelog('cacheCTL RESET'); OpCacheCtl('reset', '/srv/http/'); opcache_reset(); - runelog('cacheCTL RESET'); echo "PHP OPCACHE CLEARED"; break; case 'debug': diff --git a/command/cmd_async b/command/cmd_async new file mode 100755 index 00000000..a7dfc1bf --- /dev/null +++ b/command/cmd_async @@ -0,0 +1,57 @@ +#!/usr/bin/php +. + * + * file: command/cmd_async {cmd} {usec wait} + * version: 1.3 + * coder: Simone De Gregori + * + */ +// common include +ini_set('display_errors', '1'); +// ini_set('error_reporting', -1); +ini_set('error_log', '/var/log/runeaudio/cmd_async.log'); +// Connect to Redis backend +$redis = new Redis(); +$redis->connect('/tmp/redis.sock'); +include('/var/www/app/libs/runeaudio.php'); + +if (isset($argv[1])) { +$argv[1] = base64_decode($argv[1]); + if (isset($argv[2])) { + settype($argv[2], 'integer'); + echo "wait for ".$argv[2]." seconds\n"; + sleep($argv[2]); + } + echo "execute command: ".$argv[1]."\n"; + $output = sysCmd($argv[1]); + echo "command response:\n"; + foreach ($output as $line) echo "\t".$line."\n"; +} else { + echo "cmd_async {cmd} {sec wait}\n"; +} diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 98dc3251..40514374 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -226,14 +226,11 @@ sysCmd("/var/www/command/orion_optimize.sh ".$redis->get('orionprofile')." ".$re // start php-fpm sysCmd('systemctl start php-fpm'); // PHP 5.5 OPCache -/* if ($redis->get('dev') === '0') { // prime PHP OPCache runelog('prime PHP OPCache'); - // wrk_opcache('prime',$redis); - sysCmdAsync("curl -s -X GET 'http://localhost/command/cachectl.php?action=prime'"); + sysCmdAsync("curl -s -X GET 'http://127.0.0.1/command/cachectl.php?action=prime'"); } -*/ // mount all sources wrk_sourcemount($redis, 'mountall'); runelog('--- NORMAL STARTUP'); @@ -547,18 +544,16 @@ $redis->pconnect('/tmp/redis.sock'); $redis->sAdd('w_lock', $jobID); // Restart PHP service if ($job->action === 'enable') { - wrk_opcache('enable'); + wrk_opcache('enable', $redis); runelog('PHP 5.5 OPcache enabled'); - sysCmd('systemctl restart php-fpm'); + sysCmdAsync('systemctl restart php-fpm', 5); // wrk_opcache('forceprime'); - $redis->set('opcache', 1); // send notfy to UI ui_notify_async('PHP OpCache', 'cache enabled', $jobID); } else { - wrk_opcache('disable'); + wrk_opcache('disable', $redis); runelog('PHP 5.5 OPcache disabled'); - sysCmd('systemctl restart php-fpm'); - $redis->set('opcache', 0); + sysCmdAsync('systemctl restart php-fpm', 5); // send notfy to UI ui_notify_async('PHP OpCache', 'cache disabled', $jobID); } diff --git a/command/ui_notify.php b/command/ui_notify.php index 2f91eb40..d4fa8b4a 100755 --- a/command/ui_notify.php +++ b/command/ui_notify.php @@ -36,35 +36,10 @@ ini_set('display_errors', '1'); ini_set('error_reporting', -1); ini_set('error_log','/var/log/runeaudio/ui_notify.log'); - -// ---- functions ----- -// push UI update to NGiNX channel -function ui_render($channel, $data) -{ - // runelog('ui_render channel: '.$channel.', data: ',$data); - curlPost('http://127.0.0.1/pub?id='.$channel,$data); -} - -function curlPost($url,$data,$proxy = null) -{ -$ch = curl_init($url); - if (isset($proxy)) { - $proxy['user'] === '' || curl_setopt($ch, CURLOPT_PROXYUSERPWD, $proxy['user'].':'.$proxy['pass']); - curl_setopt($ch, CURLOPT_PROXY, $proxy['host']); - //runelog('cURL proxy HOST: ',$proxy['host']); - //runelog('cURL proxy USER: ',$proxy['user']); - //runelog('cURL proxy PASS: ',$proxy['pass']); - } - curl_setopt($ch, CURLOPT_TIMEOUT, 2); - curl_setopt($ch, CURLOPT_POST, 1); - curl_setopt($ch, CURLOPT_POSTFIELDS, $data); - curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); - curl_setopt($ch, CURLOPT_HEADER, 0); // DO NOT RETURN HTTP HEADERS - curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // RETURN THE CONTENTS OF THE CALL - $response = curl_exec($ch); - curl_close($ch); - return $response; -} +// Connect to Redis backend +$redis = new Redis(); +$redis->connect('/tmp/redis.sock'); +include('/var/www/app/libs/runeaudio.php'); // ---- end functions ----- if (isset($argv[2]) && !isset($argv[3])) { // Connect to Redis backend diff --git a/db/redis_datastore_setup b/db/redis_datastore_setup index 43c9dd30..dc0e90bb 100755 --- a/db/redis_datastore_setup +++ b/db/redis_datastore_setup @@ -156,7 +156,6 @@ function redisDatastore($redis,$action) { $transaction = $redis->multi(); // RuneAudio Libs & config $transaction->sAdd('php_opcache_prime', '/srv/http/app/config/config.php'); - $transaction->sAdd('php_opcache_prime', '/srv/http/app/libs/runeaudio.php'); // RuneAudio Controllers $transaction->sAdd('php_opcache_prime', '/srv/http/index.php'); $transaction->sAdd('php_opcache_prime', '/srv/http/db/index.php'); From 02e275ef2fb48ba3f1a1d703a66cdf09a22e54cc Mon Sep 17 00:00:00 2001 From: Orion1 Date: Sat, 13 Dec 2014 21:49:30 +0100 Subject: [PATCH 21/80] fixed git branch detection --- command/rune_SY_wrk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 40514374..562c054f 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -78,7 +78,7 @@ if ($arch_db !== $arch) { $playerid_db = ''; } // check git branch -$gitbranch = sysCmd("git branch | grep \"*\" | cut -d ' ' -f 2"); +$gitbranch = sysCmd("cd /var/www/ ; git branch | grep \"*\" | cut -d ' ' -f 2"); runelog('GIT BRANCH: ', $gitbranch[0]); $redis->hSet('git', 'branch', $gitbranch[0]); if ($playerid_db === '') { From e3bd3085f541e2230a1addf8cc83970446ac817b Mon Sep 17 00:00:00 2001 From: hondagx35 Date: Sun, 14 Dec 2014 01:29:32 +0100 Subject: [PATCH 22/80] fixed mpd.conf acard_name setting --- app/libs/runeaudio.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 2112ac85..938714a2 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -2121,7 +2121,7 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) if (isset($sub_interface)) { $output .="\tname \t\t\"".$card_decoded->name."\"\n"; } else { - $output .= $main_acard_name; + $output .="\tname \t\t\"".$main_acard_name."\"\n"; } $output .="\ttype \t\t\"".$card_decoded->type."\"\n"; $output .="\tdevice \t\t\"".$card_decoded->device."\"\n"; From 69f90017fcb8644dd415b01d1cc55d50e93db4d0 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sun, 14 Dec 2014 19:52:02 +0100 Subject: [PATCH 23/80] Further attempts to improve queue rendering --- assets/css/runeui.css | 2 +- assets/img/list-bg.gif | Bin 0 -> 5558 bytes assets/js/runeui.js | 30 ++++++++++++++---------- assets/js/runeui.min.js | 4 ++-- assets/js/vendor/jquery.scrollTo.min.js | 8 +++---- assets/less/runeui-custom.less | 6 +++-- 6 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 assets/img/list-bg.gif diff --git a/assets/css/runeui.css b/assets/css/runeui.css index 9ba5bb18..5a224c87 100644 --- a/assets/css/runeui.css +++ b/assets/css/runeui.css @@ -7,4 +7,4 @@ * * Copyright 2013 bootstrap-select * Licensed under the MIT license - */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file + */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}#playlist{background:transparent url('../img/list-bg.gif') repeat 0 30px}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file diff --git a/assets/img/list-bg.gif b/assets/img/list-bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..a1aba37c37541eb0c47f6350b2c739debe380d4e GIT binary patch literal 5558 zcmaJ^cU)6v+tzAp7UXT!S|^D57Dyl>plqsOg(N_=TD1;}5XlaZu$Rcnj>z5{vLNgY zVUq>8CxQ!wBoH?$Xg=)sw%_;1*YEkA-#O2?uIs+<^IYfr&N<}yvz@))%&HRTg_SEd z7@O(!`t5q~39ny_-Ti2O%U37Yh#)_I0)}RM4iktYJDcb_r6$I>0B4iqwqCovg4{4z zoJUj$=GQ3iqyA9@fBOIvR~KWa2!{w#5D7!`Gman;$yA33XA{2w$~la~a{tRT!o>Jb z2#w%uvj5A1@t2rxln{)ut);bv|86TQ9 z{DKfxmb<@{^cT>}>;H$6NPnZLv?G}R$@l*hrXGz9!XS=dsFctUf6Ov`$Cpq+4sIbB zKN=n{F+rO+r;EG5X;?bp4=rpIyQ07^L3>`%OxmxCvnO7kQ8V?5oRO_mib zakv17eRkINcKh59*jd}!Sy>&lIdH(%#(lrrK`U!3n?3v8Z2#iAQ~X0o7&7fIZovO= z-TsmL#R{aL<;d=s5L_50;O7tu$@tHb9dQ4gi~T?9{f8Uy&$;aXM=oMH8N`>3{a+jX z*VM9mzI6Y#?egGn<73FnZVy?u^-BHcPfLp*KfGUf_x8=}S1(`a=I68;_3X^^XVXug zJbv_WYVyIv{d;%s+`e`5#`SAguZ)k4s+0=3Y-D(7aG<}hSK8Cv)!EVB*4onC)Ywp8 zC#kIwi-ZDxbya0Wd0A;maZzDGeqL@)c2;Ia`sK7sJT8aLVlwEdDalER7ZWbT$Hm4( zM@2@2hlSFpA;CcuGKomQE`SYLBTpMXu)RgMwJnPVJmvE@9iO=4nuVnvJ@f}tJC76C2zm~`O?GGIJz%4m zz2`|>BqLYQF26hb0l3NB0r@*VikTnqD~Q_S^1()<$cW}cnjPKeVQ1< zE)aLACbUbCtrpH+XGpP}!kX^U2XmhcwpqG(pC!j}i)wquCg(pJ8X;VLd@1p~Vu^Ho zN~eeJF6m8J4c_EL-(A|D4B6}u1F$L^WUPbz-bJ@6ALi({I7Tf2_EgBycB1l}7<(!e znebB`F+l4oRjv);UKhiTS4gX51J8P3O(?)Qu5}of53$hj75F8c#-p#ZX z-Ksg=8TARYSA3^FK$+*v+B*Uj1|ne2{P{P+oMSNE_l3B1{b zZCC$zh`re{4r1T%RGtAl)x)-Ld^TF(82uUI&@^+k0+sK=acEZG6rbvhGjMFt-fbe> z@8LMM&OhjiUi@s})b`@hAZxQL*Qx#0v?|{*-q5+@&Fl@)DJj>v^WEG;XSCkXrR)96 zr^GfC%D-F(jd;Ws*s# z?U+{(Bt4%&#JYY%6tRBTe0yMnLT{-gHjcS~Nln+hJ8#wBI?E!p+#@SVt&?$Ja@%7r ziroIJh(+#D*DA@K^F3fn*Q+rUrTg6^i_-IPUP+OD{tOQ4{R)Z>>ifos9n=p(sDcIz zT_M4P-}#_}hrah^2M=$esDekfUH^$BGvT2_tH0+AG)F6B!WZWzKL0ISAu*oRhX!ul|-XP-PMW}bgqZA`<#A7C6 zEaC~*)iCnuWgqXz=`6i3H}Y8?Wi0Y}QM_T)Oc~ERYPPDF8>JRX#-cQ}Qp0F%!?^b% zFMNs{J>Q`li`IqTHjH`E5A}(8Ic&s>d8I&%$GjeMg~qt&S!D$110aJgt`nDhjiC2I@Ii@Nv?Xg?0sa4C1|{u;mjZq0{p*B5$#7yR z*cUMHgCZ!!MqFxu+0eU19hB;%Ern9U2aG|%ba!~!w>kf>&&ZGGy-NA!%%4#SSB&+yfbMIYV5r3&D`1@geC2+KL}tfr?+4 zAsH3$N;4mZ;;8VNcNDP_<_lDwP#iH6i7PEA4CQHcNOqUD5)ltn{Q;up48p6dcnnp5 zIW<>Btgz>C4vDm}XyN zTxH{Fd&v6$e;| zPL4BgH3>s&h$PXeDbVdUMQAOpMs!BUJbuF|R1z~M^3@|Vxd{E3~Q>esKNQ5e(M#6HH%4e@WbHycNAeQ zO*J(n3hVxaI;^#8u7(m1o_GifZyU6z4d$^Xo|=cZtMsH=YBBi13^Kgq2C0l7VLi~| zTjOue)rL#KlP{RzT~93}k>jk%H^T64ElCnR1)h4Z2=94QBZ<|qrk2#<(xo{`ydM1U z9x1$cwPjs`*Y^)s!y@`1I!-MFIL3hPRn|R z5Bu>tQN)nIv5w^ndGdpVF=SI)&!MoNY|%uFIL+7d;vr9s!I3g|%Z4-_`{_W#kyG zwy{vhe(t1+9FLiAEMBXa{s|m)C5fxh7ehHS?y#tfr=u0>BR&9_SR1}`pvV;-(XwDm!`FOpy}k06w` z0VBhgbX3gab&|Fr1o!33XVFi#=bX?_e-&DY2XVH|7>&1p|`KVa+QAx*53HPm- z5UV+@>$oj7d{;LTJQINEyu0w@yCzZW9Ffv_f68#7O&L2+lXO1NaTmHYvAP&t=ak;? zeJ?ofMG_+B`!VkOL6{3Uh0^uJ2>L;WihGqI>6%9HKBx$BuM2ct&t0J(udw3YR3N%% zeRv;VSj4>*Q(~KrKo{>QfbA; zT;?UxPdc7nzod!RFX^Ou{qirQ>4jAu7rw?`SVO-62wC4&XUnNGjtw+A@fg7_h4Mzz{sXEa`}vW8KZE9Q4C;~nlj7v z9?VKCvzpEn@R=eRvu1`Vu>)nAvKsjjby!v_oz>1~b;?-XGb|~9-Dk=k@L&&N*&}qe zoX=Lu*rO-THvu?Tf1r(daBgBbx9Oa_e9nCt=fMnT3c!72%6;O&oyKyX)48*JuEx~v z+6-5RrD#oguRVBgvAhL3?*pH=DC2#a;pqXFR+?Q}<$39A+@&>)OF#keh3t~SNh}DM z_N`gkTFz7w2gwa&GNLZvuQ@a%iGN^@9@053wK%j?2?(_@`1Q*1fSHHQGJo~V zJci3W&d59|$UG&_JTsf=3(P7?$nf{f60gq+WMtt4Sp<0&X*P=j%nmlorg~>PubPo35afyEc{Q_n5@3G4S$?Bue){#?Rz|+$SbnEGzk4=c z3M}X|D;V%B7{V2dFbd>?0;RlQbhcm|SO`kXzwTKWv99noqwubv@V>n8!EE6au;`Il z(G$<2X<~bC99An zU*k)#-xLFdCD`y119b@$RQj!X=~`szdVJ{yX6Z&@>1IXgR&}WnsBHW12f)a(T~UrE z%rY}!8B9@Tp)Ny!%B{@Ht&!!n`0{Q~5ur#StXcl_1BvR*MU6;NGhWon z6txRQoeEL6TJ#`I*k>+Ycqtmfi$|DZxlpWBh)31paZt@w^P20(nw$8V+d}bxu;#vc z+Z}by6sY!*dF>Nq?KHmjIkR?FSgTRg&Z%p4Ajv~n&1mks_7u1 z=@6^QQ`CggE1SGDO+Mh}!?5OGQO!{+n~t-ZSNzg^O4)oy)9edw@q@MaqgpV8mOxeu zPSiqBw)~LaOo?tF!CI-P)=)xgIIA^M)Ecd9jn%ZqgWD2dZHc1HAVQk~s*NFPV=3D> znl>J|Jq^~Lj%v>&v}d#0b4Bfy;cbPEl6-JSDXgO$)lo_4sAhEtL>(e!M~$XK0`9CQ z_!gl$2h2NLS)J{o&Q4`#x297H?&^be4WPP)2wfwru3N`CmC-`ErfVGBeHGSy9o2o4 z(0!ZLeOJ_dU)lXY(>(<xq3E*nJzteVbK% zTeW>gkpAuP{s~~;E_B%rcE6dpAExTJ(DoxB16J?>YxICEabO>N;4rq|5mIcg9dLyV z?uQS$p$88V2M@6aJ;j44)u5MlP&qts7+vUt9y&%GI?f(CDIPkd8aksL@`Vih!H50P z!-sYa1;*rK#KQ#DFiAU1fs6#hN2utLP~u29dn8gkGL|?TyCo+YB1?eF64A0`qAZmy zV~Axem5ig6@gQ>4qLs}=Wh-0RE>?C<^a-^}L%FgKt{OnAhKQ;Wwn{EmDOIXbt!f-H+Wt{_ reTjROIC`5sdRIJpUp4wbJ30j!djubQf*zZW$-KcHyK-X13djEfL?ZR( literal 0 HcmV?d00001 diff --git a/assets/js/runeui.js b/assets/js/runeui.js index d1c9f4a9..3b8c436f 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -227,12 +227,12 @@ function setQueuePos() { queueTracks[GUI.currentqueuepos].current = false; GUI.currentqueuepos = parseInt(GUI.json.song); queueTracks[GUI.currentqueuepos].current = true; + m.redraw(); } } // custom scrolling function customScroll(list, destination, speed) { - isCustomScroll = true; // console.log('list = ' + list + ', destination = ' + destination + ', speed = ' + speed); if (typeof(speed) === 'undefined') { speed = 500; @@ -258,8 +258,9 @@ function customScroll(list, destination, speed) { // console.log('scrolltop = ', scrolltop); // console.log('scrollcalc = ', scrollcalc); // console.log('scrolloffset = ', scrolloffset); - $.scrollTo((scrollcalc >0? scrolloffset:0), speed); - isCustomScroll = false; + isCustomScroll = true; + $.scrollTo((scrollcalc > 0 ? scrolloffset : 0), speed, {onAfter: function(){ m.redraw(); isCustomScroll = false; }}); + } // [!] scrolling debug purpose only @@ -2328,7 +2329,8 @@ if ($('#section-index').length) { }); $('#pl-firstPage').click(function(){ - $.scrollTo(0 , 500); + isCustomScroll = true; + $.scrollTo(0 , 500, {onAfter: function(){ m.redraw(); isCustomScroll = false; }}); }); $('#pl-prevPage').click(function(){ var scrollTop = $(window).scrollTop(); @@ -2340,10 +2342,12 @@ if ($('#section-index').length) { var scrollTop = $(window).scrollTop(); var scrolloffset = scrollTop + $(window).height() - 160; // console.log('scrolloffset = ', scrolloffset); + $.scrollTo(scrolloffset , 500); }); $('#pl-lastPage').click(function(){ - $.scrollTo('100%', 500); + isCustomScroll = true; + $.scrollTo('100%', 500, {onAfter: function(){ m.redraw(); isCustomScroll = false; }}); }); // open tab from external link @@ -2713,12 +2717,14 @@ window.resize = function() { visibleEntries = (Math.floor(pageHeight / listEntryHeight || 0 + 2)); }; window.onscroll = function(e) { - pageY = Math.max(window.pageYOffset, 0); // the pixels the current document has been scrolled from the upper left corner of the window - var diff = Math.abs(pageOldY - (pageY - pageHeight)); - // console.log('pageY=' + pageY + ', pageOldY=' + pageOldY + ', diff=' + diff + ', pageHeight=' + pageHeight); - if (diff > pageHeight) { - pageOldY = pageY; - m.redraw(); + if (!isCustomScroll) { + pageY = Math.max(window.pageYOffset, 0); // the pixels the current document has been scrolled from the upper left corner of the window + var diff = Math.abs(pageOldY - (pageY - pageHeight)); + // console.log('pageY=' + pageY + ', pageOldY=' + pageOldY + ', diff=' + diff + ', pageHeight=' + pageHeight); + if (diff > pageHeight) { + pageOldY = pageY; + m.redraw(); + } } }; // $(window).trigger('scroll'); @@ -2729,7 +2735,7 @@ m.module(document.getElementById('playlist'), { var begin = Math.floor(pageY / listEntryHeight) || 0; // first visible entry var end = begin + visibleEntries; // last visible entry var offset = pageY % listEntryHeight; - var buffer = 2; // amount of preceeding and following blocks to load + var buffer = 4; // amount of preceeding and following blocks to load var start = Math.max(begin - visibleEntries * buffer, 0); // index of the first block var finish = Math.min(end + visibleEntries * buffer, Math.max(queueTracks.length - 1, 0)); // index of the last block // var offsetUL = pageY - (listEntryHeight * (begin - start)); diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index 6060de74..e4a7ac44 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ -function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0)}function customScroll(a,b,c){isCustomScroll=!0,"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),$.scrollTo(f>0?g:0,c),isCustomScroll=!1}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b() -}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){a.scrollTo(0,500)}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){a.scrollTo("100%",500)});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=2,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close"); +transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){if(!isCustomScroll){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())}},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=4,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file diff --git a/assets/js/vendor/jquery.scrollTo.min.js b/assets/js/vendor/jquery.scrollTo.min.js index 296ba0ef..d9f9b159 100644 --- a/assets/js/vendor/jquery.scrollTo.min.js +++ b/assets/js/vendor/jquery.scrollTo.min.js @@ -1,7 +1,7 @@ /** - * Copyright (c) 2007-2012 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com - * Dual licensed under MIT and GPL. + * Copyright (c) 2007-2014 Ariel Flesler - afleslergmailcom | http://flesler.blogspot.com + * Licensed under MIT * @author Ariel Flesler - * @version 1.4.4 + * @version 1.4.14 */ -;(function($){var h=$.scrollTo=function(a,b,c){$(window).scrollTo(a,b,c)};h.defaults={axis:'xy',duration:parseFloat($.fn.jquery)>=1.3?0:1,limit:true};h.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(e,f,g){if(typeof f=='object'){g=f;f=0}if(typeof g=='function')g={onAfter:g};if(e=='max')e=9e9;g=$.extend({},h.defaults,g);f=f||g.duration;g.queue=g.queue&&g.axis.length>1;if(g.queue)f/=2;g.offset=both(g.offset);g.over=both(g.over);return this._scrollable().each(function(){if(e==null)return;var d=this,$elem=$(d),targ=e,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}$.each(g.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=h.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(g.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=g.offset[pos]||0;if(g.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*g.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(g.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&g.queue){if(old!=attr[key])animate(g.onAfterFirst);delete attr[key]}});animate(g.onAfter);function animate(a){$elem.animate(attr,f,g.easing,a&&function(){a.call(this,e,g)})}}).end()};h.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return typeof a=='object'?a:{top:a,left:a}}})(jQuery); \ No newline at end of file +;(function(k){'use strict';k(['jquery'],function($){var j=$.scrollTo=function(a,b,c){return $(window).scrollTo(a,b,c)};j.defaults={axis:'xy',duration:0,limit:!0};j.window=function(a){return $(window)._scrollable()};$.fn._scrollable=function(){return this.map(function(){var a=this,isWin=!a.nodeName||$.inArray(a.nodeName.toLowerCase(),['iframe','#document','html','body'])!=-1;if(!isWin)return a;var b=(a.contentWindow||a).document||a.ownerDocument||a;return/webkit/i.test(navigator.userAgent)||b.compatMode=='BackCompat'?b.body:b.documentElement})};$.fn.scrollTo=function(f,g,h){if(typeof g=='object'){h=g;g=0}if(typeof h=='function')h={onAfter:h};if(f=='max')f=9e9;h=$.extend({},j.defaults,h);g=g||h.duration;h.queue=h.queue&&h.axis.length>1;if(h.queue)g/=2;h.offset=both(h.offset);h.over=both(h.over);return this._scrollable().each(function(){if(f==null)return;var d=this,$elem=$(d),targ=f,toff,attr={},win=$elem.is('html,body');switch(typeof targ){case'number':case'string':if(/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)){targ=both(targ);break}targ=win?$(targ):$(targ,this);if(!targ.length)return;case'object':if(targ.is||targ.style)toff=(targ=$(targ)).offset()}var e=$.isFunction(h.offset)&&h.offset(d,targ)||h.offset;$.each(h.axis.split(''),function(i,a){var b=a=='x'?'Left':'Top',pos=b.toLowerCase(),key='scroll'+b,old=d[key],max=j.max(d,a);if(toff){attr[key]=toff[pos]+(win?0:old-$elem.offset()[pos]);if(h.margin){attr[key]-=parseInt(targ.css('margin'+b))||0;attr[key]-=parseInt(targ.css('border'+b+'Width'))||0}attr[key]+=e[pos]||0;if(h.over[pos])attr[key]+=targ[a=='x'?'width':'height']()*h.over[pos]}else{var c=targ[pos];attr[key]=c.slice&&c.slice(-1)=='%'?parseFloat(c)/100*max:c}if(h.limit&&/^\d+$/.test(attr[key]))attr[key]=attr[key]<=0?0:Math.min(attr[key],max);if(!i&&h.queue){if(old!=attr[key])animate(h.onAfterFirst);delete attr[key]}});animate(h.onAfter);function animate(a){$elem.animate(attr,g,h.easing,a&&function(){a.call(this,targ,h)})}}).end()};j.max=function(a,b){var c=b=='x'?'Width':'Height',scroll='scroll'+c;if(!$(a).is('html,body'))return a[scroll]-$(a)[c.toLowerCase()]();var d='client'+c,html=a.ownerDocument.documentElement,body=a.ownerDocument.body;return Math.max(html[scroll],body[scroll])-Math.min(html[d],body[d])};function both(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}return j})}(typeof define==='function'&&define.amd?define:function(a,b){if(typeof module!=='undefined'&&module.exports){module.exports=b(require('jquery'))}else{b(jQuery)}})); \ No newline at end of file diff --git a/assets/less/runeui-custom.less b/assets/less/runeui-custom.less index fe99d7f0..96687489 100644 --- a/assets/less/runeui-custom.less +++ b/assets/less/runeui-custom.less @@ -562,7 +562,7 @@ html, body { line-height: 19px; // margin: 0; // background: @body-bg; - border-bottom: 1px solid darken(@brand-alt, 16%); + // border-bottom: 1px solid darken(@brand-alt, 16%); // color: @text-color; font-size: 15px; // text-align: left; @@ -837,7 +837,9 @@ html, body { #playlist, #database { padding: 80px 0; - // background: @body-bg; +} +#playlist { + background: transparent url('../img/list-bg.gif') repeat 0 30px; // this simulates the presence of entries while they are dinamically rendered in the virtual DOM } .sortable-ghost { background: darken(@brand-alt, 10%); From 907b610535a6606e03891c57613de80a81185ab1 Mon Sep 17 00:00:00 2001 From: hondagx35 Date: Mon, 15 Dec 2014 18:13:29 +0100 Subject: [PATCH 24/80] new networking --- .../etc/wpa_supplicant/wpa_supplicant.conf | 7 +- .../_os/usr/lib/systemd/system/redis.service | 33 +- .../lib/systemd/system/rune_PL_wrk.service | 24 +- .../lib/systemd/system/rune_SY_wrk.service | 25 +- .../systemd/system/wpa_supplicant@.service | 13 - app/libs/runeaudio.php | 357 ++++++++---------- app/network_ctl.php | 26 +- app/templates/network.php | 6 +- app/templates/network_edit.php | 13 + app/templates/network_wlan.php | 185 ++++++--- assets/js/runeui.js | 22 +- command/refresh_nics | 163 ++++---- command/rune_SY_wrk | 78 +++- 13 files changed, 531 insertions(+), 421 deletions(-) delete mode 100644 app/config/_os/usr/lib/systemd/system/wpa_supplicant@.service diff --git a/app/config/_os/etc/wpa_supplicant/wpa_supplicant.conf b/app/config/_os/etc/wpa_supplicant/wpa_supplicant.conf index d5d66e7e..7900a500 100644 --- a/app/config/_os/etc/wpa_supplicant/wpa_supplicant.conf +++ b/app/config/_os/etc/wpa_supplicant/wpa_supplicant.conf @@ -1,2 +1,5 @@ -ctrl_interface=/var/run/wpa_supplicant -update_config=1 +ctrl_interface=/var/run/wpa_supplicant +#update_config=1 +eapol_version=1 +ap_scan=1 +fast_reauth=1 diff --git a/app/config/_os/usr/lib/systemd/system/redis.service b/app/config/_os/usr/lib/systemd/system/redis.service index d55bf4ed..212437c0 100644 --- a/app/config/_os/usr/lib/systemd/system/redis.service +++ b/app/config/_os/usr/lib/systemd/system/redis.service @@ -1,15 +1,18 @@ -[Unit] -Description=Advanced key-value store -After=network.target - -[Service] -#Type=forking -User=redis -PIDFile=/run/redis/redis.pid -ExecStartPre=/bin/mkdir -p /var/lib/redis -ExecStart=/usr/bin/redis-server /etc/redis.conf -ExecStop=/usr/bin/redis-cli shutdown -Restart=always - -[Install] -WantedBy=multi-user.target +[Unit] +Description=Advanced key-value store +After=network.target + +[Service] +#Type=forking +User=redis +PIDFile=/run/redis/redis.pid +ExecStartPre=/bin/mkdir -p /var/lib/redis +ExecStart=/usr/bin/redis-server /etc/redis.conf +ExecStop=/usr/bin/redis-cli shutdown +Restart=always +RestartSec=1 +StartLimitInterval=30 +StartLimitBurst=20 + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/rune_PL_wrk.service b/app/config/_os/usr/lib/systemd/system/rune_PL_wrk.service index 1118fe75..cc387a7f 100644 --- a/app/config/_os/usr/lib/systemd/system/rune_PL_wrk.service +++ b/app/config/_os/usr/lib/systemd/system/rune_PL_wrk.service @@ -1,10 +1,14 @@ -[Unit] -Description=RuneAudio Playback Worker After=network.target - -[Service] -ExecStart=/var/www/command/rune_PL_wrk -TimeoutSec=0 -Restart=always - -[Install] -WantedBy=multi-user.target +[Unit] +Description=RuneAudio Playback Worker +After=network.target redis.target + +[Service] +ExecStart=/var/www/command/rune_PL_wrk +TimeoutSec=0 +Restart=always +RestartSec=1 +StartLimitInterval=30 +StartLimitBurst=20 + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/rune_SY_wrk.service b/app/config/_os/usr/lib/systemd/system/rune_SY_wrk.service index f8a4eacf..093b7d58 100644 --- a/app/config/_os/usr/lib/systemd/system/rune_SY_wrk.service +++ b/app/config/_os/usr/lib/systemd/system/rune_SY_wrk.service @@ -1,11 +1,14 @@ -[Unit] -Description=RuneAudio System Worker -After=multi-user.target redis.service - -[Service] -ExecStart=/var/www/command/rune_SY_wrk -TimeoutSec=0 -Restart=always - -[Install] -WantedBy=multi-user.target +[Unit] +Description=RuneAudio System Worker +After=multi-user.target network.target redis.target + +[Service] +ExecStart=/var/www/command/rune_SY_wrk +TimeoutSec=0 +Restart=always +RestartSec=1 +StartLimitInterval=30 +StartLimitBurst=20 + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/wpa_supplicant@.service b/app/config/_os/usr/lib/systemd/system/wpa_supplicant@.service deleted file mode 100644 index 15e880e5..00000000 --- a/app/config/_os/usr/lib/systemd/system/wpa_supplicant@.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=WPA supplicant daemon (interface-specific version) -Requires=sys-subsystem-net-devices-%i.device -After=sys-subsystem-net-devices-%i.device - -# NetworkManager users will probably want the dbus version instead. - -[Service] -Type=simple -ExecStart=/usr/bin/wpa_supplicant -c/etc/wpa_supplicant/wpa_supplicant.conf -i%I - -[Install] -Alias=multi-user.target.wants/wpa_supplicant@%i.service diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 938714a2..150dc57f 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -1347,11 +1347,12 @@ function wrk_opcache($action, $redis) function wrk_netconfig($redis, $action, $args = null, $configonly = null) { -$updateh = 0; + // nics blacklist + $excluded_nics = array('ifb0', 'ifb1', 'p2p0', 'bridge'); + + $updateh = 0; switch ($action) { case 'setnics': - // nics blacklist - $excluded_nics = array('ifb0', 'ifb1', 'p2p0', 'bridge'); // flush nics Redis hash table $transaction = $redis->multi(); $transaction->del('nics'); @@ -1381,46 +1382,71 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) $transaction->hSet('nics', $interface , json_encode(array('ip' => $ip[0], 'netmask' => $netmask, 'gw' => $gw[0], 'dns1' => $dns[0], 'dns2' => $dns[1], 'speed' => $speed[0],'wireless' => 0))); } } - //// if ($scanwifi) sysCmdAsync('/var/www/command/refresh_nics'); - // check wpa_supplicant auto-start and purge interface list - /* TODO marked for deletion - $wpa_supplicant_start = sysCmd("ls -lah /etc/systemd/system/multi-user.target.wants/wpa_supplicant@*.service | cut -d '@' -f 2 | cut -d '.' -f 1"); - $disable_wpa_supplicant = array_diff($wpa_supplicant_start, $interfaces); - if (!empty($disable_wpa_supplicant)) { - foreach ($disable_wpa_supplicant as $interface_name) { - unlink('/etc/systemd/system/multi-user.target.wants/wpa_supplicant@'.$interface_name.'.service'); - } - } - */ $transaction->exec(); break; case 'getnics': - foreach ($redis->hGetAll('nics') as $interface => $details) { - $interfaces[$interface] = json_decode($details); + $interfaces = sysCmd("ip addr |grep \"BROADCAST,\" |cut -d':' -f1-2 |cut -d' ' -f2"); + $interfaces = array_diff($interfaces, $excluded_nics); + foreach ($interfaces as $interface) { + $ip = sysCmd("ip addr list ".$interface." |grep \"inet \" |cut -d' ' -f6|cut -d/ -f1"); + $netmask = sysCmd("ip addr list ".$interface." |grep \"inet \" |cut -d' ' -f6|cut -d/ -f2"); + if (isset($netmask[0]) && isset($ip[0])) { + $netmask = "255.255.255.0";//netmask($netmask[0]); + } else { + unset($netmask); + } + if (isset($netmask[0])) { + $gw = sysCmd("route -n |grep \"0.0.0.0\" |grep \"UG\" |cut -d' ' -f10"); + $dns = sysCmd("cat /etc/resolv.conf |grep \"nameserver\" |cut -d' ' -f2"); + } + $type = sysCmd("iwconfig ".$interface." 2>&1 | grep \"no wireless\""); + if (empty($type[0])) { + $speed = sysCmd("iwconfig ".$interface." 2>&1 | grep 'Bit Rate' | cut -d ':' -f 2 | cut -d ' ' -f 1-2"); + $currentSSID = sysCmd("iwconfig ".$interface." | grep 'ESSID' | cut -d ':' -f 2 | cut -d '\"' -f 2"); + $actinterfaces[$interface] = (object) ['ip' => $ip[0], 'netmask' => $netmask, 'gw' => $gw[0], 'dns1' => $dns[0], 'dns2' => $dns[1], 'speed' => $speed[0], 'wireless' => 1, 'currentssid' => $currentSSID[0]]; + $redis->hSet('nics', $interface , json_encode(array('ip' => $ip[0], 'netmask' => $netmask, 'gw' => $gw[0], 'dns1' => $dns[0], 'dns2' => $dns[1], 'speed' => $speed[0],'wireless' => 1, 'currentssid' => $currentSSID[0]))); + } else { + $speed = sysCmd("ethtool ".$interface." 2>&1 | grep -i speed | cut -d':' -f2"); + $actinterfaces[$interface] = (object) ['ip' => $ip[0], 'netmask' => $netmask, 'gw' => $gw[0], 'dns1' => $dns[0], 'dns2' => $dns[1], 'speed' => $speed[0], 'wireless' => 0]; + $redis->hSet('nics', $interface , json_encode(array('ip' => $ip[0], 'netmask' => $netmask, 'gw' => $gw[0], 'dns1' => $dns[0], 'dns2' => $dns[1], 'speed' => $speed[0],'wireless' => 0))); + } } - return $interfaces; + return $actinterfaces; + break; + case 'getstoredwlans': + sysCmd('/www/command/refresh_nics'); + $wlans_profiles = json_decode($redis->Get('stored_profiles')); + foreach ($wlans_profiles as $profile) { + runelog(' Get stored wlan profiles:'.$profile); + if ($nicdetail->currentssid === $profile) { + $connected = 1; + } else { + $connected = 0; + } + $wlans[] = json_encode(array('ssid' => $profile, 'encryption' => 'on', 'connected' => $connected, 'storedprofile' => 1)); + } + return $wlans; break; case 'writecfg': // ArchLinux netctl config for wired ethernet $nic = "Description='".$args->name." connection'\n"; $nic .= "Interface=".$args->name."\n"; - $nic .= "ForceConnect=yes\n"; - $nic .= "SkipNoCarrier=yes\n"; if ($args->wireless === '1') { // Wireless configuration $nic .= "Connection=wireless\n"; - $nic .= "Security=wpa-config\n"; - $nic .= "WPAConfigFile='/etc/wpa_supplicant/wpa_supplicant.conf'\n"; + $nic .= "Security=wpa-configsection\n"; } else { // Wired configuration + $nic .= "ForceConnect=yes\n"; + $nic .= "SkipNoCarrier=yes\n"; $nic .= "Connection=ethernet\n"; } if ($args->dhcp === '1') { // DHCP configuration $nic .= "IP=dhcp\n"; // Prepare data object for Redis record - $args = array( 'name' => $args->name, 'dhcp' => $args->dhcp ); - $args = (object) $args; + $dhcpargs = array( 'name' => $args->name, 'dhcp' => $args->dhcp ); + $dhcpargs = (object) $args; } else { // STATIC configuration $nic .= "AutoWired=yes\n"; @@ -1433,8 +1459,66 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) $nic .= "DNS=('".$args->dns1."')\n"; } } - // ntp sync after connect - $nic .= "ExecUpPost='/usr/bin/ntpd -gq || true'\n"; + if ($args->wireless === '1') { + $nic .= "WPAConfigSection=(\n"; + if ($args->newssid === "add") { + $nic .= " 'ssid=\"".$args->ssid."\"'\n"; + $nic .= " 'scan_ssid=1'\n"; + } else { + $nic .= " 'ssid=\"".$args->newssid."\"'\n"; + } + //$key = $args->key; + switch ($args->encryption) { + case 'none': + $nic .= " 'key_mgmt=NONE'\n"; + break; + case 'wep': + $nic .= " 'key_mgmt=NONE'\n"; + $nic .= " 'wep_tx_keyidx=0'\n"; + $wepkey = $args->key; + if (ctype_xdigit($wepkey) && (strlen($wepkey) == 10 OR strlen($wepkey) == 26 OR strlen($wepkey) == 32)) { + $nic .= " 'wep_key0=".$wepkey."'\n"; + } elseif (strlen($wepkey) <= 16) { + $nic .= " 'wep_key0=\"".$wepkey."\"'\n"; + } else { + $nic .= " 'wep_key0=\"* wrong wepkey *\"'\n"; + ui_notify_async('WIFI-Config ERROR', "You entered a wrong key!\n"); + return ''; + } + // auth_alg=SHARED + break; + case 'wpa': + $wpakey = $args->key; + if (ctype_xdigit($wpakey) && strlen($wpakey) == 64) { + $nic .= " 'psk=".$wpakey."'\n"; + } elseif (strlen($wpakey) >= 8 && strlen($wpakey) <= 63) { + $nic .= " 'psk=\"".$wpakey."\"'\n"; + } else { + $nic .= " 'psk=\"* wrong wepkey *\"'\n"; + ui_notify_async('WIFI-Config ERROR', "You entered a wrong key!\n"); + return ''; + } + $nic .= " 'key_mgmt=WPA-PSK'\n"; + if (strpos($args->ie, "WPA2") !== false) { + $nic .= " 'proto=RSN'\n"; + } else { + $nic .= " 'proto=WPA'\n"; + } + if (strpos($args->GroupCipher, "CCMP") !== false) { + $nic .= " 'group=CCMP'\n"; + } else { + $nic .= " 'group=TKIP'\n"; + } + if (strpos($args->PairwiseCiphers1, "CCMP") !== false OR strpos($args->PairwiseCiphers2, "CCMP") !== false) { + $nic .= " 'pairwise=CCMP'\n"; + } else { + $nic .= " 'pairwise=TKIP'\n"; + } + } + $nic .= " 'priority=3'\n"; + $nic .= ")\n"; + } + // set advanced DNS options $newArray = wrk_replaceTextLine('/etc/resolvconf.conf', '', 'resolv_conf_options=', "resolv_conf_options=('timeout:".$redis->hGet('resolvconf', 'timeout')." attempts:".$redis->hGet('resolvconf', 'attempts')."')", '#name_servers=127.0.0.1', 1); // Commit changes to /etc/resolvconf.conf @@ -1445,11 +1529,27 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) sysCmd('resolvconf -u'); // write current network config - $redis->set($args->name, json_encode($args)); - $fp = fopen('/etc/netctl/'.$args->name, 'w'); + runelog("wireless = ".$args->wireless); + if ($args->wireless === '1') { + // wireless + runelog("save as wireless"); + if ($args->newssid === "add") { + $redis->Set($args->ssid, json_encode($args)); + $fp = fopen('/etc/netctl/'.$args->ssid, 'w'); + } else { + $redis->Set($args->newssid, json_encode($args)); + $fp = fopen('/etc/netctl/'.$args->newssid, 'w'); + } + } else { + // wired + runelog("save as wired"); + $redis->Set($args->name, json_encode($args)); + $fp = fopen('/etc/netctl/'.$args->name, 'w'); + } fwrite($fp, $nic); fclose($fp); if (!isset($configonly)) $updateh = 1; + //$updateh = 1; break; case 'manual': $file = '/etc/netctl/'.$args['name']; @@ -1468,195 +1568,68 @@ function wrk_netconfig($redis, $action, $args = null, $configonly = null) break; } if ($updateh === 1) { - runelog('wireless NIC?', $args->wireless); + sysCmd('mpc pause'); + //sysCmd('systemctl stop mpd'); // activate configuration (RuneOS) - wrk_mpdPlaybackStatus($redis, 'record'); - sysCmd('netctl stop '.$args->name); - sysCmd('ip addr flush dev '.$args->name); - if ($args->dhcp === '1') { - // dhcp configuration - if ($args->wireless !== '1') { - // $cmd = 'systemctl enable ifplugd@'.$args->name; - sysCmd("ln -s '/usr/lib/systemd/system/netctl-ifplugd@.service' '/etc/systemd/system/multi-user.target.wants/netctl-ifplugd@".$args->name.".service'"); - sysCmd('systemctl daemon-reload'); - sysCmd('systemctl start netctl-ifplugd@'.$args->name); + runelog("wireless = ".$args->wireless); + if ($args->wireless !== '1') { + sysCmd('systemctl reenable netctl-ifplugd@'.$args->name); + if ($args->reboot === '1') { + runelog('**** reboot requested ****', $args->name); + $return = 'reboot'; + } else { + runelog('**** no reboot requested ****', $args->name); + sysCmd('systemctl restart netctl-ifplugd@'.$args->name); + $return = ''; } - // sysCmd('systemctl daemon-reload'); } else { - // static configuration - if ($args->wireless !== '1') { - // $cmd = 'systemctl disable ifplugd@'.$args->name; - sysCmd("rm '/etc/systemd/system/multi-user.target.wants/netctl-ifplugd@".$args->name.".service'"); - sysCmd('systemctl daemon-reload'); - // kill ifplugd - sysCmd('killall ifplugd'); - } - // get pids of dhcpcd - $pids = sysCmd('pgrep -xf "dhcpcd -4 -q -t 30 -L '.$args->name.'"'); - foreach ($pids as $pid) { - // debug - runelog('kill pid:', $pid); - // kill dhcpcd - sysCmd('kill '.$pid); - } + sysCmd('systemctl reenable netctl-auto@'.$args->name); + sysCmd('systemctl restart netctl-auto@'.$args->name); + sysCmd('netctl-auto enable '.$args->newssid); + sysCmd('netctl-auto switch-to '.$args->newssid); + runelog('**** wireless => do not reboot ****', $args->name); + $return = ''; } - // start netctl profile for wired nics - if ($args->wireless !== '1') sysCmd('netctl start '.$args->name); - sysCmd('systemctl restart mpd'); - // set process priority - sysCmdAsync('sleep 1 && rune_prio nice'); } // update hash if necessary $updateh === 0 || $redis->set($args->name.'_hash', md5_file('/etc/netctl/'.$args->name)); if (wrk_mpdPlaybackStatus($redis, 'laststate') === 'playing') sysCmd('mpc play'); -} - -function wrk_wifiprofile($redis, $action, $args) -{ - switch ($action) { - case 'add': - $args->id = wrk_wpa_cli('add', $args); - if ($args->id !== false) { - unset($args->action); - $return = $redis->hSet('wlan_profiles', $args->ssid, json_encode($args)); - } - break; - case 'edit': - if(wrk_wpa_cli('edit', $args, $redis)) { - unset($args->action); - unset($args->edit); - $return = $redis->hSet('wlan_profiles', $args->ssid, json_encode($args)); - } - break; - case 'delete': - if (wrk_wpa_cli('delete', $args)) $return = $redis->hDel('wlan_profiles', $args->ssid); - break; - case 'connect': - if (wrk_wpa_cli('connect')) { - $redis->Set('wlan_autoconnect', 1); - $return = 1; - } - break; - case 'disconnect': - if (wrk_wpa_cli('disconnect')) { - $redis->Set('wlan_autoconnect', 0); - $return = 1; - } - break; - } return $return; } -function wrk_wpa_cli($action, $args = null, $redis = null) +function wrk_wifiprofile($redis, $action, $args) { - $return = 0; - // debug - runelog('**** wrk_wpa_cli() START ****'); - runelog('----- wrk_wpa_cli() args:',$args); - runelog('----- wrk_wpa_cli() action:',$action); switch ($action) { case 'add': - // add wpa entry in the stack - $wlanid = sysCmd('wpa_cli add_network'); - $args->id = $wlanid[1]; - // debug - runelog('wrk_wpa_cli('.$action.'): assigned wlan ID', $args->id); - $wpa_cli_response = wrk_wpa_cli('store', $args); - if ($wpa_cli_response) { - if (isset($args->connect)) { - wrk_wpa_cli('connect'); - } - $return = $args->id; - } else { - // rollback - sysCmd('wpa_cli remove_network '.$args->id); - $return = false; - } + runelog('**** wrk_wifiprofile ADD ****', $args->ssid); + wrk_wifiprofile($redis, 'connect', $args); break; case 'edit': - $args->edit = 1; - if (isset($args->connect)) { - unset($args->connect); - $connect = 1; - } - if (wrk_wpa_cli('store', $args, $redis)) { - if ($connect) wrk_wpa_cli('connect'); - $return = 1; - } - break; - case 'store': - // set default set password command - $cmd_pass = "wpa_cli set_network ".$args->id." psk '\"".$args->key."\"'"; - if (isset($args->edit)) { - $stored_profile = json_decode($redis->hGet('wlan_profiles',$args->ssid)); - if ($stored_profile->encryption === $args->encryption) { - // select correct change password command - $cmd_pass = "wpa_cli new_password ".$args->id." '\"".$args->key."\"'"; - } else { - // remove and - if (wrk_wpa_cli('delete', $args)) { - unset($args->edit); - wrk_wpa_cli('add', $args); - } else { - $return = false; - break; - } - } - } - // set the SSID - $wpa_cli_response = sysCmd("wpa_cli set_network ".$args->id." ssid '\"".$args->ssid."\"'"); - // set the encryption type - if ($wpa_cli_response[1] === 'OK') { - if ($args->encryption === 'open') { - $wpa_cli_response = sysCmd('wpa_cli set_network '.$args->id.' key_mgmt NONE'); - } - if ($args->encryption === 'wpa') { - $wpa_cli_response = sysCmd('wpa_cli set_network '.$args->id.' key_mgmt WPA-PSK'); - // store the encryption key - $wpa_cli_response = sysCmd($cmd_pass); - } - if ($args->encryption === 'wep') { - $wpa_cli_response = sysCmd('wpa_cli set_network '.$args->id.' key_mgmt NONE'); - // store the encryption key - if (isset($chpass)) { - $wpa_cli_response = sysCmd("wpa_cli new_password ".$args->id." '\"".$args->key."\"'"); - } else { - $wpa_cli_response = sysCmd("wpa_cli set_network ".$args->id." wep_key0 '\"".$args->key."\"'"); - } - } - } - // enable the new network profile - if ($wpa_cli_response[1] === 'OK') $wpa_cli_response = sysCmd('wpa_cli enable_network '.$args->id); - // save configuration file - if ($wpa_cli_response[1] === 'OK') $wpa_cli_response = sysCmd('wpa_cli save_config'); - if ($wpa_cli_response[1] === 'OK') { - $return = true; - } else { - $return = false; - } + runelog('**** wrk_wifiprofile EDIT ****', $args->ssid); + wrk_wifiprofile($redis, 'connect', $args); break; case 'delete': - $wpa_cli_response = sysCmd('wpa_cli remove_network '.$args->id); - if ($wpa_cli_response[1] === 'OK') $wpa_cli_response = sysCmd('wpa_cli save_config'); - if ($wpa_cli_response[1] === 'OK') { - $return = 1; - } else { - $return = false; - } + runelog('**** wrk_wifiprofile DELETE ****', $args->ssid); + wrk_wifiprofile($redis, 'disconnect', $args); + $redis->Del($args->ssid); + $redis->Del('stored_profiles'); + sysCmd("rm /etc/netctl/".$args->ssid); + sysCmdAsync("systemctl restart netctl-auto@".$args->nic); + $return = 1; break; case 'connect': - // TODO: enhance, catch the event "CTRL-EVENT-CONNECTED" instead of "OK" response from wpa_cli - $wpa_cli_response = sysCmd('wpa_cli reconnect'); - if ($wpa_cli_response[1] === 'OK') $return = 1; + runelog('**** wrk_wifiprofile CONNECT ****', $args->ssid); + sysCmdAsync("netctl-auto switch-to ".$args->ssid); + $redis->Set('wlan_autoconnect', 1); + $return = 1; break; case 'disconnect': - $wpa_cli_response = sysCmd('wpa_cli disconnect'); - if ($wpa_cli_response[1] === 'OK') $return = 1; + runelog('**** wrk_wifiprofile DISCONNECT ****', $args->ssid); + sysCmdAsync("netctl-auto disable ".$args->ssid); + $redis->Set('wlan_autoconnect', 0); + $return = 1; break; } - // debug - runelog('----- wrk_wpa_cli() exit status',$return); - runelog('**** wrk_wpa_cli() STOP ****'); return $return; } diff --git a/app/network_ctl.php b/app/network_ctl.php index e3d7fbab..d406379a 100755 --- a/app/network_ctl.php +++ b/app/network_ctl.php @@ -34,40 +34,44 @@ // inspect POST if (isset($_POST)) { - if (isset($_POST['nic'])) { + if (isset($_POST['nic']) && !isset($_POST['wifiprofile'])) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'config'", $_POST['nic']); $redis->get($_POST['nic']['name']) === json_encode($nic) || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'config', 'args' => $_POST['nic'])); } if (isset($_POST['refresh'])) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'refresh'", $_POST['nic']); $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'refresh')); } if (isset($_POST['wifiprofile'])) { switch ($_POST['wifiprofile']['action']) { case 'add': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'add'", $_POST['wifiprofile']); $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'add', 'args' => $_POST['wifiprofile'])); break; case 'edit': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'edit'", $_POST['wifiprofile']); $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'edit', 'args' => $_POST['wifiprofile'])); break; case 'delete': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'delete'", $_POST['wifiprofile']); $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'delete', 'args' => $_POST['wifiprofile'])); break; + case 'connect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'connect'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'connect', 'args' => $_POST['wifiprofile'] )); + break; case 'disconnect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'disconnect'", $_POST['wifiprofile']); $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'disconnect', 'args' => $_POST['wifiprofile'] )); break; } } - // if (isset($_POST['wifidelete'])) { - // $jobID[] = wrk_control($redis,'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'delete', 'args' => $_POST['wifidelete'] )); - // } - if (isset($_POST['wpa_cli'])) { - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'wpa_cli', 'args' => $_POST['wpa_cli'])); - } } waitSyWrk($redis,$jobID); $template->nics = wrk_netconfig($redis, 'getnics'); $template->wlan_autoconnect = $redis->Get('wlan_autoconnect'); -if ($redis->hExists('wlan_profiles', urldecode($template->uri(4)))) $template->stored = 1; +if ($redis->Exists(urldecode($template->uri(4)))) $template->stored = 1; if (isset($template->action)) { // check if we are into interface details (ex. http://runeaudio/network/edit/eth0) if (isset($template->arg)) { @@ -97,8 +101,10 @@ if ($template->nic->wireless === 1) { $template->wlans = json_decode($redis->get('wlans')); $template->wlan_profiles = new stdClass(); - if ($wlan_profiles = $redis->hGetAll('wlan_profiles')) foreach ($wlan_profiles as $key => $value) { - $template->wlan_profiles->{$key} = json_decode($value); + if ($wlan_profiles = wrk_netconfig($redis, 'getstoredwlans')) { + foreach ($wlan_profiles as $key => $value) { + $template->wlan_profiles->{$key} = json_decode($value); + } } } // we are in the wlan subtemplate (ex. http://runeaudio/network/wlan/....) diff --git a/app/templates/network.php b/app/templates/network.php index 970d44e5..b01e4d88 100644 --- a/app/templates/network.php +++ b/app/templates/network.php @@ -11,7 +11,11 @@

    List of active network interfaces. Click on an entry to configure the corresponding connection.

    nics as $key => $value): ?> -

       [ip !== null): ?>ip ?>no IP assigned]

    + wireless !== 1): ?> +

       [ip !== null): ?>ip ?>no IP assigned]

    + +

       [ip !== null): ?>ip ?>] [currentssid) ?>no IP assigned]

    +
    \ No newline at end of file diff --git a/app/templates/network_edit.php b/app/templates/network_edit.php index 39c2f1ba..4ca640a9 100644 --- a/app/templates/network_edit.php +++ b/app/templates/network_edit.php @@ -3,6 +3,7 @@ nic->wireless === 1): ?> Wi-Fi networks in range The list of available Wi-Fi networks is automatically refreshed while you are on this page (so don't forget it open in your browser to avoid unnecessary system load). + Click on an entry to connect or to generate a new profile.

    scanning for networks...

    @@ -27,6 +28,7 @@
    + nic->wireless === 0): ?>
    @@ -102,6 +104,16 @@ +
    + +
    + + If you experience problems, set this to YES. +
    +
    Cancel @@ -109,6 +121,7 @@
    + - \ No newline at end of file + diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 31724a66..4a60e7d4 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -1381,7 +1381,7 @@ function libraryHome(text) { // list of in range wlans function listWLANs(text) { var i = 0, content = '', inrange = '', stored = '', wlans = text[0]; - // console.log(wlans); + //console.log(wlans); $.each(wlans, function(i) { content += '

    '; if (wlans[i].connected !== 0) { @@ -1399,10 +1399,11 @@ function listWLANs(text) { } } content += '' + wlans[i].ESSID + '

    '; + if (wlans[i].origin === 'scan') { + inrange += content; + } if (wlans[i].storedprofile === 1) { stored += content; - } else { - inrange += content; } content = ''; }); @@ -1422,7 +1423,7 @@ function nicsDetails(text) { if (i === $('#nic-details').data('name')) { content += 'Name:' + i + ''; content += 'Type:wireless'; - if (nics[i].currentssid === 'off/any') { + if (nics[i].currentssid === null) { content += 'Status:no network connected'; } else { content += 'Status:connected'; @@ -1431,10 +1432,12 @@ function nicsDetails(text) { content += 'Assigned IP:' + ((nics[i].ip !== null) ? ('' + nics[i].ip + '') : 'none') + ''; content += 'Speed:' + ((nics[i].speed !== null) ? nics[i].speed : 'unknown') + ''; - // content += 'Netmask:' + nics[i].netmask + ''; - // content += 'Gateway:' + nics[i].gw + ''; - // content += 'DNS1:' + nics[i].dns1 + ''; - // content += 'DNS2:' + nics[i].dns2 + ''; + if (nics[i].currentssid !== null) { + content += 'Netmask:' + nics[i].netmask + ''; + content += 'Gateway:' + nics[i].gw + ''; + content += 'DNS1:' + nics[i].dns1 + ''; + content += 'DNS2:' + nics[i].dns2 + ''; + } } }); $('#nic-details tbody').html(content); @@ -2576,8 +2579,7 @@ if ($('#section-index').length) { } }); - } - + } // MPD // ---------------------------------------------------------------------------------------------------- diff --git a/command/refresh_nics b/command/refresh_nics index a540fa1b..1812eb2e 100755 --- a/command/refresh_nics +++ b/command/refresh_nics @@ -50,7 +50,7 @@ usleep($sleep); runelog('random delay: ', $sleep); // startup - collect system data runelog('--------------------------- collect system data ---------------------------'); -$excluded_nics = array('ifb0', 'ifb1'); +$excluded_nics = array('ifb0', 'ifb1', 'p2p0', 'bridge'); $active_nics = sysCmd("ifconfig | grep UP | cut -d ':' -f 1"); $detected_nics = sysCmd("ip addr |grep \"BROADCAST,\" |cut -d':' -f1-2 |cut -d' ' -f2"); $detected_nics = array_diff($detected_nics, $excluded_nics); @@ -72,115 +72,87 @@ runelog('########### configured_nics ########### ', $configured_nics); runelog('########### removed_nics ########### ', $removed_nics); // handle inactive nics runelog('--------------------------- handle inactive nics ---------------------------'); -if (!empty($inactive_nics)) { - foreach($inactive_nics as $nic) { - $wireless = sysCmd("iwconfig ".$nic." | grep 'no wireless'"); - if (empty($wireless)) { - // activate link - runelog('########### activate currently inactive wifi nic: '.$nic); - sysCmd('ip link set '.$nic.' up'); - // start wpa_supplicant - runelog('########### start wpa_supplicant for wifi nic: '.$nic); - sysCmd('systemctl start wpa_supplicant@'.$nic); - // check if the nic is unconfigured (= without an existing netctl profile) - if (empty(sysCmd('ls /etc/netctl/ | grep '.$nic))) { - // create a new standard (dhcp) wifi netctl profile - $args = new stdClass; - $args->name = $nic; - $args->wireless = '1'; - $args->dhcp = '1'; - wrk_netconfig($redis, 'writecfg', $args, 1); - } - // check wpa_supplicant status - // if (empty(sysCmd('ls /etc/systemd/system/multi-user.target.wants/ | grep wpa_supplicant@'.$nic))) { - // enable wpa_supplicant - // runelog('########### enable wpa_supplicant for wifi nic: '.$nic); - // sysCmd('systemctl enable wpa_supplicant@'.$nic); - // } - // enable netctl profile - // if (empty(sysCmd('ls /etc/systemd/system/multi-user.target.wants/ | grep netctl@'.$nic))) { - // runelog('########### enable netctl for wifi nic: '.$nic); - // sysCmd('netctl enable '.$nic); - // } - } - } -} unset($nic); runelog('--------------------------- handle active nics ---------------------------'); // check if there is a stored profile // refesh visible wifi networks. $iw = new iwlist_parser; -// debug -// print_r($iw->parseScanDev( 'wlan0' )); wrk_netconfig($redis, 'setnics'); $nics = wrk_netconfig($redis, 'getnics'); -// debug -// print_r($nics); foreach ($nics as $nic => $nicdetail) { if ($nicdetail->wireless === 1) { - // check and activate wpa_supplicant - if (empty(sysCmd("ps x | grep '\-c\/etc\/wpa_supplicant\/wpa_supplicant.conf'"))) { - runelog('########### start wpa_supplicant for nic: '.$nic); - sysCmd('systemctl start wpa_supplicant@'.$nic); - } - // check and activate netctl@nic profile - if (empty(sysCmd('netctl list | grep '.$nic.' | grep \*'))) { - runelog('########### start netctl profile for nic: '.$nic); - if(!empty(sysCmd('netctl start '.$nic))) { - runelog('########### ZERO condition reached for nic: '.$nic.' restart link and wpa_supplicant helper'); - sysCmd('ip link set '.$nic.' up'); - sysCmd('systemctl start wpa_supplicant@'.$nic); - } - } - // temp + if (empty(sysCmd('ifconfig | grep '.$nic.''))) { + runelog('########### restart link for nic: '.$nic); + sysCmd('ip link set '.$nic.' up'); + } + runelog(' try nic: '.$nic); + + // test if service is enabled + sysCmd('systemctl enable netctl-auto@'.$nic.'.service'); + + // get stored profiles + $wlans_profiles = sysCmd("netctl-auto list | cut -c3-"); + $redis->set('stored_profiles',json_encode($wlans_profiles)); + // scan for ap in range $scan = $iw->parseScanDev( $nic ); + $tmp_wlans = array(); $redis->set('wlans',json_encode($scan)); - // debug - // print_r($scan); foreach ($scan as $nicname => $nicscan) { + runelog(' scan for nic: '.$nic.' nicname = '.$nicname); foreach ($nicscan as $count => $wlan) { - foreach ($wlan as $key => $value) { - $wlans[$count]['nic'] = $nicname; - if ($key === 'ESSID') { - $wlans[$count][$key] = $value; - if ($nicdetail->currentssid === $value) { - $wlans[$count]['connected'] = 1; - } else { - $wlans[$count]['connected'] = 0; + runelog(' scan for nic: '.$nic.' AP = '.$count); + if ($wlan['ESSID'] === "" OR array_search ($wlan['ESSID'], $tmp_wlans) !== false) { + runelog(' SSID already found'); + } else { + foreach ($wlan as $key => $value) { + $wlans[$count]['nic'] = $nicname; + runelog(' scan for nic: '.$nic.' = '.$key.' = '.$value); + if ($key === 'ESSID') { + $wlans[$count][$key] = $value; + $tmp_wlans[] = $value; + if ($nicdetail->currentssid === $value) { + $wlans[$count]['connected'] = 1; + } else { + $wlans[$count]['connected'] = 0; + } + foreach($wlans_profiles as $item){ + if($item === $value){ + $wlans[$count]['storedprofile'] = 1; + break; // found it! + } else { + $wlans[$count]['storedprofile'] = 0; + } + } } + if ($key === 'Encryption key') $wlans[$count]['encryption'] = $value; + $wlans[$count]['origin'] = 'scan'; } - if ($key === 'Encryption key') $wlans[$count]['encryption'] = $value; } } - } - // debug - // print_r($wlans); - // render wlans channel - // $wlans = json_encode($wlans); - $wlans_profiles = $redis->hGetAll('wlan_profiles'); - $i = count($wlans); - foreach ($wlans_profiles as $profile => $details) { - $i++; - $details = json_decode($details); - $stored_profiles[$i]['nic'] = $details->nic; - if ($details->encryption !== 'open') { - $stored_profiles[$i]['encryption'] = 'on'; - } else { - $stored_profiles[$i]['encryption'] = 'off'; - } - $stored_profiles[$i]['ESSID'] = $details->ssid; - if ($nicdetail->currentssid === $details->ssid) { - $stored_profiles[$i]['connected'] = 1; - } else { - $stored_profiles[$i]['connected'] = 0; + } + + // handle hidden but stored profiles + foreach ($wlans_profiles as $item){ + if ((bool)strpos(serialize($wlans), $item) === false){ + $wlans[++$count]['nic'] = $nic; + $wlans[$count]['ESSID'] = $item; + if ($nicdetail->currentssid === $item) { + $wlans[$count]['connected'] = 1; + } else { + $wlans[$count]['connected'] = 0; + } + $wlans[$count]['storedprofile'] = 1; + $wlans[$count]['encryption'] = 'unknown'; + $wlans[$count]['origin'] = 'storage'; } - $stored_profiles[$i]['storedprofile'] = 1; - $wlans[] = $stored_profiles[$i]; } + + //runelog('wlans response: ', $wlans); $wlans = json_encode($wlans); - // $wlans = json_encode(array_merge($wlans, $stored_profiles)); + runelog('wlans response(encoded): ', $wlans); ui_render('wlans', $wlans); - runelog('wlans response: ', $wlans); + } else { + sysCmd('systemctl enable netctl-ifplugd@'.$nic.'.service'); } } // send nics status to RuneUI @@ -192,19 +164,10 @@ if (!empty($removed_nics)) { foreach($removed_nics as $nic) { // check for orphan netctl startup profiles if (!empty(sysCmd('ls /etc/systemd/system/multi-user.target.wants/ | grep '.$nic))) { - // disable orphan netctl profiles - // sysCmd("rm -f /etc/systemd/system/multi-user.target.wants/netctl@".$nic.".service')"); - // sysCmd("systemctl disable netctl@".$nic.".service')"); runelog('########### disable netctl profiles for nic: '.$nic); - sysCmd('netctl disable '.$nic); + sysCmd('systemctl disable netctl-ifplugd@'.$nic); + sysCmd('systemctl disable netctl-auto@'.$nic); } - // check wpa_supplicant startup status - // if (!empty(sysCmd('ls /etc/systemd/system/multi-user.target.wants/ | grep wpa_supplicant@'.$nic))) { - // disable wpa_supplicant autostart - // runelog('########### disable wpa_supplicant autostart for nic: '.$nic); - // sysCmd("rm -f /etc/systemd/system/multi-user.target.wants/wpa_supplicant@".$nic.".service')"); - // sysCmd('systemctl disable wpa_supplicant@'.$nic.'.service'); - // } } } // end - unlock the scan system diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 283bd94b..c02ce2c0 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -39,6 +39,31 @@ error_reporting(E_ALL); ini_set('error_log', '/var/log/runeaudio/rune_SY_wrk.log'); define('APP', '/srv/http/app/'); include('/srv/http/app/libs/runeaudio.php'); + +// if os updates are needed +if(file_exists('/srv/http/command/update_os')) +{ + include '/srv/http/command/update_os'; + updateOS(); +} + +// test if all services are enabled +$retval = sysCmd('systemctl is-enabled ntpd.service'); +if ($retval[0] === 'disabled') + sysCmd('systemctl enable ntpd.service'); +$retval = sysCmd('systemctl is-enabled rune_PL_wrk.service'); +if ($retval[0] === 'disabled') + sysCmd('systemctl enable rune_PL_wrk.service'); +$retval = sysCmd('systemctl is-enabled redis.service'); +if ($retval[0] === 'disabled') + sysCmd('systemctl enable redis.service'); +$retval = sysCmd('systemctl is-enabled nginx.service'); +if ($retval[0] === 'disabled') + sysCmd('systemctl enable nginx.service'); +$retval = sysCmd('systemctl is-enabled dhcpcd.service'); +if ($retval[0] === 'disabled') + sysCmd('systemctl enable dhcpcd.service'); + // stop php-fpm sysCmd('systemctl stop php-fpm'); // setup /run dir @@ -128,8 +153,8 @@ if ($playerid_db === '') { // NTP sync $start2 = microtime(true); $firstlap = $start2-$start; - runelog('NTP sync', $redis->get('ntpserver')); - wrk_NTPsync($redis->get('ntpserver')); + //runelog('NTP sync', $redis->get('ntpserver')); + //wrk_NTPsync($redis->get('ntpserver')); $start3 = microtime(true); // check HOSTNAME << TODO: integrate in wrk_sysEnvCheck >> $hn = sysCmd('hostname'); @@ -517,21 +542,35 @@ $redis->pconnect('/tmp/redis.sock'); // reset network configuration to default if ($job->action === 'reset') { wrk_netconfig($redis,'reset',$job->args); + $redis->sRem('w_lock', $jobID); } // write network configuration if ($job->action === 'config') { - wrk_netconfig($redis, 'writecfg', $job->args); - sysCmd('/var/www/command/refresh_nics'); + // send notfy to UI + ui_notify('Networkconfiguration', 'it takes some time .....'); + $retval = wrk_netconfig($redis, 'writecfg', $job->args); + $redis->sRem('w_lock', $jobID); + // reboot if needed !!! + if ($retval === 'reboot') { + //$notification = new stdClass(); + //$notification->title = 'Network config'; + //$notification->text = 'Config changed successfully, reboot reqired'; + //wrk_notify($redis, 'kernelswitch', $notification, $jobID); + sysCmd('/var/www/command/rune_shutdown'); + sysCmd('systemctl reboot'); + //$redis->sRem('w_lock', $jobID); + } } // refresh network configuration if ($job->action === 'refresh') { sysCmd('/var/www/command/refresh_nics'); + $redis->sRem('w_lock', $jobID); } // manual network configuration if ($job->action === 'manual') { // wrk_netconfig($redis,'manual',$job->args); + $redis->sRem('w_lock', $jobID); } - $redis->sRem('w_lock', $jobID); break; case 'ntpserver': runelog('wrk_SY: ', $job->wrkcmd); @@ -715,36 +754,47 @@ $redis->pconnect('/tmp/redis.sock'); break; case 'wificfg': runelog('wrk_SY: ', $job->wrkcmd); - // inject random delay to avoid wifi scan overlapping - if ($job->action === 'scan') { - // random delay - $sleep = rand(1000000, 2000000); - usleep($sleep); - $lock = $redis->Get('lock_wifiscan'); - } $redis->sAdd('w_lock',$jobID); // add profile if ($job->action === 'add') { runelog('wificfg: add profile for SSID: '.$job->args->ssid); + ui_notify_async('Adding WIFI-Profile', $job->args->ssid, $jobID); wrk_wifiprofile($redis, 'add', $job->args); + ui_notify_async('Added WIFI-Profile', $job->args->ssid, $jobID); } if ($job->action === 'edit') { runelog('wificfg: edit profile for SSID: '.$job->args->ssid); + ui_notify_async('Changing WIFI-Profile', $job->args->ssid, $jobID); wrk_wifiprofile($redis, 'edit', $job->args); + ui_notify_async('Changed WIFI-Profile', $job->args->ssid, $jobID); } if ($job->action === 'delete') { runelog('wificfg: delete profile for SSID: '.$job->args->ssid); + ui_notify_async('Deleting WIFI-Profile', $job->args->ssid, $jobID); wrk_wifiprofile($redis, 'delete', $job->args); + ui_notify_async('Deleted WIFI-Profile', $job->args->ssid, $jobID); } if ($job->action === 'disconnect') { runelog('wificfg: disconnect profile for SSID: '.$job->args->ssid); - wrk_wifiprofile($redis, 'disconnect'); + ui_notify_async('Disconnecting from WIFI-Profile', $job->args->ssid, $jobID); + wrk_wifiprofile($redis, 'disconnect', $job->args); + ui_notify_async('Disconnected from WIFI-Profile', $job->args->ssid, $jobID); } if ($job->action === 'connect') { runelog('wificfg: connect profile for SSID: '.$job->args->ssid); - wrk_wifiprofile($redis, 'connect'); + ui_notify_async('Connecting to WIFI-Profile', $job->args->ssid, $jobID); + wrk_wifiprofile($redis, 'connect', $job->args); + ui_notify_async('Connected to WIFI-Profile', $job->args->ssid, $jobID); } + // inject random delay to avoid wifi scan overlapping if ($job->action === 'scan') { + // random delay +// $sleep = rand(1000000, 2000000); +// usleep($sleep); +// $lock = $redis->Get('lock_wifiscan'); + } + if ($job->action === 'scan') { + $lock = $redis->Get('lock_wifiscan'); if ($lock !== '1') { runelog('wificfg: scan '); // refresh nics status From 994de4901f8213e625ea353eb997075d28916e7d Mon Sep 17 00:00:00 2001 From: hondagx35 Date: Mon, 15 Dec 2014 19:02:22 +0100 Subject: [PATCH 25/80] new networking --- .../_os/usr/lib/systemd/system/mpd.service | 10 ++++ .../systemd/system/netctl-ifplugd@.service | 12 +++++ .../_os/usr/lib/systemd/system/ntpd.service | 16 ++++++ .../usr/lib/systemd/system/php-fpm.service | 17 +++++++ command/update_os | 49 +++++++++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 app/config/_os/usr/lib/systemd/system/mpd.service create mode 100644 app/config/_os/usr/lib/systemd/system/netctl-ifplugd@.service create mode 100644 app/config/_os/usr/lib/systemd/system/ntpd.service create mode 100644 app/config/_os/usr/lib/systemd/system/php-fpm.service create mode 100644 command/update_os diff --git a/app/config/_os/usr/lib/systemd/system/mpd.service b/app/config/_os/usr/lib/systemd/system/mpd.service new file mode 100644 index 00000000..3b9b0acb --- /dev/null +++ b/app/config/_os/usr/lib/systemd/system/mpd.service @@ -0,0 +1,10 @@ +[Unit] +Description=Music Player Daemon +After=network.target sound.target + +[Service] +ExecStart=/usr/bin/mpd --no-daemon +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/netctl-ifplugd@.service b/app/config/_os/usr/lib/systemd/system/netctl-ifplugd@.service new file mode 100644 index 00000000..508f4eee --- /dev/null +++ b/app/config/_os/usr/lib/systemd/system/netctl-ifplugd@.service @@ -0,0 +1,12 @@ +[Unit] +Description=Automatic wired network connection using netctl profiles +Documentation=man:netctl.special(7) +BindsTo=sys-subsystem-net-devices-%i.device +After=sys-subsystem-net-devices-%i.device + +[Service] +ExecStart=/usr/bin/ifplugd -i %I -r /etc/ifplugd/netctl.action -bfIns +Restart=always + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/ntpd.service b/app/config/_os/usr/lib/systemd/system/ntpd.service new file mode 100644 index 00000000..82186f6f --- /dev/null +++ b/app/config/_os/usr/lib/systemd/system/ntpd.service @@ -0,0 +1,16 @@ +[Unit] +Description=Network Time Service +After=network.target nss-lookup.target +Conflicts=systemd-timesyncd.service + +[Service] +Type=forking +PrivateTmp=true +ExecStart=/usr/bin/ntpd -g -u ntp:ntp +Restart=always +RestartSec=1 +StartLimitInterval=30 +StartLimitBurst=20 + +[Install] +WantedBy=multi-user.target diff --git a/app/config/_os/usr/lib/systemd/system/php-fpm.service b/app/config/_os/usr/lib/systemd/system/php-fpm.service new file mode 100644 index 00000000..2245a350 --- /dev/null +++ b/app/config/_os/usr/lib/systemd/system/php-fpm.service @@ -0,0 +1,17 @@ +[Unit] +Description=The PHP FastCGI Process Manager +After=syslog.target network.target + +[Service] +Type=notify +PIDFile=/run/php-fpm/php-fpm.pid +PrivateTmp=true +ExecStart=/usr/bin/php-fpm --nodaemonize --pid /run/php-fpm/php-fpm.pid +ExecReload=/bin/kill -USR2 $MAINPID +Restart=always +RestartSec=1 +StartLimitInterval=30 +StartLimitBurst=20 + +[Install] +WantedBy=multi-user.target diff --git a/command/update_os b/command/update_os new file mode 100644 index 00000000..441d8b49 --- /dev/null +++ b/command/update_os @@ -0,0 +1,49 @@ +#!/usr/bin/php +. + * + * file: command/update_os + * version: 0.1 + * coder: Frank Friedmann + * + */ + +function updateOS() +{ + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/rune_SY_wrk.service /usr/lib/systemd/system/'); + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/rune_PL_wrk.service /usr/lib/systemd/system/'); + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/redis.service /usr/lib/systemd/system/'); + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/mpd.service /usr/lib/systemd/system/'); + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/ntpd.service /usr/lib/systemd/system/'); + sysCmd('cp /srv/http/app/config/_os/usr/lib/systemd/system/php-fpm.service /usr/lib/systemd/system/'); + sysCmd('systemctl daemon-reload'); + + sysCmd('cp /srv/http/app/config/_os/etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/'); + + sysCmd('rm /srv/http/command/update_os'); +} \ No newline at end of file From e7f604e7b1df18812b2be289e069bd364619ae90 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Tue, 16 Dec 2014 10:59:42 +0100 Subject: [PATCH 26/80] update on wrk_kernelswitch function --- command/rune_SY_wrk | 1 + 1 file changed, 1 insertion(+) diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 283bd94b..5e2f1d11 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -403,6 +403,7 @@ $redis->pconnect('/tmp/redis.sock'); if (wrk_kernelswitch($redis,$job->args)) { if ($job->args === 'linux-rune-rpi_3.12.13-rt21_wosa') { $redis->set('ao', 'snd_rpi_wsp_1'); + $redis->set('i2smodule', 'none'); $redis->set('orionprofile', 'OrionV2'); } $notification = new stdClass(); From 2cb05d01b515d511a699bfd18f16b6a73b8ca3c4 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Tue, 16 Dec 2014 11:24:18 +0100 Subject: [PATCH 27/80] Removed CmediaFix (no longer needed) --- app/libs/runeaudio.php | 22 +++++----------------- app/settings_ctl.php | 7 ------- app/templates/settings.php | 22 ---------------------- command/rune_SY_wrk | 20 +------------------- 4 files changed, 6 insertions(+), 65 deletions(-) diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 150dc57f..cb0dfc22 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -95,14 +95,8 @@ function sendMpdCommand($sock, $cmd) if (isset($sock['resource'])) { $sock = $sock['resource']; } - if ($cmd == 'cmediafix') { - socket_write($sock, 'pause\n', strlen('pause\n')); - usleep(500000); - socket_write($sock, 'pause\n', strlen('pause\n')); - } else { - $cmd = $cmd."\n"; - socket_write($sock, $cmd, strlen($cmd)); - } + $cmd = $cmd."\n"; + socket_write($sock, $cmd, strlen($cmd)); runelog("MPD COMMAND: (socket=".$sock.")", $cmd); } @@ -339,14 +333,8 @@ function sendSpopCommand($sock, $cmd) if (isset($sock['resource'])) { $sock = $sock['resource']; } - if ($cmd == 'cmediafix') { - socket_write($sock, 'toggle\n', strlen('toggle\n')); - usleep(500000); - socket_write($sock, 'toggle\n', strlen('toggle\n')); - } else { - $cmd = $cmd."\n"; - socket_write($sock, $cmd, strlen($cmd)); - } + $cmd = $cmd."\n"; + socket_write($sock, $cmd, strlen($cmd)); runelog("SPOP COMMAND: (socket=".$sock.")", $cmd); //ui_notify('COMMAND GIVEN','CMD = '.$cmd,'','.9'); } @@ -1219,7 +1207,7 @@ function waitSyWrk($redis, $jobID) } } elseif (!empty($jobID)) { do { - usleep(650000); + usleep(650000); } while ($redis->sIsMember('w_lock', $jobID)); } } diff --git a/app/settings_ctl.php b/app/settings_ctl.php index ed09373a..43f9c7b8 100755 --- a/app/settings_ctl.php +++ b/app/settings_ctl.php @@ -147,12 +147,6 @@ $redis->hGet('spotify','enable') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'spotify', 'action' => 'stop')); } } - // ----- C-MEDIA FIX ----- - if (isset($_POST['cmediafix'][1])){ - $redis->get('cmediafix') == 1 || $redis->set('cmediafix', 1); - } else { - $redis->get('cmediafix') == 0 || $redis->set('cmediafix', 0); - } // ----- SYSTEM COMMANDS ----- if (isset($_POST['syscmd'])){ if ($_POST['syscmd'] === 'reboot') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'reboot')); @@ -183,7 +177,6 @@ $template->coverart = $redis->get('coverart'); $template->globalrandom = $redis->get('globalrandom'); $template->lastfm = $redis->hGetAll('lastfm'); -$template->cmediafix = $redis->get('cmediafix'); $template->proxy = $redis->hGetAll('proxy'); $template->spotify = $redis->hGetAll('spotify'); $template->hwplatformid = $redis->get('hwplatformid'); diff --git a/app/templates/settings.php b/app/templates/settings.php index e6c5089a..76deec80 100755 --- a/app/templates/settings.php +++ b/app/templates/settings.php @@ -292,28 +292,6 @@ -
    -
    - Compatibility fixes -

    For people suffering problems with some receivers and DACs.

    -
    - -
    - - For those who have a CM6631 receiver and experiment issues (noise, crackling) between tracks with different sample rates and/or bit depth.
    - A "dirty" fix that should avoid the problem, do NOT use if everything works normally.
    -
    -
    -
    -
    - -
    -
    -
    -
    Backup / Restore configuration diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 3db75ede..eae8ca9a 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -226,25 +226,7 @@ if ($redis->get('udevil') === '1') { // hashCFG('check_net',$redis); // check /etc/mpd.conf integrity // hashCFG('check_mpd',$redis); -// Cmediafix startup check -if ($redis->get('cmediafix') === '1') { - // close palyer backend connection - if ($activePlayer === 'MPD') { - // open MPD connection - $mpd = openMpdSocket('/run/mpd.sock'); - // send cmediafix command - sendMpdCommand($mpd, 'cmediafix'); - // close MPD connection - closeMpdSocket($mpd); - } elseif ($activePlayer === 'Spotify') { - // open SPOP connection - $spop = openSpopSocket('localhost', 6602, 1); - // send cmediafix command - sendSpopCommand($mpd, 'cmediafix'); - // close SPOP connection - closeSpopSocket($spop); - } -} + // initialize OrionProfile runelog('env: SET KERNEL PROFILE',$redis->get('orionprofile')); sysCmd("/var/www/command/orion_optimize.sh ".$redis->get('orionprofile')." ".$redis->get('hwplatformid')); From c4b79eb99c1130722fb9a95712f4fdc5d6e7591b Mon Sep 17 00:00:00 2001 From: ACXgit Date: Wed, 17 Dec 2014 16:12:27 +0100 Subject: [PATCH 28/80] Tweaking queue's performance --- assets/css/runeui.css | 2 +- assets/img/list-bg.gif | Bin 5558 -> 0 bytes assets/js/runeui.js | 5 +++-- assets/js/runeui.min.js | 2 +- assets/less/runeui-custom.less | 6 ++---- 5 files changed, 7 insertions(+), 8 deletions(-) delete mode 100644 assets/img/list-bg.gif diff --git a/assets/css/runeui.css b/assets/css/runeui.css index 5a224c87..9ba5bb18 100644 --- a/assets/css/runeui.css +++ b/assets/css/runeui.css @@ -7,4 +7,4 @@ * * Copyright 2013 bootstrap-select * Licensed under the MIT license - */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:50px;line-height:19px;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}#playlist{background:transparent url('../img/list-bg.gif') repeat 0 30px}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file + */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file diff --git a/assets/img/list-bg.gif b/assets/img/list-bg.gif deleted file mode 100644 index a1aba37c37541eb0c47f6350b2c739debe380d4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5558 zcmaJ^cU)6v+tzAp7UXT!S|^D57Dyl>plqsOg(N_=TD1;}5XlaZu$Rcnj>z5{vLNgY zVUq>8CxQ!wBoH?$Xg=)sw%_;1*YEkA-#O2?uIs+<^IYfr&N<}yvz@))%&HRTg_SEd z7@O(!`t5q~39ny_-Ti2O%U37Yh#)_I0)}RM4iktYJDcb_r6$I>0B4iqwqCovg4{4z zoJUj$=GQ3iqyA9@fBOIvR~KWa2!{w#5D7!`Gman;$yA33XA{2w$~la~a{tRT!o>Jb z2#w%uvj5A1@t2rxln{)ut);bv|86TQ9 z{DKfxmb<@{^cT>}>;H$6NPnZLv?G}R$@l*hrXGz9!XS=dsFctUf6Ov`$Cpq+4sIbB zKN=n{F+rO+r;EG5X;?bp4=rpIyQ07^L3>`%OxmxCvnO7kQ8V?5oRO_mib zakv17eRkINcKh59*jd}!Sy>&lIdH(%#(lrrK`U!3n?3v8Z2#iAQ~X0o7&7fIZovO= z-TsmL#R{aL<;d=s5L_50;O7tu$@tHb9dQ4gi~T?9{f8Uy&$;aXM=oMH8N`>3{a+jX z*VM9mzI6Y#?egGn<73FnZVy?u^-BHcPfLp*KfGUf_x8=}S1(`a=I68;_3X^^XVXug zJbv_WYVyIv{d;%s+`e`5#`SAguZ)k4s+0=3Y-D(7aG<}hSK8Cv)!EVB*4onC)Ywp8 zC#kIwi-ZDxbya0Wd0A;maZzDGeqL@)c2;Ia`sK7sJT8aLVlwEdDalER7ZWbT$Hm4( zM@2@2hlSFpA;CcuGKomQE`SYLBTpMXu)RgMwJnPVJmvE@9iO=4nuVnvJ@f}tJC76C2zm~`O?GGIJz%4m zz2`|>BqLYQF26hb0l3NB0r@*VikTnqD~Q_S^1()<$cW}cnjPKeVQ1< zE)aLACbUbCtrpH+XGpP}!kX^U2XmhcwpqG(pC!j}i)wquCg(pJ8X;VLd@1p~Vu^Ho zN~eeJF6m8J4c_EL-(A|D4B6}u1F$L^WUPbz-bJ@6ALi({I7Tf2_EgBycB1l}7<(!e znebB`F+l4oRjv);UKhiTS4gX51J8P3O(?)Qu5}of53$hj75F8c#-p#ZX z-Ksg=8TARYSA3^FK$+*v+B*Uj1|ne2{P{P+oMSNE_l3B1{b zZCC$zh`re{4r1T%RGtAl)x)-Ld^TF(82uUI&@^+k0+sK=acEZG6rbvhGjMFt-fbe> z@8LMM&OhjiUi@s})b`@hAZxQL*Qx#0v?|{*-q5+@&Fl@)DJj>v^WEG;XSCkXrR)96 zr^GfC%D-F(jd;Ws*s# z?U+{(Bt4%&#JYY%6tRBTe0yMnLT{-gHjcS~Nln+hJ8#wBI?E!p+#@SVt&?$Ja@%7r ziroIJh(+#D*DA@K^F3fn*Q+rUrTg6^i_-IPUP+OD{tOQ4{R)Z>>ifos9n=p(sDcIz zT_M4P-}#_}hrah^2M=$esDekfUH^$BGvT2_tH0+AG)F6B!WZWzKL0ISAu*oRhX!ul|-XP-PMW}bgqZA`<#A7C6 zEaC~*)iCnuWgqXz=`6i3H}Y8?Wi0Y}QM_T)Oc~ERYPPDF8>JRX#-cQ}Qp0F%!?^b% zFMNs{J>Q`li`IqTHjH`E5A}(8Ic&s>d8I&%$GjeMg~qt&S!D$110aJgt`nDhjiC2I@Ii@Nv?Xg?0sa4C1|{u;mjZq0{p*B5$#7yR z*cUMHgCZ!!MqFxu+0eU19hB;%Ern9U2aG|%ba!~!w>kf>&&ZGGy-NA!%%4#SSB&+yfbMIYV5r3&D`1@geC2+KL}tfr?+4 zAsH3$N;4mZ;;8VNcNDP_<_lDwP#iH6i7PEA4CQHcNOqUD5)ltn{Q;up48p6dcnnp5 zIW<>Btgz>C4vDm}XyN zTxH{Fd&v6$e;| zPL4BgH3>s&h$PXeDbVdUMQAOpMs!BUJbuF|R1z~M^3@|Vxd{E3~Q>esKNQ5e(M#6HH%4e@WbHycNAeQ zO*J(n3hVxaI;^#8u7(m1o_GifZyU6z4d$^Xo|=cZtMsH=YBBi13^Kgq2C0l7VLi~| zTjOue)rL#KlP{RzT~93}k>jk%H^T64ElCnR1)h4Z2=94QBZ<|qrk2#<(xo{`ydM1U z9x1$cwPjs`*Y^)s!y@`1I!-MFIL3hPRn|R z5Bu>tQN)nIv5w^ndGdpVF=SI)&!MoNY|%uFIL+7d;vr9s!I3g|%Z4-_`{_W#kyG zwy{vhe(t1+9FLiAEMBXa{s|m)C5fxh7ehHS?y#tfr=u0>BR&9_SR1}`pvV;-(XwDm!`FOpy}k06w` z0VBhgbX3gab&|Fr1o!33XVFi#=bX?_e-&DY2XVH|7>&1p|`KVa+QAx*53HPm- z5UV+@>$oj7d{;LTJQINEyu0w@yCzZW9Ffv_f68#7O&L2+lXO1NaTmHYvAP&t=ak;? zeJ?ofMG_+B`!VkOL6{3Uh0^uJ2>L;WihGqI>6%9HKBx$BuM2ct&t0J(udw3YR3N%% zeRv;VSj4>*Q(~KrKo{>QfbA; zT;?UxPdc7nzod!RFX^Ou{qirQ>4jAu7rw?`SVO-62wC4&XUnNGjtw+A@fg7_h4Mzz{sXEa`}vW8KZE9Q4C;~nlj7v z9?VKCvzpEn@R=eRvu1`Vu>)nAvKsjjby!v_oz>1~b;?-XGb|~9-Dk=k@L&&N*&}qe zoX=Lu*rO-THvu?Tf1r(daBgBbx9Oa_e9nCt=fMnT3c!72%6;O&oyKyX)48*JuEx~v z+6-5RrD#oguRVBgvAhL3?*pH=DC2#a;pqXFR+?Q}<$39A+@&>)OF#keh3t~SNh}DM z_N`gkTFz7w2gwa&GNLZvuQ@a%iGN^@9@053wK%j?2?(_@`1Q*1fSHHQGJo~V zJci3W&d59|$UG&_JTsf=3(P7?$nf{f60gq+WMtt4Sp<0&X*P=j%nmlorg~>PubPo35afyEc{Q_n5@3G4S$?Bue){#?Rz|+$SbnEGzk4=c z3M}X|D;V%B7{V2dFbd>?0;RlQbhcm|SO`kXzwTKWv99noqwubv@V>n8!EE6au;`Il z(G$<2X<~bC99An zU*k)#-xLFdCD`y119b@$RQj!X=~`szdVJ{yX6Z&@>1IXgR&}WnsBHW12f)a(T~UrE z%rY}!8B9@Tp)Ny!%B{@Ht&!!n`0{Q~5ur#StXcl_1BvR*MU6;NGhWon z6txRQoeEL6TJ#`I*k>+Ycqtmfi$|DZxlpWBh)31paZt@w^P20(nw$8V+d}bxu;#vc z+Z}by6sY!*dF>Nq?KHmjIkR?FSgTRg&Z%p4Ajv~n&1mks_7u1 z=@6^QQ`CggE1SGDO+Mh}!?5OGQO!{+n~t-ZSNzg^O4)oy)9edw@q@MaqgpV8mOxeu zPSiqBw)~LaOo?tF!CI-P)=)xgIIA^M)Ecd9jn%ZqgWD2dZHc1HAVQk~s*NFPV=3D> znl>J|Jq^~Lj%v>&v}d#0b4Bfy;cbPEl6-JSDXgO$)lo_4sAhEtL>(e!M~$XK0`9CQ z_!gl$2h2NLS)J{o&Q4`#x297H?&^be4WPP)2wfwru3N`CmC-`ErfVGBeHGSy9o2o4 z(0!ZLeOJ_dU)lXY(>(<xq3E*nJzteVbK% zTeW>gkpAuP{s~~;E_B%rcE6dpAExTJ(DoxB16J?>YxICEabO>N;4rq|5mIcg9dLyV z?uQS$p$88V2M@6aJ;j44)u5MlP&qts7+vUt9y&%GI?f(CDIPkd8aksL@`Vih!H50P z!-sYa1;*rK#KQ#DFiAU1fs6#hN2utLP~u29dn8gkGL|?TyCo+YB1?eF64A0`qAZmy zV~Axem5ig6@gQ>4qLs}=Wh-0RE>?C<^a-^}L%FgKt{OnAhKQ;Wwn{EmDOIXbt!f-H+Wt{_ reTjROIC`5sdRIJpUp4wbJ30j!djubQf*zZW$-KcHyK-X13djEfL?ZR( diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 3b8c436f..f600a539 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -2719,10 +2719,11 @@ window.resize = function() { window.onscroll = function(e) { if (!isCustomScroll) { pageY = Math.max(window.pageYOffset, 0); // the pixels the current document has been scrolled from the upper left corner of the window - var diff = Math.abs(pageOldY - (pageY - pageHeight)); + var diff = Math.abs(pageOldY - pageY); // console.log('pageY=' + pageY + ', pageOldY=' + pageOldY + ', diff=' + diff + ', pageHeight=' + pageHeight); if (diff > pageHeight) { pageOldY = pageY; + console.log('REDRAW ', pageY); m.redraw(); } } @@ -2735,7 +2736,7 @@ m.module(document.getElementById('playlist'), { var begin = Math.floor(pageY / listEntryHeight) || 0; // first visible entry var end = begin + visibleEntries; // last visible entry var offset = pageY % listEntryHeight; - var buffer = 4; // amount of preceeding and following blocks to load + var buffer = 6; // amount of preceeding and following blocks to load var start = Math.max(begin - visibleEntries * buffer, 0); // index of the first block var finish = Math.min(end + visibleEntries * buffer, Math.max(queueTracks.length - 1, 0)); // index of the last block // var offsetUL = pageY - (listEntryHeight * (begin - start)); diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index e4a7ac44..ba4fde19 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=getPlaylist,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e)}}var c=$(a),d=$(a+"-open"),e=$(a+"-close"); -transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){if(!isCustomScroll){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-(pageY-pageHeight));a>pageHeight&&(pageOldY=pageY,m.redraw())}},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=4,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file +transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageOldY=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){if(!isCustomScroll){pageY=Math.max(window.pageYOffset,0);var a=Math.abs(pageOldY-pageY);a>pageHeight&&(pageOldY=pageY,console.log("REDRAW ",pageY),m.redraw())}},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=6,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file diff --git a/assets/less/runeui-custom.less b/assets/less/runeui-custom.less index 96687489..b8754673 100644 --- a/assets/less/runeui-custom.less +++ b/assets/less/runeui-custom.less @@ -562,7 +562,7 @@ html, body { line-height: 19px; // margin: 0; // background: @body-bg; - // border-bottom: 1px solid darken(@brand-alt, 16%); + border-bottom: 1px solid darken(@brand-alt, 16%); // color: @text-color; font-size: 15px; // text-align: left; @@ -838,9 +838,7 @@ html, body { #playlist, #database { padding: 80px 0; } -#playlist { - background: transparent url('../img/list-bg.gif') repeat 0 30px; // this simulates the presence of entries while they are dinamically rendered in the virtual DOM -} + .sortable-ghost { background: darken(@brand-alt, 10%); } From 36cf9714da893caa4347bd0f497aef66c77d26ca Mon Sep 17 00:00:00 2001 From: Orion1 Date: Wed, 17 Dec 2014 08:17:38 -0700 Subject: [PATCH 29/80] api backend initial draft --- app/api/coverart_ctl.php | 208 +++++++++++++++++++++++++++++++++++++++ app/api/credits_ctl.php | 37 +++++++ app/api/debug_ctl.php | 38 +++++++ app/api/dev_ctl.php | 94 ++++++++++++++++++ app/api/login_ctl.php | 34 +++++++ app/api/mpd_ctl.php | 100 +++++++++++++++++++ app/api/network_ctl.php | 132 +++++++++++++++++++++++++ app/api/playback_ctl.php | 53 ++++++++++ app/api/settings_ctl.php | 184 ++++++++++++++++++++++++++++++++++ app/api/sources_ctl.php | 84 ++++++++++++++++ app/api/tun_ctl.php | 42 ++++++++ app/api_ctl.php | 3 + app/config_ctl.php | 34 +++++++ app/templates/api_lo.php | 1 + app/templates/config.php | 1 + index.php | 6 +- 16 files changed, 1050 insertions(+), 1 deletion(-) create mode 100644 app/api/coverart_ctl.php create mode 100644 app/api/credits_ctl.php create mode 100644 app/api/debug_ctl.php create mode 100644 app/api/dev_ctl.php create mode 100644 app/api/login_ctl.php create mode 100644 app/api/mpd_ctl.php create mode 100644 app/api/network_ctl.php create mode 100644 app/api/playback_ctl.php create mode 100644 app/api/settings_ctl.php create mode 100644 app/api/sources_ctl.php create mode 100644 app/api/tun_ctl.php create mode 100644 app/api_ctl.php create mode 100644 app/config_ctl.php create mode 100644 app/templates/api_lo.php create mode 100644 app/templates/config.php diff --git a/app/api/coverart_ctl.php b/app/api/coverart_ctl.php new file mode 100644 index 00000000..f844057c --- /dev/null +++ b/app/api/coverart_ctl.php @@ -0,0 +1,208 @@ +. + * + * file: file: app/coverart_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// direct output bypass template system +$tplfile = 0; +runelog("\n--------------------- coverart (start) ---------------------"); +// turn off output buffering +ob_implicit_flush(0); +// --------------------- MPD --------------------- +if ($activePlayer === 'MPD') { + // output switch + $output = 0; + include('getid3/audioinfo.class.php'); + // get Last.FM api-key + $lastfm_apikey = $redis->get('lastfm_apikey'); + // get HTTP proxy settings + $proxy = $redis->hGetall('proxy'); + // connect to MPD daemon + $mpd2 = openMpdSocket('/run/mpd.sock', 0); + // fetch MPD status + $status = _parseStatusResponse(MpdStatus($mpd2)); + $curTrack = getTrackInfo($mpd2, $status['song']); + $mpdRoot = "/mnt/MPD/"; + $trackMpdPath = findPLposPath($status['song'], $mpd2); + $currentpath = $mpdRoot.$trackMpdPath; + closeMpdSocket($mpd2); + // debug + runelog("MPD current path", $currentpath); + $request_uri = urldecode($_SERVER['REQUEST_URI']); + runelog("HTTP GET request_uri (urldecoded)", $request_uri); + $request_folder = substr(substr($request_uri, 0, strrpos($request_uri, "/")), 10); + runelog("HTTP GET (request_folder)", $request_folder); + $request_coverfile = substr($request_uri, strrpos($request_uri, "/") + 1); + runelog("HTTP GET (request_coverfile)", $request_coverfile); + $current_mpd_folder = substr(substr($currentpath, 0, strrpos($currentpath, "/")), 9); + runelog("MPD (current_mpd_folder)", $current_mpd_folder); +// --------------------- Spotify --------------------- +} elseif ($redis->get('activePlayer') === 'Spotify') { + runelog('rune_PL_wrk: open SPOP socket'); + $spop = openSpopSocket('localhost', 6602, 1); +} +if ((substr($request_coverfile, 0, 2) === '?v' OR $current_mpd_folder === $request_folder) && $activePlayer === 'MPD') { + // extact song details + if (isset($curTrack[0]['Title'])) { + $status['currentartist'] = $curTrack[0]['Artist']; + $status['currentsong'] = $curTrack[0]['Title']; + $status['currentalbum'] = $curTrack[0]['Album']; + $status['fileext'] = parseFileStr($curTrack[0]['file'], '.'); + } + //Extract info from current audio file (using ZendMedia library) + /* if ($status['fileext'] === 'flac') { + require_once('Zend/Media/Flac.php'); + $flac = new Zend_Media_Flac($currentpath); + if ($flac->hasMetadataBlock(Zend_Media_Flac::PICTURE)) { + // debug + runelog("coverart match: embedded (ZendMedia lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$flac->getPicture()->getMimeType()); + echo $flac->getPicture()->getData(); + $output = 1; + } + } */ + //Extract info from current audio file (using GetID3 library) + if ($output === 0) { + $au = new AudioInfo(); + $auinfo = $au->Info($currentpath); + // 1. try to find embedded coverart + if (!empty($auinfo['comments']['picture'][0]['data'])) { + // debug + runelog("coverart match: embedded (GetID3 lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .$auinfo['comments']['picture'][0]['image_mime']); + echo $auinfo['comments']['picture'][0]['data']; + $output = 1; + } + } + // 2. try to find local coverart + if ($output === 0) { + $local_cover_root = substr($currentpath, 0, strrpos($currentpath, "/")); + $local_cover_path[] = $local_cover_root.'/folder.jpg'; + $local_cover_path[] = $local_cover_root.'/cover.jpg'; + $local_cover_path[] = $local_cover_root.'/folder.png'; + $local_cover_path[] = $local_cover_root.'/cover.png'; + foreach ($local_cover_path as $path) { + if (file_exists($path)) { + $local_cover_path = $path; + $output = 1; + break; + } + } + // debug + runelog("coverart: local (path): ", $local_cover_path); + if ($output === 1) { + // debug + runelog("coverart match: cover-local"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($local_cover_path)); + readfile($local_cover_path); + } + } + // 3.0 try to find coverart on Last.FM (Album) + if ($output === 0) { + $cover_url = ui_lastFM_coverart($status['currentartist'], $status['currentalbum'], $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 1) coverURL=", $cover_url); + $lastfm_img = curlGet($cover_url, $proxy); + $bufferinfo = new finfo(FILEINFO_MIME); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } else { + // 3.1 try to find coverart on Last.FM (Artist) + $cover_url = ui_lastFM_coverart($status['currentartist'], '', $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 2) coverURL=", $cover_url); + if (!empty($cover_url)) { + $lastfm_img = curlGet($cover_url, $proxy); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } + } + } + if (!empty($lastfm_img)) { + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$lastfm_img_mime); + echo $lastfm_img; + $output = 1; + } + } + // 4. serve DEFAULT rune-cover image + if ($output === 0) { + // debug + runelog("coverart match: cover-default"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($_SERVER['HOME'].'/assets/img/cover-default.png')); + readfile($_SERVER['HOME'].'/assets/img/cover-default.png'); + $output = 1; + } +} else { + if ($activePlayer === 'Spotify') { + $count = 1; + do { + sendSpopCommand($spop, 'image'); + unset($spotify_cover); + $spotify_cover = readSpopResponse($spop); + $spotify_cover = json_decode($spotify_cover); + usleep(500000); + runelog('coverart (spotify): retry n: '.$count, $spotify_cover->status); + if ($spotify_cover->status === 'ok') { + $spotify_cover = base64_decode($spotify_cover->data); + break; + } + $count++; + } while ($count !== 10); + $bufferinfo = new finfo(FILEINFO_MIME); + $spotify_cover_mime = $bufferinfo->buffer($spotify_cover); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$spotify_cover_mime); + echo $spotify_cover; + } else { + // redirect to /covers NGiNX location + $local_cover_url = 'http://'.$_SERVER["SERVER_ADDR"].'/covers/'.$request_folder.'/'.$request_coverfile; + runelog("coverart: redirect to local-coverart (url): ", $local_cover_url); + header('Location: '.$local_cover_url, true, 301); + } +} +runelog("\n--------------------- coverart (end) ---------------------"); diff --git a/app/api/credits_ctl.php b/app/api/credits_ctl.php new file mode 100644 index 00000000..87eeddb6 --- /dev/null +++ b/app/api/credits_ctl.php @@ -0,0 +1,37 @@ +. + * + * file: app/credits_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + + $template->buildversion = $redis->get('buildversion'); + $template->release = $redis->get('release'); + \ No newline at end of file diff --git a/app/api/debug_ctl.php b/app/api/debug_ctl.php new file mode 100644 index 00000000..e1ddb424 --- /dev/null +++ b/app/api/debug_ctl.php @@ -0,0 +1,38 @@ +. + * + * file: app/debug_ctl.php + * version: 1.3 + * + */ +// ob_start(); +// echo debug_data($redis); +// $debugdata = ob_get_clean(); +$jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'debug')); +waitSyWrk($redis, $jobID); +$template->debug = $redis->get('debugdata'); diff --git a/app/api/dev_ctl.php b/app/api/dev_ctl.php new file mode 100644 index 00000000..b361e581 --- /dev/null +++ b/app/api/dev_ctl.php @@ -0,0 +1,94 @@ +. + * + * file: app/dev_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// inspect POST +if (isset($_POST)) { + // ----- DEV MODE ----- + if (isset($_POST['mode'])) { + if ($_POST['mode']['dev']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('dev') == 1 || $redis->set('dev', 1); + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('dev') == 0 || $redis->set('dev', 0); + } + // ----- DEBUG ----- + if ($_POST['mode']['debug']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('debug') == 0 || $redis->set('debug', 0); + } + } + // ----- OPCACHE ----- + if (isset($_POST['opcache'])) { + if ($_POST['opcache']['enable'] == 1) { + // create worker job (enable php opcache) + $redis->get('opcache') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'enable')); + } else { + // create worker job (disable php opcache) + $redis->get('opcache') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'disable')); + } + } + if (isset($_POST['syscmd'])) { + // ----- BLANK PLAYERID ----- + if ($_POST['syscmd'] === 'blankplayerid') $redis->set('playerid',''); + // ----- CLEARIMG ----- + if ($_POST['syscmd'] === 'clearimg') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'clearimg')); + // ----- CHECK FS PERMISSIONS ----- + if ($_POST['syscmd'] === 'syschmod') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sysAcl')); + // ----- RESTART MPD ----- + if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); + // ----- RESET NET CONFIG ----- + if ($_POST['syscmd'] === 'netconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'reset')); + // ----- RESET MPD CONFIG ----- + if ($_POST['syscmd'] === 'mpdconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); + // ----- RESTART PHP-FPM ----- + if ($_POST['syscmd'] === 'phprestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'phprestart')); + // ----- GIT PULL ----- + if ($_POST['syscmd'] === 'gitpull') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'gitpull')); + // ----- RESTART WORKERS ----- + if (isset($_POST['syscmd']['wrkrestart'])) $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wrkrestart', 'args' => $_POST['syscmd']['wrkrestart'])); + } +} +waitSyWrk($redis, $jobID); +$template->debug = $redis->get('debug'); +$template->playerid = $redis->get('playerid'); +$template->opcache = $redis->get('opcache'); +$template->gitbranch = $redis->hGet('git', 'branch'); +// debug +// var_dump($template->dev); +// var_dump($template->debug); +// var_dump($template->opcache); diff --git a/app/api/login_ctl.php b/app/api/login_ctl.php new file mode 100644 index 00000000..3f9377c0 --- /dev/null +++ b/app/api/login_ctl.php @@ -0,0 +1,34 @@ +. + * + * file: app/login_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + \ No newline at end of file diff --git a/app/api/mpd_ctl.php b/app/api/mpd_ctl.php new file mode 100644 index 00000000..49302cf2 --- /dev/null +++ b/app/api/mpd_ctl.php @@ -0,0 +1,100 @@ +. + * + * file: mpd_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + if (isset($_POST)) { + // switch audio output + if (isset($_POST['ao'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'switchao', 'args' => $_POST['ao'])); + } + // reset MPD configuration + if (isset($_POST['reset'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); + } + // update MPD configuration + if (isset($_POST['conf'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'update', 'args' => $_POST['conf'])); + } + // manual MPD configuration + if (isset($_POST['mpdconf'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfgman', 'args' => $_POST['mpdconf'])); + } + } +waitSyWrk($redis, $jobID); +// check integrity of /etc/network/interfaces +if(!hashCFG('check_mpd', $redis)) { + $template->mpdconf = file_get_contents('/etc/mpd.conf'); + // set manual config template + $template->content = "mpd_manual"; +} else { + $template->conf = $redis->hGetAll('mpdconf'); + $i2smodule = $redis->get('i2smodule'); + // debug + // echo $i2smodule."\n"; + $acards = $redis->hGetAll('acards'); + // debug + // print_r($acards); + foreach ($acards as $card => $data) { + $acard_data = json_decode($data); + // debug + // echo $card."\n"; + // print_r($acard_data); + if ($i2smodule !== 'none') { + $acards_details = $redis->hGet('acards_details', $i2smodule); + } else { + $acards_details = $redis->hGet('acards_details', $card); + } + if (!empty($acards_details)) { + $details = json_decode($acards_details); + // debug + // echo "acards_details\n"; + // print_r($details); + if ($details->sysname === $card) { + if ($details->type === 'integrated_sub') { + $sub_interfaces = $redis->sMembers($card); + foreach ($sub_interfaces as $int) { + $sub_int_details = json_decode($int); + // TODO !!! check + $audio_cards[] = $sub_int_details; + } + } + if ($details->extlabel !== 'none') $acard_data->extlabel = $details->extlabel; + } + } + $audio_cards[] = $acard_data; + } + osort($audio_cards, 'extlabel'); + // debug + // print_r($audio_cards); + $template->acards = $audio_cards; + $template->ao = $redis->get('ao'); +} diff --git a/app/api/network_ctl.php b/app/api/network_ctl.php new file mode 100644 index 00000000..d406379a --- /dev/null +++ b/app/api/network_ctl.php @@ -0,0 +1,132 @@ +. + * + * file: app/network_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + +// inspect POST +if (isset($_POST)) { + if (isset($_POST['nic']) && !isset($_POST['wifiprofile'])) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'config'", $_POST['nic']); + $redis->get($_POST['nic']['name']) === json_encode($nic) || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'config', 'args' => $_POST['nic'])); + } + if (isset($_POST['refresh'])) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'refresh'", $_POST['nic']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'refresh')); + } + if (isset($_POST['wifiprofile'])) { + switch ($_POST['wifiprofile']['action']) { + case 'add': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'add'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'add', 'args' => $_POST['wifiprofile'])); + break; + case 'edit': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'edit'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'edit', 'args' => $_POST['wifiprofile'])); + break; + case 'delete': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'delete'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'delete', 'args' => $_POST['wifiprofile'])); + break; + case 'connect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'connect'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'connect', 'args' => $_POST['wifiprofile'] )); + break; + case 'disconnect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'disconnect'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'disconnect', 'args' => $_POST['wifiprofile'] )); + break; + } + } +} + +waitSyWrk($redis,$jobID); +$template->nics = wrk_netconfig($redis, 'getnics'); +$template->wlan_autoconnect = $redis->Get('wlan_autoconnect'); +if ($redis->Exists(urldecode($template->uri(4)))) $template->stored = 1; +if (isset($template->action)) { + // check if we are into interface details (ex. http://runeaudio/network/edit/eth0) + if (isset($template->arg)) { + // check if there is a stored profile for current nic + $nic_stored_profile = json_decode($redis->Get($template->uri(3))); + // runelog('nic stored profile: ',$nic_stored_profile); + if (!empty($nic_stored_profile)) { + if ($nic_stored_profile->dhcp === '0') { + // read nic stored profile + $template->nic_stored = $nic_stored_profile; + } + } + // retrieve current nic status data (detected from the system) + $nic_connection = $redis->hGet('nics', $template->arg); + $template->nic = json_decode($nic_connection); + // check if we action is = 'edit' or 'wlan' (ex. http://runeaudio/network/edit/....) + if ($template->action === 'edit') { + // fetch current (stored) nic configuration data + if ($redis->get($template->arg)) { + $template->{$template->arg} = json_decode($redis->get($template->arg)); + // ok nic configuration not stored, but check if it is configured + } else if ($nic_connection == null) { + // last case, nonexistant nic. route to error template + $template->content = 'error'; + } + // check if the current nic is wireless + if ($template->nic->wireless === 1) { + $template->wlans = json_decode($redis->get('wlans')); + $template->wlan_profiles = new stdClass(); + if ($wlan_profiles = wrk_netconfig($redis, 'getstoredwlans')) { + foreach ($wlan_profiles as $key => $value) { + $template->wlan_profiles->{$key} = json_decode($value); + } + } + } + // we are in the wlan subtemplate (ex. http://runeaudio/network/wlan/....) + } else { + // check if we want to store a wifi profile, that is not in range. (ex. http://runeaudio/network/wlan/add ) + if ($template->uri(4) === 'add') { + $template->addprofile = 1; + } else { + // we are connecting to a visible network + $template->wlans = json_decode($redis->get('wlans')); + foreach ($template->wlans->{$template->uri(3)} as $key => $value) { + // if we are in a stored profile, retrieve his details + if ($template->stored) { + $template->profile_{urldecode($template->uri(4))} = json_decode($redis->hGet('wlan_profiles', urldecode($template->uri(4)))); + } + // check if we are in a connected profile + if ($template->uri(4) === $value->ESSID) { + // retrieve SSID details + $template->{$template->uri(4)} = $value; + } + } + } + } + } +} diff --git a/app/api/playback_ctl.php b/app/api/playback_ctl.php new file mode 100644 index 00000000..296ad06a --- /dev/null +++ b/app/api/playback_ctl.php @@ -0,0 +1,53 @@ +. + * + * file: app/playback_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +$template->activePlayer = $redis->get('activePlayer'); +if ($redis->get('coverart') == 1) { + $template->coverart = 1; + $template->colspan = 4; +} else { + $template->coverart = 0; + $template->colspan = 6; +} +if ($redis->get('volume') == 1 && $template->activePlayer !== 'Spotify') { + $template->volume['color'] = '#0095D8'; + $template->volume['readonly'] = 'false'; +} else { + //$_volumeColor = '#002c40'; + $template->volume['color'] = '#1A242F'; + $template->volume['readonly'] = 'true'; + $template->volume['disabled'] = 1; + $template->volume['divclass'] = 'nomixer'; +} +$template->dev = $redis->get; +$template->spotify = $redis->hGet('spotify', 'enable'); diff --git a/app/api/settings_ctl.php b/app/api/settings_ctl.php new file mode 100644 index 00000000..43f9c7b8 --- /dev/null +++ b/app/api/settings_ctl.php @@ -0,0 +1,184 @@ +. + * + * file: app/settings_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// inspect POST +if (isset($_POST)) { + // ----- HOSTNAME ----- + if (isset($_POST['hostname'])) { + if (empty($_POST['hostname'])) { + $args = 'runeaudio'; + } else { + $args = $_POST['hostname']; + } + $redis->get('hostname') == $_POST['hostname'] || $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'hostname', 'args' => $args )); + } + // ----- TIME SETTINGS ----- + if (isset($_POST['ntpserver'])) { + if (empty($_POST['ntpserver'])) { + $args = 'pool.ntp.org'; + } else { + $args = $_POST['ntpserver']; + } + $redis->get('ntpserver') == $args || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'ntpserver', 'args' => $args)); + } + if (isset($_POST['timezone'])) { + $args = $_POST['timezone']; + $redis->get('timezone') == $args || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'timezone', 'args' => $args)); + } + // ----- KERNEL ----- + if (isset($_POST['kernel'])) { + // submit worker job + if ($redis->get('kernel') !== $_POST['kernel']) { + $job = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'kernelswitch', 'args' => $_POST['kernel'])); + $notification = new stdClass(); + $notification->title = 'Kernel switch'; + $notification->text = 'Kernel switch started...'; + wrk_notify($redis, 'startjob', $notification, $job); + $jobID[] = $job; + } + } + if (isset($_POST['orionprofile'])) { + // submit worker job + $redis->get('orionprofile') == $_POST['orionprofile'] || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'orionprofile', 'args' => $_POST['orionprofile'])); + } + if (isset($_POST['i2smodule'])) { + // submit worker job + if ($redis->get('i2smodule') !== $_POST['i2smodule']) { + $notification = new stdClass(); + if ($_POST['i2smodule'] !== 'none') { + $notification->title = 'Loading I²S kernel module'; + } else { + $notification->title = 'Unloading I²S kernel module'; + } + $job = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'i2smodule', 'args' => $_POST['i2smodule'])); + $notification->text = 'Please wait'; + wrk_notify($redis, 'startjob', $notification, $job); + $jobID[] = $job; + } + + // autoswitch optimized kernel profile for BerryNOS mini DAC + if ($_POST['i2smodule'] === 'berrynosmini') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'orionprofile', 'args' => 'OrionV3_berrynosmini')); + // autoswitch optimized kernel profile for IQaudIO Pi-DAC + if ($_POST['i2smodule'] === 'iqaudiopidac') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'orionprofile', 'args' => 'OrionV3_iqaudio')); + } + // ----- FEATURES ----- + if (isset($_POST['features'])) { + if ($_POST['features']['airplay']['enable'] == 1) { + if ($redis->hGet('airplay','enable') !== $_POST['features']['airplay']['enable'] OR $redis->hGet('airplay','name') !== $_POST['features']['airplay']['name']) { + // create worker job (start shairport) + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'airplay', 'action' => 'start', 'args' => $_POST['features']['airplay']['name'])); + } + } else { + // create worker job (stop shairport) + $redis->hGet('airplay','enable') === '0' || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'airplay', 'action' => 'stop', 'args' => $_POST['features']['airplay']['name'])); + } + if ($_POST['features']['dlna']['enable'] == 1) { + if ($redis->hGet('dlna','enable') !== $_POST['features']['dlna']['enable'] OR $redis->hGet('dlna','name') !== $_POST['features']['dlna']['name']) { + // create worker job (start upmpdcli) + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'dlna', 'action' => 'start', 'args' => $_POST['features']['dlna']['name'])); + } + } else { + // create worker job (stop upmpdcli) + $redis->hGet('dlna','enable') === '0' || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'dlna', 'action' => 'stop', 'args' => $_POST['features']['dlna']['name'])); + } + if ($_POST['features']['udevil'] == 1) { + // create worker job (start udevil) + $redis->get('udevil') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'udevil', 'action' => 'start')); + } else { + // create worker job (stop udevil) + $redis->get('udevil') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'udevil', 'action' => 'stop')); + } + if ($_POST['features']['coverart'] == 1) { + $redis->get('coverart') == 1 || $redis->set('coverart', 1); + } else { + $redis->get('coverart') == 0 || $redis->set('coverart', 0); + } + if ($_POST['features']['globalrandom'] == 1) { + $redis->get('globalrandom') == 1 || $redis->set('globalrandom', 1); + } else { + $redis->get('globalrandom') == 0 || $redis->set('globalrandom', 0); + } + if ($_POST['features']['lastfm']['enable'] == 1) { + // create worker job (start mpdscribble) + if (($_POST['features']['lastfm']['user'] != $redis->hGet('lastfm', 'user') OR $_POST['features']['lastfm']['pass'] != $redis->hGet('lastfm', 'pass')) OR $redis->hGet('lastfm', 'enable') != $_POST['features']['lastfm']['enable']) { + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'lastfm', 'action' => 'start', 'args' => $_POST['features']['lastfm'])); + } + } else { + // create worker job (stop mpdscribble) + $redis->hGet('lastfm','enable') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'lastfm', 'action' => 'stop')); + } + if ($_POST['features']['spotify']['enable'] == 1) { + // create worker job (start mpdscribble) + if (($_POST['features']['spotify']['user'] != $redis->hGet('spotify', 'user') OR $_POST['features']['spotify']['pass'] != $redis->hGet('spotify', 'pass')) OR $redis->hGet('spotify', 'enable') != $_POST['features']['spotify']['enable']) { + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'spotify', 'action' => 'start', 'args' => $_POST['features']['spotify'])); + } + } else { + // create worker job (stop spotify) + $redis->hGet('spotify','enable') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'spotify', 'action' => 'stop')); + } + } + // ----- SYSTEM COMMANDS ----- + if (isset($_POST['syscmd'])){ + if ($_POST['syscmd'] === 'reboot') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'reboot')); + if ($_POST['syscmd'] === 'poweroff') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'poweroff')); + if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); + if ($_POST['syscmd'] === 'backup') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'backup')); + } +} +waitSyWrk($redis,$jobID); +// push backup file +if ($_POST['syscmd'] === 'backup') { + pushFile($redis->hGet('w_msg', $jobID[0])); + $redis->hDel('w_msg', $jobID[0]); +} +// collect system status +$template->sysstate['kernel'] = file_get_contents('/proc/version'); +$template->sysstate['time'] = implode('\n', sysCmd('date')); +$template->sysstate['uptime'] = date('d:H:i:s', strtok(file_get_contents('/proc/uptime'), ' ' )); +$template->sysstate['HWplatform'] = $redis->get('hwplatform')." (".$redis->get('hwplatformid').")"; +$template->sysstate['playerID'] = $redis->get('playerid'); +$template->hostname = $redis->get('hostname'); +$template->ntpserver = $redis->get('ntpserver'); +$template->timezone = $redis->get('timezone'); +$template->orionprofile = $redis->get('orionprofile'); +$template->airplay = $redis->hGetAll('airplay'); +$template->dlna = $redis->hGetAll('dlna'); +$template->udevil = $redis->get('udevil'); +$template->coverart = $redis->get('coverart'); +$template->globalrandom = $redis->get('globalrandom'); +$template->lastfm = $redis->hGetAll('lastfm'); +$template->proxy = $redis->hGetAll('proxy'); +$template->spotify = $redis->hGetAll('spotify'); +$template->hwplatformid = $redis->get('hwplatformid'); +$template->i2smodule = $redis->get('i2smodule'); +$template->kernel = $redis->get('kernel'); diff --git a/app/api/sources_ctl.php b/app/api/sources_ctl.php new file mode 100644 index 00000000..06586352 --- /dev/null +++ b/app/api/sources_ctl.php @@ -0,0 +1,84 @@ +. + * + * file: app/sources_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// inspect POST +if (isset($_POST)) { + if ($_POST['updatempd'] == 1) sendMpdCommand($mpd, 'update'); + if ($_POST['mountall'] == 1) $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'mountall' )); + if (isset($_POST['usb-umount'])) $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'umountusb', 'args' => $_POST['usb-umount'])); + if (!empty($_POST['mount'])) { + $_POST['mount']['remotedir'] = str_replace('\\', '/', $_POST['mount']['remotedir']); + if ($_POST['mount']['rsize'] == '') $_POST['mount']['rsize'] = 16384; + if ($_POST['mount']['wsize'] == '') $_POST['mount']['wsize'] = 17408; + if ($_POST['mount']['options'] == '') { + if ($_POST['mount']['type'] === 'cifs' OR $_POST['mount']['type'] === 'osx') { + $_POST['mount']['options'] = "cache=none,ro"; + } else { + $_POST['mount']['options'] = "nfsvers=3,ro"; + } + } + if ($_POST['action'] == 'add') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'add', 'args' => $_POST['mount'])); + if ($_POST['action'] == 'edit') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'edit', 'args' => $_POST['mount'])); + if ($_POST['action'] == 'delete') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'delete', 'args' => $_POST['mount'])); + if ($_POST['action'] == 'reset') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfgman', 'action' => 'reset' )); + } +} +waitSyWrk($redis, $jobID); +$source = netMounts($redis, 'read'); +if($source !== true) { + foreach ($source as $mp) { + if (wrk_checkStrSysfile('/proc/mounts', '/mnt/MPD/NAS/'.$mp['name'])) { + $mp['status'] = 1; + } else { + $mp['status'] = 0; + } + $mounts[]=$mp; + } +} +$template->mounts = $mounts; +$usbmounts = $redis->hGetAll('usbmounts'); +foreach ($usbmounts as $usbmount) { + $template->usbmounts[] = json_decode($usbmount); +} +if (isset($template->action)) { + if (isset($template->arg)) { + foreach ($source as $mp) { + if ($mp['id'] == $template->arg) { + $template->mount = $mp; + } + } + $template->title = 'Edit network mount'; + } else { + $template->title = 'Add new network mount'; + } +} diff --git a/app/api/tun_ctl.php b/app/api/tun_ctl.php new file mode 100644 index 00000000..93ca34a4 --- /dev/null +++ b/app/api/tun_ctl.php @@ -0,0 +1,42 @@ +. + * + * file: app/tun_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// disable main template output +$tplfile = 0; +$proxy = $redis->hGetall('proxy'); +if ($proxy['enable'] === '1') { + echo curlGet(substr($_SERVER["REQUEST_URI"], 5), $proxy); +} else { + echo curlGet(substr($_SERVER["REQUEST_URI"], 5)); +} + \ No newline at end of file diff --git a/app/api_ctl.php b/app/api_ctl.php new file mode 100644 index 00000000..008d7b93 --- /dev/null +++ b/app/api_ctl.php @@ -0,0 +1,3 @@ +action.'_ctl.php'); diff --git a/app/config_ctl.php b/app/config_ctl.php new file mode 100644 index 00000000..4efb9ea9 --- /dev/null +++ b/app/config_ctl.php @@ -0,0 +1,34 @@ +. + * + * file: app/config_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + \ No newline at end of file diff --git a/app/templates/api_lo.php b/app/templates/api_lo.php new file mode 100644 index 00000000..3646e95a --- /dev/null +++ b/app/templates/api_lo.php @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/templates/config.php b/app/templates/config.php new file mode 100644 index 00000000..e9275538 --- /dev/null +++ b/app/templates/config.php @@ -0,0 +1 @@ +
    \ No newline at end of file diff --git a/index.php b/index.php index dc2c12b4..d5776741 100755 --- a/index.php +++ b/index.php @@ -53,8 +53,10 @@ $template->activePlayer = $activePlayer; // allowed controllers $controllers = array( - 'credits', + 'api', + 'config', 'coverart', + 'credits', 'dev', 'debug', 'help', @@ -122,6 +124,8 @@ // plates: render layout (if you want to output direct, set $tplfile = 0 into controller) if ($tplfile !== 0) { echo $template->render('default_lo'); +} elseif ($template->uri(1) === 'api') { + echo $template->render('api_lo'); } // close palyer backend connection if ($activePlayer === 'MPD') { From c2cd19fbc3203e93ba84e8ce605abe1f40adca17 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Thu, 18 Dec 2014 02:17:57 +0100 Subject: [PATCH 30/80] Updated Bootstrap-select to v1.6.3 --- assets/js/vendor/bootstrap-select.min.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/assets/js/vendor/bootstrap-select.min.js b/assets/js/vendor/bootstrap-select.min.js index cd4f7fe2..074e3837 100644 --- a/assets/js/vendor/bootstrap-select.min.js +++ b/assets/js/vendor/bootstrap-select.min.js @@ -1,8 +1,8 @@ /*! - * bootstrap-select v1.4.2 - * http://silviomoreto.github.io/bootstrap-select/ + * Bootstrap-select v1.6.3 (http://silviomoreto.github.io/bootstrap-select/) * - * Copyright 2013 bootstrap-select - * Licensed under the MIT license + * Copyright 2013-2014 bootstrap-select + * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE) */ -;!function(b){b.expr[":"].icontains=function(e,c,d){return b(e).text().toUpperCase().indexOf(d[3].toUpperCase())>=0};var a=function(d,c,f){if(f){f.stopPropagation();f.preventDefault()}this.$element=b(d);this.$newElement=null;this.$button=null;this.$menu=null;this.options=b.extend({},b.fn.selectpicker.defaults,this.$element.data(),typeof c=="object"&&c);if(this.options.title===null){this.options.title=this.$element.attr("title")}this.val=a.prototype.val;this.render=a.prototype.render;this.refresh=a.prototype.refresh;this.setStyle=a.prototype.setStyle;this.selectAll=a.prototype.selectAll;this.deselectAll=a.prototype.deselectAll;this.init()};a.prototype={constructor:a,init:function(){this.$element.hide();this.multiple=this.$element.prop("multiple");var d=this.$element.attr("id");this.$newElement=this.createView();this.$element.after(this.$newElement);this.$menu=this.$newElement.find("> .dropdown-menu");this.$button=this.$newElement.find("> button");this.$searchbox=this.$newElement.find("input");if(d!==undefined){var c=this;this.$button.attr("data-id",d);b('label[for="'+d+'"]').click(function(f){f.preventDefault();c.$button.focus()})}this.checkDisabled();this.clickListener();if(this.options.liveSearch){this.liveSearchListener()}this.render();this.liHeight();this.setStyle();this.setWidth();if(this.options.container){this.selectPosition()}this.$menu.data("this",this);this.$newElement.data("this",this)},createDropdown:function(){var c=this.multiple?" show-tick":"";var f=this.options.header?'
    '+this.options.header+"
    ":"";var e=this.options.liveSearch?'':"";var d='
    ';return b(d)},createView:function(){var c=this.createDropdown();var d=this.createLi();c.find("ul").append(d);return c},reloadLi:function(){this.destroyLi();var c=this.createLi();this.$menu.find("ul").append(c)},destroyLi:function(){this.$menu.find("li").remove()},createLi:function(){var d=this,e=[],c="";this.$element.find("option").each(function(){var i=b(this);var g=i.attr("class")||"";var h=i.attr("style")||"";var m=i.data("content")?i.data("content"):i.html();var k=i.data("subtext")!==undefined?''+i.data("subtext")+"":"";var j=i.data("icon")!==undefined?' ':"";if(j!==""&&(i.is(":disabled")||i.parent().is(":disabled"))){j=""+j+""}if(!i.data("content")){m=j+''+m+k+""}if(d.options.hideDisabled&&(i.is(":disabled")||i.parent().is(":disabled"))){e.push('')}else{if(i.parent().is("optgroup")&&i.data("divider")!==true){if(i.index()===0){var l=i.parent().attr("label");var n=i.parent().data("subtext")!==undefined?''+i.parent().data("subtext")+"":"";var f=i.parent().data("icon")?' ':"";l=f+''+l+n+"";if(i[0].index!==0){e.push('
    '+l+"
    "+d.createA(m,"opt "+g,h))}else{e.push("
    "+l+"
    "+d.createA(m,"opt "+g,h))}}else{e.push(d.createA(m,"opt "+g,h))}}else{if(i.data("divider")===true){e.push('
    ')}else{if(b(this).data("hidden")===true){e.push("")}else{e.push(d.createA(m,g,h))}}}}});b.each(e,function(f,g){c+="
  • "+g+"
  • "});if(!this.multiple&&this.$element.find("option:selected").length===0&&!this.options.title){this.$element.find("option").eq(0).prop("selected",true).attr("selected","selected")}return b(c)},createA:function(e,c,d){return''+e+''},render:function(){var d=this;this.$element.find("option").each(function(h){d.setDisabled(h,b(this).is(":disabled")||b(this).parent().is(":disabled"));d.setSelected(h,b(this).is(":selected"))});this.tabIndex();var g=this.$element.find("option:selected").map(function(){var j=b(this);var i=j.data("icon")&&d.options.showIcon?' ':"";var h;if(d.options.showSubtext&&j.attr("data-subtext")&&!d.multiple){h=' '+j.data("subtext")+""}else{h=""}if(j.data("content")&&d.options.showContent){return j.data("content")}else{if(j.attr("title")!==undefined){return j.attr("title")}else{return i+j.html()+h}}}).toArray();var f=!this.multiple?g[0]:g.join(this.options.multipleSeparator);if(this.multiple&&this.options.selectedTextFormat.indexOf("count")>-1){var c=this.options.selectedTextFormat.split(">");var e=this.options.hideDisabled?":not([disabled])":"";if((c.length>1&&g.length>c[1])||(c.length==1&&g.length>=2)){f=this.options.countSelectedText.replace("{0}",g.length).replace("{1}",this.$element.find('option:not([data-divider="true"]):not([data-hidden="true"])'+e).length)}}if(!f){f=this.options.title!==undefined?this.options.title:this.options.noneSelectedText}this.$button.attr("title",b.trim(f));this.$newElement.find(".filter-option").html(f)},setStyle:function(e,d){if(this.$element.attr("class")){this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device/gi,""))}var c=e?e:this.options.style;if(d=="add"){this.$button.addClass(c)}else{if(d=="remove"){this.$button.removeClass(c)}else{this.$button.removeClass(this.options.style);this.$button.addClass(c)}}},liHeight:function(){var e=this.$menu.parent().clone().appendTo("body"),f=e.addClass("open").find("> .dropdown-menu"),d=f.find("li > a").outerHeight(),c=this.options.header?f.find(".popover-title").outerHeight():0,g=this.options.liveSearch?f.find(".bootstrap-select-searchbox").outerHeight():0;e.remove();this.$newElement.data("liHeight",d).data("headerHeight",c).data("searchHeight",g)},setSize:function(){var h=this,d=this.$menu,i=d.find(".inner"),t=this.$newElement.outerHeight(),f=this.$newElement.data("liHeight"),r=this.$newElement.data("headerHeight"),l=this.$newElement.data("searchHeight"),k=d.find("li .divider").outerHeight(true),q=parseInt(d.css("padding-top"))+parseInt(d.css("padding-bottom"))+parseInt(d.css("border-top-width"))+parseInt(d.css("border-bottom-width")),o=this.options.hideDisabled?":not(.disabled)":"",n=b(window),g=q+parseInt(d.css("margin-top"))+parseInt(d.css("margin-bottom"))+2,p,u,s,j=function(){u=h.$newElement.offset().top-n.scrollTop();s=n.height()-u-t};j();if(this.options.header){d.css("padding-top",0)}if(this.options.size=="auto"){var e=function(){var v;j();p=s-g;if(h.options.dropupAuto){h.$newElement.toggleClass("dropup",(u>s)&&((p-g)3){v=f*3+g-2}else{v=0}d.css({"max-height":p+"px",overflow:"hidden","min-height":v+"px"});i.css({"max-height":p-r-l-q+"px","overflow-y":"auto","min-height":v-q+"px"})};e();b(window).resize(e);b(window).scroll(e)}else{if(this.options.size&&this.options.size!="auto"&&d.find("li"+o).length>this.options.size){var m=d.find("li"+o+" > *").filter(":not(.div-contain)").slice(0,this.options.size).last().parent().index();var c=d.find("li").slice(0,m+1).find(".div-contain").length;p=f*this.options.size+c*k+q;if(h.options.dropupAuto){this.$newElement.toggleClass("dropup",(u>s)&&(p .dropdown-menu").css("width");d.remove();this.$newElement.css("width",c)}else{if(this.options.width=="fit"){this.$menu.css("min-width","");this.$newElement.css("width","").addClass("fit-width")}else{if(this.options.width){this.$menu.css("min-width","");this.$newElement.css("width",this.options.width)}else{this.$menu.css("min-width","");this.$newElement.css("width","")}}}if(this.$newElement.hasClass("fit-width")&&this.options.width!=="fit"){this.$newElement.removeClass("fit-width")}},selectPosition:function(){var e=this,d="
    ",f=b(d),h,g,c=function(i){f.addClass(i.attr("class")).toggleClass("dropup",i.hasClass("dropup"));h=i.offset();g=i.hasClass("dropup")?0:i[0].offsetHeight;f.css({top:h.top+g,left:h.left,width:i[0].offsetWidth,position:"absolute"})};this.$newElement.on("click",function(){c(b(this));f.appendTo(e.options.container);f.toggleClass("open",!b(this).hasClass("open"));f.append(e.$menu)});b(window).resize(function(){c(e.$newElement)});b(window).on("scroll",function(){c(e.$newElement)});b("html").on("click",function(i){if(b(i.target).closest(e.$newElement).length<1){f.removeClass("open")}})},mobile:function(){this.$element.addClass("mobile-device").appendTo(this.$newElement);if(this.options.container){this.$menu.hide()}},refresh:function(){this.reloadLi();this.render();this.setWidth();this.setStyle();this.checkDisabled();this.liHeight()},update:function(){this.reloadLi();this.setWidth();this.setStyle();this.checkDisabled();this.liHeight()},setSelected:function(c,d){this.$menu.find("li").eq(c).toggleClass("selected",d)},setDisabled:function(c,d){if(d){this.$menu.find("li").eq(c).addClass("disabled").find("a").attr("href","#").attr("tabindex",-1)}else{this.$menu.find("li").eq(c).removeClass("disabled").find("a").removeAttr("href").attr("tabindex",0)}},isDisabled:function(){return this.$element.is(":disabled")},checkDisabled:function(){var c=this;if(this.isDisabled()){this.$button.addClass("disabled").attr("tabindex",-1)}else{if(this.$button.hasClass("disabled")){this.$button.removeClass("disabled")}if(this.$button.attr("tabindex")==-1){if(!this.$element.data("tabindex")){this.$button.removeAttr("tabindex")}}}this.$button.click(function(){return !c.isDisabled()})},tabIndex:function(){if(this.$element.is("[tabindex]")){this.$element.data("tabindex",this.$element.attr("tabindex"));this.$button.attr("tabindex",this.$element.data("tabindex"))}},clickListener:function(){var c=this;b("body").on("touchstart.dropdown",".dropdown-menu",function(d){d.stopPropagation()});this.$newElement.on("click",function(){c.setSize();if(!c.options.liveSearch&&!c.multiple){setTimeout(function(){c.$menu.find(".selected a").focus()},10)}});this.$menu.on("click","li a",function(k){var g=b(this).parent().index(),j=c.$element.val(),f=c.$element.prop("selectedIndex");if(c.multiple){k.stopPropagation()}k.preventDefault();if(!c.isDisabled()&&!b(this).parent().hasClass("disabled")){var d=c.$element.find("option");var i=d.eq(g);if(!c.multiple){d.prop("selected",false);i.prop("selected",true)}else{var h=i.prop("selected");i.prop("selected",!h)}if(!c.multiple){c.$button.focus()}else{if(c.options.liveSearch){c.$searchbox.focus()}}if((j!=c.$element.val()&&c.multiple)||(f!=c.$element.prop("selectedIndex")&&!c.multiple)){c.$element.change()}}});this.$menu.on("click","li.disabled a, li dt, li .div-contain, .popover-title, .popover-title :not(.close)",function(d){if(d.target==this){d.preventDefault();d.stopPropagation();if(!c.options.liveSearch){c.$button.focus()}else{c.$searchbox.focus()}}});this.$menu.on("click",".popover-title .close",function(){c.$button.focus()});this.$searchbox.on("click",function(d){d.stopPropagation()});this.$element.change(function(){c.render()})},liveSearchListener:function(){var d=this,c=b('
  • ');this.$newElement.on("click.dropdown.data-api",function(){d.$menu.find(".active").removeClass("active");if(!!d.$searchbox.val()){d.$searchbox.val("");d.$menu.find("li").show();if(!!c.parent().length){c.remove()}}if(!d.multiple){d.$menu.find(".selected").addClass("active")}setTimeout(function(){d.$searchbox.focus()},10)});this.$searchbox.on("input propertychange",function(){if(d.$searchbox.val()){d.$menu.find("li").show().not(":icontains("+d.$searchbox.val()+")").hide();if(!d.$menu.find("li").filter(":visible:not(.no-results)").length){if(!!c.parent().length){c.remove()}c.html('No results match "'+d.$searchbox.val()+'"').show();d.$menu.find("li").last().after(c)}else{if(!!c.parent().length){c.remove()}}}else{d.$menu.find("li").show();if(!!c.parent().length){c.remove()}}d.$menu.find("li.active").removeClass("active");d.$menu.find("li").filter(":visible:not(.divider)").eq(0).addClass("active").find("a").focus();b(this).focus()});this.$menu.on("mouseenter","a",function(f){d.$menu.find(".active").removeClass("active");b(f.currentTarget).parent().not(".disabled").addClass("active")});this.$menu.on("mouseleave","a",function(){d.$menu.find(".active").removeClass("active")})},val:function(c){if(c!==undefined){this.$element.val(c);this.$element.change();return this.$element}else{return this.$element.val()}},selectAll:function(){this.$element.find("option").prop("selected",true).attr("selected","selected");this.render()},deselectAll:function(){this.$element.find("option").prop("selected",false).removeAttr("selected");this.render()},keydown:function(p){var q,o,i,n,k,j,r,f,h,m,d,s,g={32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9"};q=b(this);i=q.parent();if(q.is("input")){i=q.parent().parent()}m=i.data("this");if(m.options.liveSearch){i=q.parent().parent()}if(m.options.container){i=m.$menu}o=b("[role=menu] li:not(.divider) a",i);s=m.$menu.parent().hasClass("open");if(m.options.liveSearch){if(/(^9$|27)/.test(p.keyCode)&&s&&m.$menu.find(".active").length===0){p.preventDefault();m.$menu.parent().removeClass("open");m.$button.focus()}o=b("[role=menu] li:not(.divider):visible",i);if(!q.val()&&!/(38|40)/.test(p.keyCode)){if(o.filter(".active").length===0){o=m.$newElement.find("li").filter(":icontains("+g[p.keyCode]+")")}}}if(!o.length){return}if(/(38|40)/.test(p.keyCode)){if(!s){m.$menu.parent().addClass("open")}n=o.index(o.filter(":focus"));j=o.parent(":not(.disabled):visible").first().index();r=o.parent(":not(.disabled):visible").last().index();k=o.eq(n).parent().nextAll(":not(.disabled):visible").eq(0).index();f=o.eq(n).parent().prevAll(":not(.disabled):visible").eq(0).index();h=o.eq(k).parent().prevAll(":not(.disabled):visible").eq(0).index();if(m.options.liveSearch){o.each(function(e){if(b(this).is(":not(.disabled)")){b(this).data("index",e)}});n=o.index(o.filter(".active"));j=o.filter(":not(.disabled):visible").first().data("index");r=o.filter(":not(.disabled):visible").last().data("index");k=o.eq(n).nextAll(":not(.disabled):visible").eq(0).data("index");f=o.eq(n).prevAll(":not(.disabled):visible").eq(0).data("index");h=o.eq(k).prevAll(":not(.disabled):visible").eq(0).data("index")}d=q.data("prevIndex");if(p.keyCode==38){if(m.options.liveSearch){n-=1}if(n!=h&&n>f){n=f}if(nr){n=r}if(n==d){n=j}}q.data("prevIndex",n);if(!m.options.liveSearch){o.eq(n).focus()}else{p.preventDefault();if(!q.is(".dropdown-toggle")){o.removeClass("active");o.eq(n).addClass("active").find("a").focus();q.focus()}}}else{if(!q.is("input")){var c=[],l,t;o.each(function(){if(b(this).parent().is(":not(.disabled)")){if(b.trim(b(this).text().toLowerCase()).substring(0,1)==g[p.keyCode]){c.push(b(this).parent().index())}}});l=b(document).data("keycount");l++;b(document).data("keycount",l);t=b.trim(b(":focus").text().toLowerCase()).substring(0,1);if(t!=g[p.keyCode]){l=1;b(document).data("keycount",l)}else{if(l>=c.length){b(document).data("keycount",0);if(l>c.length){l=1}}}o.eq(c[l-1]).focus()}}if(/(13|32|^9$)/.test(p.keyCode)&&s){if(!/(32)/.test(p.keyCode)){p.preventDefault()}if(!m.options.liveSearch){b(":focus").click()}else{if(!/(32)/.test(p.keyCode)){m.$menu.find(".active a").click();q.focus()}}b(document).data("keycount",0)}if((/(^9$|27)/.test(p.keyCode)&&s&&(m.multiple||m.options.liveSearch))||(/(27)/.test(p.keyCode)&&!s)){m.$menu.parent().removeClass("open");m.$button.focus()}},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},destroy:function(){this.$newElement.remove();this.$element.remove()}};b.fn.selectpicker=function(e,f){var c=arguments;var g;var d=this.each(function(){if(b(this).is("select")){var m=b(this),l=m.data("selectpicker"),h=typeof e=="object"&&e;if(!l){m.data("selectpicker",(l=new a(this,h,f)))}else{if(h){for(var j in h){l.options[j]=h[j]}}}if(typeof e=="string"){var k=e;if(l[k] instanceof Function){[].shift.apply(c);g=l[k].apply(l,c)}else{g=l.options[k]}}}});if(g!==undefined){return g}else{return d}};b.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Nothing selected",countSelectedText:"{0} of {1} selected",width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"};b(document).data("keycount",0).on("keydown",".bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bootstrap-select-searchbox input",a.prototype.keydown).on("focusin.modal",".bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bootstrap-select-searchbox input",function(c){c.stopPropagation()})}(window.jQuery); \ No newline at end of file +!function(a){"use strict";function b(a,b){return a.toUpperCase().indexOf(b.toUpperCase())>-1}function c(b){var c=[{re:/[\xC0-\xC6]/g,ch:"A"},{re:/[\xE0-\xE6]/g,ch:"a"},{re:/[\xC8-\xCB]/g,ch:"E"},{re:/[\xE8-\xEB]/g,ch:"e"},{re:/[\xCC-\xCF]/g,ch:"I"},{re:/[\xEC-\xEF]/g,ch:"i"},{re:/[\xD2-\xD6]/g,ch:"O"},{re:/[\xF2-\xF6]/g,ch:"o"},{re:/[\xD9-\xDC]/g,ch:"U"},{re:/[\xF9-\xFC]/g,ch:"u"},{re:/[\xC7-\xE7]/g,ch:"c"},{re:/[\xD1]/g,ch:"N"},{re:/[\xF1]/g,ch:"n"}];return a.each(c,function(){b=b.replace(this.re,this.ch)}),b}function d(a){var b={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},c="(?:"+Object.keys(b).join("|")+")",d=new RegExp(c),e=new RegExp(c,"g"),f=null==a?"":""+a;return d.test(f)?f.replace(e,function(a){return b[a]}):f}function e(b,c){var d=arguments,e=b,b=d[0],c=d[1];[].shift.apply(d),"undefined"==typeof b&&(b=e);var g,h=this.each(function(){var e=a(this);if(e.is("select")){var h=e.data("selectpicker"),i="object"==typeof b&&b;if(h){if(i)for(var j in i)i.hasOwnProperty(j)&&(h.options[j]=i[j])}else{var k=a.extend({},f.DEFAULTS,a.fn.selectpicker.defaults||{},e.data(),i);e.data("selectpicker",h=new f(this,k,c))}"string"==typeof b&&(g=h[b]instanceof Function?h[b].apply(h,d):h.options[b])}});return"undefined"!=typeof g?g:h}a.expr[":"].icontains=function(c,d,e){return b(a(c).text(),e[3])},a.expr[":"].aicontains=function(c,d,e){return b(a(c).data("normalizedText")||a(c).text(),e[3])};var f=function(b,c,d){d&&(d.stopPropagation(),d.preventDefault()),this.$element=a(b),this.$newElement=null,this.$button=null,this.$menu=null,this.$lis=null,this.options=c,null===this.options.title&&(this.options.title=this.$element.attr("title")),this.val=f.prototype.val,this.render=f.prototype.render,this.refresh=f.prototype.refresh,this.setStyle=f.prototype.setStyle,this.selectAll=f.prototype.selectAll,this.deselectAll=f.prototype.deselectAll,this.destroy=f.prototype.remove,this.remove=f.prototype.remove,this.show=f.prototype.show,this.hide=f.prototype.hide,this.init()};f.VERSION="1.6.3",f.DEFAULTS={noneSelectedText:"Nothing selected",noneResultsText:"No results match",countSelectedText:function(a){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){var c=[];return c[0]=1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",c[1]=1==b?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)",c},selectAllText:"Select All",deselectAllText:"Deselect All",multipleSeparator:", ",style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,actionsBox:!1,iconBase:"glyphicon",tickIcon:"glyphicon-ok",maxOptions:!1,mobile:!1,selectOnTab:!1,dropdownAlignRight:!1,searchAccentInsensitive:!1},f.prototype={constructor:f,init:function(){var b=this,c=this.$element.attr("id");this.$element.hide(),this.multiple=this.$element.prop("multiple"),this.autofocus=this.$element.prop("autofocus"),this.$newElement=this.createView(),this.$element.after(this.$newElement),this.$menu=this.$newElement.find("> .dropdown-menu"),this.$button=this.$newElement.find("> button"),this.$searchbox=this.$newElement.find("input"),this.options.dropdownAlignRight&&this.$menu.addClass("dropdown-menu-right"),"undefined"!=typeof c&&(this.$button.attr("data-id",c),a('label[for="'+c+'"]').click(function(a){a.preventDefault(),b.$button.focus()})),this.checkDisabled(),this.clickListener(),this.options.liveSearch&&this.liveSearchListener(),this.render(),this.liHeight(),this.setStyle(),this.setWidth(),this.options.container&&this.selectPosition(),this.$menu.data("this",this),this.$newElement.data("this",this),this.options.mobile&&this.mobile()},createDropdown:function(){var b=this.multiple?" show-tick":"",c=this.$element.parent().hasClass("input-group")?" input-group-btn":"",d=this.autofocus?" autofocus":"",e=this.$element.parents().hasClass("form-group-lg")?" btn-lg":this.$element.parents().hasClass("form-group-sm")?" btn-sm":"",f=this.options.header?'
    '+this.options.header+"
    ":"",g=this.options.liveSearch?'':"",h=this.options.actionsBox?'
    ":"",i='
    ';return a(i)},createView:function(){var a=this.createDropdown(),b=this.createLi();return a.find("ul").append(b),a},reloadLi:function(){this.destroyLi();var a=this.createLi();this.$menu.find("ul").append(a)},destroyLi:function(){this.$menu.find("li").remove()},createLi:function(){var b=this,e=[],f=0,g=function(a,b,c){return""+a+""},h=function(a,e,f,g){var h=c(d(a));return''+a+''};return this.$element.find("option").each(function(){var c=a(this),d=c.attr("class")||"",i=c.attr("style"),j=c.data("content")?c.data("content"):c.html(),k="undefined"!=typeof c.data("subtext")?''+c.data("subtext")+"":"",l="undefined"!=typeof c.data("icon")?' ':"",m=c.is(":disabled")||c.parent().is(":disabled"),n=c[0].index;if(""!==l&&m&&(l=""+l+""),c.data("content")||(j=l+''+j+k+""),!b.options.hideDisabled||!m)if(c.parent().is("optgroup")&&c.data("divider")!==!0){if(0===c.index()){f+=1;var o=c.parent().attr("label"),p="undefined"!=typeof c.parent().data("subtext")?''+c.parent().data("subtext")+"":"",q=c.parent().data("icon")?' ':"";o=q+''+o+p+"",0!==n&&e.length>0&&e.push(g("",null,"divider")),e.push(g(o,null,"dropdown-header"))}e.push(g(h(j,"opt "+d,i,f),n))}else e.push(c.data("divider")===!0?g("",n,"divider"):c.data("hidden")===!0?g(h(j,d,i),n,"hide is-hidden"):g(h(j,d,i),n))}),this.multiple||0!==this.$element.find("option:selected").length||this.options.title||this.$element.find("option").eq(0).prop("selected",!0).attr("selected","selected"),a(e.join(""))},findLis:function(){return null==this.$lis&&(this.$lis=this.$menu.find("li")),this.$lis},render:function(b){var c=this;b!==!1&&this.$element.find("option").each(function(b){c.setDisabled(b,a(this).is(":disabled")||a(this).parent().is(":disabled")),c.setSelected(b,a(this).is(":selected"))}),this.tabIndex();var e=this.options.hideDisabled?":not([disabled])":"",f=this.$element.find("option:selected"+e).map(function(){var b,d=a(this),e=d.data("icon")&&c.options.showIcon?' ':"";return b=c.options.showSubtext&&d.attr("data-subtext")&&!c.multiple?' '+d.data("subtext")+"":"",d.data("content")&&c.options.showContent?d.data("content"):"undefined"!=typeof d.attr("title")?d.attr("title"):e+d.html()+b}).toArray(),g=this.multiple?f.join(this.options.multipleSeparator):f[0];if(this.multiple&&this.options.selectedTextFormat.indexOf("count")>-1){var h=this.options.selectedTextFormat.split(">");if(h.length>1&&f.length>h[1]||1==h.length&&f.length>=2){e=this.options.hideDisabled?", [disabled]":"";var i=this.$element.find("option").not('[data-divider="true"], [data-hidden="true"]'+e).length,j="function"==typeof this.options.countSelectedText?this.options.countSelectedText(f.length,i):this.options.countSelectedText;g=j.replace("{0}",f.length.toString()).replace("{1}",i.toString())}}this.options.title=this.$element.attr("title"),"static"==this.options.selectedTextFormat&&(g=this.options.title),g||(g="undefined"!=typeof this.options.title?this.options.title:this.options.noneSelectedText),this.$button.attr("title",d(g)),this.$newElement.find(".filter-option").html(g)},setStyle:function(a,b){this.$element.attr("class")&&this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device|validate\[.*\]/gi,""));var c=a?a:this.options.style;"add"==b?this.$button.addClass(c):"remove"==b?this.$button.removeClass(c):(this.$button.removeClass(this.options.style),this.$button.addClass(c))},liHeight:function(){if(this.options.size!==!1){var a=this.$menu.parent().clone().find("> .dropdown-toggle").prop("autofocus",!1).end().appendTo("body"),b=a.addClass("open").find("> .dropdown-menu"),c=b.find("li").not(".divider").not(".dropdown-header").filter(":visible").children("a").outerHeight(),d=this.options.header?b.find(".popover-title").outerHeight():0,e=this.options.liveSearch?b.find(".bs-searchbox").outerHeight():0,f=this.options.actionsBox?b.find(".bs-actionsbox").outerHeight():0;a.remove(),this.$newElement.data("liHeight",c).data("headerHeight",d).data("searchHeight",e).data("actionsHeight",f)}},setSize:function(){this.findLis();var b,c,d,e=this,f=this.$menu,g=f.find(".inner"),h=this.$newElement.outerHeight(),i=this.$newElement.data("liHeight"),j=this.$newElement.data("headerHeight"),k=this.$newElement.data("searchHeight"),l=this.$newElement.data("actionsHeight"),m=this.$lis.filter(".divider").outerHeight(!0),n=parseInt(f.css("padding-top"))+parseInt(f.css("padding-bottom"))+parseInt(f.css("border-top-width"))+parseInt(f.css("border-bottom-width")),o=this.options.hideDisabled?", .disabled":"",p=a(window),q=n+parseInt(f.css("margin-top"))+parseInt(f.css("margin-bottom"))+2,r=function(){c=e.$newElement.offset().top-p.scrollTop(),d=p.height()-c-h};if(r(),this.options.header&&f.css("padding-top",0),"auto"==this.options.size){var s=function(){var a,h=e.$lis.not(".hide");r(),b=d-q,e.options.dropupAuto&&e.$newElement.toggleClass("dropup",c>d&&b-q3?3*i+q-2:0,f.css({"max-height":b+"px",overflow:"hidden","min-height":a+j+k+l+"px"}),g.css({"max-height":b-j-k-l-n+"px","overflow-y":"auto","min-height":Math.max(a-n,0)+"px"})};s(),this.$searchbox.off("input.getSize propertychange.getSize").on("input.getSize propertychange.getSize",s),a(window).off("resize.getSize").on("resize.getSize",s),a(window).off("scroll.getSize").on("scroll.getSize",s)}else if(this.options.size&&"auto"!=this.options.size&&f.find("li"+o).length>this.options.size){var t=this.$lis.not(".divider"+o).find(" > *").slice(0,this.options.size).last().parent().index(),u=this.$lis.slice(0,t+1).filter(".divider").length;b=i*this.options.size+u*m+n,e.options.dropupAuto&&this.$newElement.toggleClass("dropup",c>d&&b .dropdown-menu").css("width"),c=a.css("width","auto").find("> button").css("width");a.remove(),this.$newElement.css("width",Math.max(parseInt(b),parseInt(c))+"px")}else"fit"==this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width","").addClass("fit-width")):this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width",this.options.width)):(this.$menu.css("min-width",""),this.$newElement.css("width",""));this.$newElement.hasClass("fit-width")&&"fit"!==this.options.width&&this.$newElement.removeClass("fit-width")},selectPosition:function(){var b,c,d=this,e="
    ",f=a(e),g=function(a){f.addClass(a.attr("class").replace(/form-control/gi,"")).toggleClass("dropup",a.hasClass("dropup")),b=a.offset(),c=a.hasClass("dropup")?0:a[0].offsetHeight,f.css({top:b.top+c,left:b.left,width:a[0].offsetWidth,position:"absolute"})};this.$newElement.on("click",function(){d.isDisabled()||(g(a(this)),f.appendTo(d.options.container),f.toggleClass("open",!a(this).hasClass("open")),f.append(d.$menu))}),a(window).resize(function(){g(d.$newElement)}),a(window).on("scroll",function(){g(d.$newElement)}),a("html").on("click",function(b){a(b.target).closest(d.$newElement).length<1&&f.removeClass("open")})},setSelected:function(a,b){this.findLis(),this.$lis.filter('[data-original-index="'+a+'"]').toggleClass("selected",b)},setDisabled:function(a,b){this.findLis(),b?this.$lis.filter('[data-original-index="'+a+'"]').addClass("disabled").find("a").attr("href","#").attr("tabindex",-1):this.$lis.filter('[data-original-index="'+a+'"]').removeClass("disabled").find("a").removeAttr("href").attr("tabindex",0)},isDisabled:function(){return this.$element.is(":disabled")},checkDisabled:function(){var a=this;this.isDisabled()?this.$button.addClass("disabled").attr("tabindex",-1):(this.$button.hasClass("disabled")&&this.$button.removeClass("disabled"),-1==this.$button.attr("tabindex")&&(this.$element.data("tabindex")||this.$button.removeAttr("tabindex"))),this.$button.click(function(){return!a.isDisabled()})},tabIndex:function(){this.$element.is("[tabindex]")&&(this.$element.data("tabindex",this.$element.attr("tabindex")),this.$button.attr("tabindex",this.$element.data("tabindex")))},clickListener:function(){var b=this;this.$newElement.on("touchstart.dropdown",".dropdown-menu",function(a){a.stopPropagation()}),this.$newElement.on("click",function(){b.setSize(),b.options.liveSearch||b.multiple||setTimeout(function(){b.$menu.find(".selected a").focus()},10)}),this.$menu.on("click","li a",function(c){var d=a(this),e=d.parent().data("originalIndex"),f=b.$element.val(),g=b.$element.prop("selectedIndex");if(b.multiple&&c.stopPropagation(),c.preventDefault(),!b.isDisabled()&&!d.parent().hasClass("disabled")){var h=b.$element.find("option"),i=h.eq(e),j=i.prop("selected"),k=i.parent("optgroup"),l=b.options.maxOptions,m=k.data("maxOptions")||!1;if(b.multiple){if(i.prop("selected",!j),b.setSelected(e,!j),d.blur(),l!==!1||m!==!1){var n=l
    ');q[2]&&(r=r.replace("{var}",q[2][l>1?0:1]),s=s.replace("{var}",q[2][m>1?0:1])),i.prop("selected",!1),b.$menu.append(t),l&&n&&(t.append(a("
    "+r+"
    ")),b.$element.trigger("maxReached.bs.select")),m&&o&&(t.append(a("
    "+s+"
    ")),b.$element.trigger("maxReachedGrp.bs.select")),setTimeout(function(){b.setSelected(e,!1)},10),t.delay(750).fadeOut(300,function(){a(this).remove()})}}}else h.prop("selected",!1),i.prop("selected",!0),b.$menu.find(".selected").removeClass("selected"),b.setSelected(e,!0);b.multiple?b.options.liveSearch&&b.$searchbox.focus():b.$button.focus(),(f!=b.$element.val()&&b.multiple||g!=b.$element.prop("selectedIndex")&&!b.multiple)&&b.$element.change()}}),this.$menu.on("click","li.disabled a, .popover-title, .popover-title :not(.close)",function(a){a.target==this&&(a.preventDefault(),a.stopPropagation(),b.options.liveSearch?b.$searchbox.focus():b.$button.focus())}),this.$menu.on("click","li.divider, li.dropdown-header",function(a){a.preventDefault(),a.stopPropagation(),b.options.liveSearch?b.$searchbox.focus():b.$button.focus()}),this.$menu.on("click",".popover-title .close",function(){b.$button.focus()}),this.$searchbox.on("click",function(a){a.stopPropagation()}),this.$menu.on("click",".actions-btn",function(c){b.options.liveSearch?b.$searchbox.focus():b.$button.focus(),c.preventDefault(),c.stopPropagation(),a(this).is(".bs-select-all")?b.selectAll():b.deselectAll(),b.$element.change()}),this.$element.change(function(){b.render(!1)})},liveSearchListener:function(){var b=this,e=a('
  • ');this.$newElement.on("click.dropdown.data-api touchstart.dropdown.data-api",function(){b.$menu.find(".active").removeClass("active"),b.$searchbox.val()&&(b.$searchbox.val(""),b.$lis.not(".is-hidden").removeClass("hide"),e.parent().length&&e.remove()),b.multiple||b.$menu.find(".selected").addClass("active"),setTimeout(function(){b.$searchbox.focus()},10)}),this.$searchbox.on("click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api",function(a){a.stopPropagation()}),this.$searchbox.on("input propertychange",function(){b.$searchbox.val()?(b.options.searchAccentInsensitive?b.$lis.not(".is-hidden").removeClass("hide").find("a").not(":aicontains("+c(b.$searchbox.val())+")").parent().addClass("hide"):b.$lis.not(".is-hidden").removeClass("hide").find("a").not(":icontains("+b.$searchbox.val()+")").parent().addClass("hide"),b.$menu.find("li").filter(":visible:not(.no-results)").length?e.parent().length&&e.remove():(e.parent().length&&e.remove(),e.html(b.options.noneResultsText+' "'+d(b.$searchbox.val())+'"').show(),b.$menu.find("li").last().after(e))):(b.$lis.not(".is-hidden").removeClass("hide"),e.parent().length&&e.remove()),b.$menu.find("li.active").removeClass("active"),b.$menu.find("li").filter(":visible:not(.divider)").eq(0).addClass("active").find("a").focus(),a(this).focus()})},val:function(a){return"undefined"!=typeof a?(this.$element.val(a),this.render(),this.$element):this.$element.val()},selectAll:function(){this.findLis(),this.$lis.not(".divider").not(".disabled").not(".selected").filter(":visible").find("a").click()},deselectAll:function(){this.findLis(),this.$lis.not(".divider").not(".disabled").filter(".selected").filter(":visible").find("a").click()},keydown:function(b){var d,e,f,g,h,i,j,k,l,m=a(this),n=m.is("input")?m.parent().parent():m.parent(),o=n.data("this"),p={32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9"};if(o.options.liveSearch&&(n=m.parent().parent()),o.options.container&&(n=o.$menu),d=a("[role=menu] li a",n),l=o.$menu.parent().hasClass("open"),!l&&/([0-9]|[A-z])/.test(String.fromCharCode(b.keyCode))&&(o.options.container?o.$newElement.trigger("click"):(o.setSize(),o.$menu.parent().addClass("open"),l=!0),o.$searchbox.focus()),o.options.liveSearch&&(/(^9$|27)/.test(b.keyCode.toString(10))&&l&&0===o.$menu.find(".active").length&&(b.preventDefault(),o.$menu.parent().removeClass("open"),o.$button.focus()),d=a("[role=menu] li:not(.divider):not(.dropdown-header):visible",n),m.val()||/(38|40)/.test(b.keyCode.toString(10))||0===d.filter(".active").length&&(d=o.$newElement.find("li").filter(o.options.searchAccentInsensitive?":aicontains("+c(p[b.keyCode])+")":":icontains("+p[b.keyCode]+")"))),d.length){if(/(38|40)/.test(b.keyCode.toString(10)))e=d.index(d.filter(":focus")),g=d.parent(":not(.disabled):visible").first().index(),h=d.parent(":not(.disabled):visible").last().index(),f=d.eq(e).parent().nextAll(":not(.disabled):visible").eq(0).index(),i=d.eq(e).parent().prevAll(":not(.disabled):visible").eq(0).index(),j=d.eq(f).parent().prevAll(":not(.disabled):visible").eq(0).index(),o.options.liveSearch&&(d.each(function(b){a(this).is(":not(.disabled)")&&a(this).data("index",b)}),e=d.index(d.filter(".active")),g=d.filter(":not(.disabled):visible").first().data("index"),h=d.filter(":not(.disabled):visible").last().data("index"),f=d.eq(e).nextAll(":not(.disabled):visible").eq(0).data("index"),i=d.eq(e).prevAll(":not(.disabled):visible").eq(0).data("index"),j=d.eq(f).prevAll(":not(.disabled):visible").eq(0).data("index")),k=m.data("prevIndex"),38==b.keyCode&&(o.options.liveSearch&&(e-=1),e!=j&&e>i&&(e=i),g>e&&(e=g),e==k&&(e=h)),40==b.keyCode&&(o.options.liveSearch&&(e+=1),-1==e&&(e=0),e!=j&&f>e&&(e=f),e>h&&(e=h),e==k&&(e=g)),m.data("prevIndex",e),o.options.liveSearch?(b.preventDefault(),m.is(".dropdown-toggle")||(d.removeClass("active"),d.eq(e).addClass("active").find("a").focus(),m.focus())):d.eq(e).focus();else if(!m.is("input")){var q,r,s=[];d.each(function(){a(this).parent().is(":not(.disabled)")&&a.trim(a(this).text().toLowerCase()).substring(0,1)==p[b.keyCode]&&s.push(a(this).parent().index())}),q=a(document).data("keycount"),q++,a(document).data("keycount",q),r=a.trim(a(":focus").text().toLowerCase()).substring(0,1),r!=p[b.keyCode]?(q=1,a(document).data("keycount",q)):q>=s.length&&(a(document).data("keycount",0),q>s.length&&(q=1)),d.eq(s[q-1]).focus()}(/(13|32)/.test(b.keyCode.toString(10))||/(^9$)/.test(b.keyCode.toString(10))&&o.options.selectOnTab)&&l&&(/(32)/.test(b.keyCode.toString(10))||b.preventDefault(),o.options.liveSearch?/(32)/.test(b.keyCode.toString(10))||(o.$menu.find(".active a").click(),m.focus()):a(":focus").click(),a(document).data("keycount",0)),(/(^9$|27)/.test(b.keyCode.toString(10))&&l&&(o.multiple||o.options.liveSearch)||/(27)/.test(b.keyCode.toString(10))&&!l)&&(o.$menu.parent().removeClass("open"),o.$button.focus())}},mobile:function(){this.$element.addClass("mobile-device").appendTo(this.$newElement),this.options.container&&this.$menu.hide()},refresh:function(){this.$lis=null,this.reloadLi(),this.render(),this.setWidth(),this.setStyle(),this.checkDisabled(),this.liHeight()},update:function(){this.reloadLi(),this.setWidth(),this.setStyle(),this.checkDisabled(),this.liHeight()},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()}};var g=a.fn.selectpicker;a.fn.selectpicker=e,a.fn.selectpicker.Constructor=f,a.fn.selectpicker.noConflict=function(){return a.fn.selectpicker=g,this},a(document).data("keycount",0).on("keydown",".bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input",f.prototype.keydown).on("focusin.modal",".bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bs-searchbox input",function(a){a.stopPropagation()}),a(window).on("load.bs.select.data-api",function(){a(".selectpicker").each(function(){var b=a(this);e.call(b,b.data())})})}(jQuery); +//# sourceMappingURL=bootstrap-select.js.map \ No newline at end of file From faeda7b808cb6e642289963494be13bfc9d99719 Mon Sep 17 00:00:00 2001 From: kdubious Date: Thu, 18 Dec 2014 00:00:38 -0500 Subject: [PATCH 31/80] Implementation of Mithril in RuneUI. - Early concepts for modules / views - Navigation - back end work to convert old template "controllers" to pre-REST API, accepting JSON --- app/api/mpd_ctl.php | 48 +- assets/js/runeui-static.js | 1573 +++++++++++++++-------------- command/cachectl.php | 2 +- {app/config => config}/index.html | 19 +- config/local.html | 114 +++ 5 files changed, 982 insertions(+), 774 deletions(-) rename {app/config => config}/index.html (86%) create mode 100644 config/local.html diff --git a/app/api/mpd_ctl.php b/app/api/mpd_ctl.php index 49302cf2..6f7db125 100644 --- a/app/api/mpd_ctl.php +++ b/app/api/mpd_ctl.php @@ -32,22 +32,38 @@ * */ if (isset($_POST)) { - // switch audio output - if (isset($_POST['ao'])) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'switchao', 'args' => $_POST['ao'])); - } - // reset MPD configuration - if (isset($_POST['reset'])) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); - } - // update MPD configuration - if (isset($_POST['conf'])) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'update', 'args' => $_POST['conf'])); - } - // manual MPD configuration - if (isset($_POST['mpdconf'])) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfgman', 'args' => $_POST['mpdconf'])); - } + // Let's make sure we've called this with an actual POST + $template->AAAAAAAAA = $_SERVER['REQUEST_METHOD']; + //if ($_SERVER['REQUEST_METHOD'] === 'POST') { + + // get the data that was POSTed + $postData = file_get_contents("php://input"); + // convert to an associative array + $json = json_decode($postData, true); + $template->BBBBBBBB = $json['ao']; + $template->CCCCCCCC = isset($json['ao']); + + //$json = json_decode($postData); + //$template->BBBBBBBB = $json->ao; + + // switch audio output + if (isset($json['ao'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'switchao', 'args' => $json['ao'])); + } + // reset MPD configuration + if (isset($json['reset'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); + } + // update MPD configuration + if (isset($json['conf'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'update', 'args' => $json['conf'])); + } + // manual MPD configuration + if (isset($_POST['mpdconf'])) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfgman', 'args' => $json['mpdconf'])); + } + // } + } waitSyWrk($redis, $jobID); // check integrity of /etc/network/interfaces diff --git a/assets/js/runeui-static.js b/assets/js/runeui-static.js index 9ac47f62..0755c27b 100644 --- a/assets/js/runeui-static.js +++ b/assets/js/runeui-static.js @@ -20,6 +20,69 @@ var config = {}; var playback = {}; +// modules - navigation + +var navigation = {}; + +navigation.Page = function (data) { + this.name = m.prop(data.name); + this.url = m.prop(data.url); + this.icon = m.prop(data.icon); + this.selected = m.prop(data.selected || false); +}; + +navigation.vm = (function (data) { + + var vm = {}; + vm.pages = []; + + vm.add = function (name, url, icon) { + vm.pages.push(new navigation.Page({ name: name, url: url, icon: icon })); + }; + + vm.navigate = function (url) { + for (i = 0; i < vm.pages.length - 1; i++) { + if (vm.pages[i].url() === url) { + vm.pages[i].selected(true); + } else { + vm.pages[i].selected(false); + } + } + }; + + vm.init = function () { + this.add('Playback', '/', 'play'); + this.add('Audio', '/audio', 'music'); + this.add('MPD', '/mpd', 'cogs'); + this.add('Settings', '/settings', 'wrench'); + this.add('Sources', '/sources', 'folder-open'); + this.add('Network', '/network', 'sitemap'); + this.add('Debug', '/debug', 'bug'); + this.add('Credits', '/credits', 'trophy'); + this.add('Turn off', '/power', 'power-off'); + + }; + + return vm; + +}()); + +navigation.controller = function () { + navigation.vm.init(); +}; + +//m("li", [m("a[href='#/']", [m("i.fa.fa-play"), " Playback"])]) + +navigation.view = function (ctrl) { + return [m("a.dropdown-toggle[data-target='#'][data-toggle='dropdown'][href='#'][id='menu-settings'][role='button']", + ["MENU ", m("i.fa.fa-th-list.dx")]), "\n", m("ul.dropdown-menu[aria-labelledby='menu-settings'][role='menu']", + [navigation.vm.pages.map(function (item, index) { + return m('li', { "class": item.selected() ? "active" : "" }, [m('a[href="' + item.url() + '"]', { config: m.route }, [m('i.fa.fa-' + item.icon()), ' ' + item.name()])]); + })])]; +}; + +m.module(document.getElementById('topMenu'), navigation); + // base classes @@ -36,9 +99,9 @@ var postData = function (vm) { console.log(vm.url); console.log(vm.data); m.request({ - method: "POST", - url: "/mpd", - serialize: function (data) { return data; } + method: 'POST', + url: vm.url, + data: vm.data }); }; @@ -48,13 +111,16 @@ var getViewModel = function (url) { var vm = {}; // properties of all our viewmodels - vm.url = url; + var urlPrefix = '/api'; + vm.url = urlPrefix + url; // initialize the view model vm.init = function () { // property 'data' is defined here asnd the loading is set up this.data = getData(this); + console.log("* in vm init"); + navigation.vm.navigate(this.url.replace(urlPrefix,'')); //return m.request({ method: 'GET', url: vm.url }).then(function (response) { // vm.data = response; // vm.originalData = JSON.parse(JSON.stringify(response)); // we need a clone of this object @@ -78,6 +144,12 @@ var getViewModel = function (url) { var getController = function (vm) { var controller = function () { vm.init(); + + console.log("* in controller"); + + this.onunload = function () { + + }; }; return controller; }; @@ -96,6 +168,37 @@ var bind2 = function (container, field, config) { }; }; +var bind2checked = function (container, field, config) { + // container: for example 'mpd.vm.data.conf' + // field: for example 'port or audio_mixer' + // config: jQuery function to run after the item is in the DOM + return { + config: config, + onchange: m.withAttr('checked', function (value) { + if (value) { + container[field] = "yes"; + } else { + container[field] = "no"; + } + }), + checked: (function () { + if (container[field] === "yes") { + return true; + } else { + return false; + } + }()) + }; +}; + +var createYesNo = function (id, container, field, config) { + return m('label.switch-light.well', [ + m('input[id="' + id + '"][type="checkbox"]', bind2checked(container, field)), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]); +}; + // createSelectYesNo('the-field', mpd.vm.data, 'the-field', selectpicker) var createSelectYesNo = function (id, container, field, config) { return m('select[data-style="btn-default btn-lg"][id="' + id + '"]', @@ -126,22 +229,22 @@ var RuneModule = function (url) { // implementation of the MPD module -var mpd = new RuneModule('mpd'); +var mpd = new RuneModule('/mpd'); // Do we want the Modules in Namespaces? // config.mpd = mpd; // implementation of the settings module -var settings = new RuneModule('mock-response-settings.json'); +var settings = new RuneModule('/settings'); -var credits = new RuneModule('mock-response-settings.json'); -var debug = new RuneModule('mock-response-settings.json'); -var dev = new RuneModule('mock-response-settings.json'); -var error = new RuneModule('mock-response-settings.json'); +var credits = new RuneModule('/credits'); +var debug = new RuneModule('/debug'); +var dev = new RuneModule('/dev'); +var error = new RuneModule('/error'); -var network = new RuneModule('mock-response-settings.json'); -var sources = new RuneModule('mock-response-settings.json'); +var network = new RuneModule('/network'); +var sources = new RuneModule('/sources'); // modules - playback var control = {}; @@ -150,737 +253,709 @@ var volume = {}; -////////////mpd.vm = {} -////////////mpd.vm.init = function (url) { -//////////// this.url = url; -//////////// mpd.getData(url) -////////////} -////////////mpd.vm.save = function () { -//////////// console.log(mpd.vm.url); -//////////// console.log(mpd.data); -////////////} - -////////////mpd.getData = function (url) { -//////////// // 'mock-response-mpd.json' -//////////// return m.request({ method: 'GET', url: url }).then(function (response) { -//////////// mpd.data = response; -//////////// }); -////////////}; - -////////////mpd.controller = function () { -//////////// mpd.vm.init('mock-response-mpd.json'); - -//////////// this.save = function () { -//////////// console.log(mpd.data); -//////////// } - -////////////}; - - - // views // Settings settings.view = function (ctrl) { - return [ - m("h1", "Settings"), - m("form.form-horizontal[action=''][method='post'][role='form']", [ - m("fieldset", [ - m("legend", "Environment"), - m(".form-group[id='systemstatus']", [ - m("label.control-label.col-sm-2", "Check system status"), - m(".col-sm-10", [ - m("a.btn.btn-default.btn-lg[data-toggle='modal'][href='#modal-sysinfo']", [m("i.fa.fa-info-circle.sx"), "show status"]), - m("span.help-block", "See information regarding the system and its status.") - ]) - ]), - m(".form-group[id='environment']", [ - m("label.control-label.col-sm-2[for='hostname']", "Player hostname"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][id='hostname'][name='hostname'][placeholder='runeaudio'][type='text'][value='a-cappella']"), - m("span.help-block", "Set the player hostname. This will change the address used to reach the RuneUI.") - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='ntpserver']", "NTP server"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][id='ntpserver'][name='ntpserver'][placeholder='pool.ntp.org'][type='text'][value='pool.ntp.org']"), - m("span.help-block", ["Set your reference time sync server ", m("i", "(NTP server)"), "."]) - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='timezone']", "Timezone"), - m(".col-sm-10", [ - m("select.selectpicker[data-style='btn-default btn-lg'][name='timezone']", { style: { "display": " none" } }, [ - m("option[value='Africa/Abidjan']", "\n Africa/Abidjan - GMT +00:00 "), - m("option[value='Africa/Accra']", "\n Africa/Accra - GMT +00:00 "), - m("option[value='Africa/Addis_Ababa']", "\n Africa/Addis_Ababa - GMT +03:00 "), - m("option[value='Africa/Algiers']", "\n Africa/Algiers - GMT +01:00 "), - m("option[value='Africa/Asmara']", "\n Africa/Asmara - GMT +03:00 "), - m("option[value='Africa/Bamako']", "\n Africa/Bamako - GMT +00:00 "), - m("option[value='Africa/Bangui']", "\n Africa/Bangui - GMT +01:00 "), - m("option[value='Africa/Banjul']", "\n Africa/Banjul - GMT +00:00 "), - m("option[value='Africa/Bissau']", "\n Africa/Bissau - GMT +00:00 "), - m("option[value='Africa/Blantyre']", "\n Africa/Blantyre - GMT +02:00 "), - m("option[value='Africa/Brazzaville']", "\n Africa/Brazzaville - GMT +01:00 "), - m("option[value='Africa/Bujumbura']", "\n Africa/Bujumbura - GMT +02:00 "), - m("option[value='Africa/Cairo']", "\n Africa/Cairo - GMT +02:00 "), - m("option[value='Africa/Casablanca']", "\n Africa/Casablanca - GMT +00:00 "), - m("option[value='Africa/Ceuta']", "\n Africa/Ceuta - GMT +01:00 "), - m("option[value='Africa/Conakry']", "\n Africa/Conakry - GMT +00:00 "), - m("option[value='Africa/Dakar']", "\n Africa/Dakar - GMT +00:00 "), - m("option[value='Africa/Dar_es_Salaam']", "\n Africa/Dar_es_Salaam - GMT +03:00 "), - m("option[value='Africa/Djibouti']", "\n Africa/Djibouti - GMT +03:00 "), - m("option[value='Africa/Douala']", "\n Africa/Douala - GMT +01:00 "), - m("option[value='Africa/El_Aaiun']", "\n Africa/El_Aaiun - GMT +00:00 "), - m("option[value='Africa/Freetown']", "\n Africa/Freetown - GMT +00:00 "), - m("option[value='Africa/Gaborone']", "\n Africa/Gaborone - GMT +02:00 "), - m("option[value='Africa/Harare']", "\n Africa/Harare - GMT +02:00 "), - m("option[value='Africa/Johannesburg']", "\n Africa/Johannesburg - GMT +02:00 "), - m("option[value='Africa/Juba']", "\n Africa/Juba - GMT +03:00 "), - m("option[value='Africa/Kampala']", "\n Africa/Kampala - GMT +03:00 "), - m("option[value='Africa/Khartoum']", "\n Africa/Khartoum - GMT +03:00 "), - m("option[value='Africa/Kigali']", "\n Africa/Kigali - GMT +02:00 "), - m("option[value='Africa/Kinshasa']", "\n Africa/Kinshasa - GMT +01:00 "), - m("option[value='Africa/Lagos']", "\n Africa/Lagos - GMT +01:00 "), - m("option[value='Africa/Libreville']", "\n Africa/Libreville - GMT +01:00 "), - m("option[value='Africa/Lome']", "\n Africa/Lome - GMT +00:00 "), - m("option[value='Africa/Luanda']", "\n Africa/Luanda - GMT +01:00 "), - m("option[value='Africa/Lubumbashi']", "\n Africa/Lubumbashi - GMT +02:00 "), - m("option[value='Africa/Lusaka']", "\n Africa/Lusaka - GMT +02:00 "), - m("option[value='Africa/Malabo']", "\n Africa/Malabo - GMT +01:00 "), - m("option[value='Africa/Maputo']", "\n Africa/Maputo - GMT +02:00 "), - m("option[value='Africa/Maseru']", "\n Africa/Maseru - GMT +02:00 "), - m("option[value='Africa/Mbabane']", "\n Africa/Mbabane - GMT +02:00 "), - m("option[value='Africa/Mogadishu']", "\n Africa/Mogadishu - GMT +03:00 "), - m("option[value='Africa/Monrovia']", "\n Africa/Monrovia - GMT +00:00 "), - m("option[value='Africa/Nairobi']", "\n Africa/Nairobi - GMT +03:00 "), - m("option[value='Africa/Ndjamena']", "\n Africa/Ndjamena - GMT +01:00 "), - m("option[value='Africa/Niamey']", "\n Africa/Niamey - GMT +01:00 "), - m("option[value='Africa/Nouakchott']", "\n Africa/Nouakchott - GMT +00:00 "), - m("option[value='Africa/Ouagadougou']", "\n Africa/Ouagadougou - GMT +00:00 "), - m("option[value='Africa/Porto-Novo']", "\n Africa/Porto-Novo - GMT +01:00 "), - m("option[value='Africa/Sao_Tome']", "\n Africa/Sao_Tome - GMT +00:00 "), - m("option[value='Africa/Tripoli']", "\n Africa/Tripoli - GMT +02:00 "), - m("option[value='Africa/Tunis']", "\n Africa/Tunis - GMT +01:00 "), - m("option[value='Africa/Windhoek']", "\n Africa/Windhoek - GMT +02:00 "), - m("option[value='America/Adak']", "\n America/Adak - GMT -10:00 "), - m("option[value='America/Anchorage']", "\n America/Anchorage - GMT -09:00 "), - m("option[value='America/Anguilla']", "\n America/Anguilla - GMT -04:00 "), - m("option[value='America/Antigua']", "\n America/Antigua - GMT -04:00 "), - m("option[value='America/Araguaina']", "\n America/Araguaina - GMT -03:00 "), - m("option[value='America/Argentina/Buenos_Aires']", "\n America/Argentina/Buenos_Aires - GMT -03:00 "), - m("option[value='America/Argentina/Catamarca']", "\n America/Argentina/Catamarca - GMT -03:00 "), - m("option[value='America/Argentina/Cordoba']", "\n America/Argentina/Cordoba - GMT -03:00 "), - m("option[value='America/Argentina/Jujuy']", "\n America/Argentina/Jujuy - GMT -03:00 "), - m("option[value='America/Argentina/La_Rioja']", "\n America/Argentina/La_Rioja - GMT -03:00 "), - m("option[value='America/Argentina/Mendoza']", "\n America/Argentina/Mendoza - GMT -03:00 "), - m("option[value='America/Argentina/Rio_Gallegos']", "\n America/Argentina/Rio_Gallegos - GMT -03:00 "), - m("option[value='America/Argentina/Salta']", "\n America/Argentina/Salta - GMT -03:00 "), - m("option[value='America/Argentina/San_Juan']", "\n America/Argentina/San_Juan - GMT -03:00 "), - m("option[value='America/Argentina/San_Luis']", "\n America/Argentina/San_Luis - GMT -03:00 "), - m("option[value='America/Argentina/Tucuman']", "\n America/Argentina/Tucuman - GMT -03:00 "), - m("option[value='America/Argentina/Ushuaia']", "\n America/Argentina/Ushuaia - GMT -03:00 "), - m("option[value='America/Aruba']", "\n America/Aruba - GMT -04:00 "), - m("option[value='America/Asuncion']", "\n America/Asuncion - GMT -03:00 "), - m("option[value='America/Atikokan']", "\n America/Atikokan - GMT -05:00 "), - m("option[value='America/Bahia']", "\n America/Bahia - GMT -03:00 "), - m("option[value='America/Bahia_Banderas']", "\n America/Bahia_Banderas - GMT -06:00 "), - m("option[value='America/Barbados']", "\n America/Barbados - GMT -04:00 "), - m("option[value='America/Belem']", "\n America/Belem - GMT -03:00 "), - m("option[value='America/Belize']", "\n America/Belize - GMT -06:00 "), - m("option[value='America/Blanc-Sablon']", "\n America/Blanc-Sablon - GMT -04:00 "), - m("option[value='America/Boa_Vista']", "\n America/Boa_Vista - GMT -04:00 "), - m("option[value='America/Bogota']", "\n America/Bogota - GMT -05:00 "), - m("option[value='America/Boise']", "\n America/Boise - GMT -07:00 "), - m("option[value='America/Cambridge_Bay']", "\n America/Cambridge_Bay - GMT -07:00 "), - m("option[value='America/Campo_Grande']", "\n America/Campo_Grande - GMT -03:00 "), - m("option[value='America/Cancun']", "\n America/Cancun - GMT -06:00 "), - m("option[value='America/Caracas']", "\n America/Caracas - GMT -04:30 "), - m("option[value='America/Cayenne']", "\n America/Cayenne - GMT -03:00 "), - m("option[value='America/Cayman']", "\n America/Cayman - GMT -05:00 "), - m("option[value='America/Chicago']", "\n America/Chicago - GMT -06:00 "), - m("option[value='America/Chihuahua']", "\n America/Chihuahua - GMT -07:00 "), - m("option[value='America/Costa_Rica']", "\n America/Costa_Rica - GMT -06:00 "), - m("option[value='America/Creston']", "\n America/Creston - GMT -07:00 "), - m("option[value='America/Cuiaba']", "\n America/Cuiaba - GMT -03:00 "), - m("option[value='America/Curacao']", "\n America/Curacao - GMT -04:00 "), - m("option[value='America/Danmarkshavn']", "\n America/Danmarkshavn - GMT +00:00 "), - m("option[value='America/Dawson']", "\n America/Dawson - GMT -08:00 "), - m("option[value='America/Dawson_Creek']", "\n America/Dawson_Creek - GMT -07:00 "), - m("option[value='America/Denver']", "\n America/Denver - GMT -07:00 "), - m("option[value='America/Detroit']", "\n America/Detroit - GMT -05:00 "), - m("option[value='America/Dominica']", "\n America/Dominica - GMT -04:00 "), - m("option[value='America/Edmonton']", "\n America/Edmonton - GMT -07:00 "), - m("option[value='America/Eirunepe']", "\n America/Eirunepe - GMT -05:00 "), - m("option[value='America/El_Salvador']", "\n America/El_Salvador - GMT -06:00 "), - m("option[value='America/Fortaleza']", "\n America/Fortaleza - GMT -03:00 "), - m("option[value='America/Glace_Bay']", "\n America/Glace_Bay - GMT -04:00 "), - m("option[value='America/Godthab']", "\n America/Godthab - GMT -03:00 "), - m("option[value='America/Goose_Bay']", "\n America/Goose_Bay - GMT -04:00 "), - m("option[value='America/Grand_Turk']", "\n America/Grand_Turk - GMT -04:00 "), - m("option[value='America/Grenada']", "\n America/Grenada - GMT -04:00 "), - m("option[value='America/Guadeloupe']", "\n America/Guadeloupe - GMT -04:00 "), - m("option[value='America/Guatemala']", "\n America/Guatemala - GMT -06:00 "), - m("option[value='America/Guayaquil']", "\n America/Guayaquil - GMT -05:00 "), - m("option[value='America/Guyana']", "\n America/Guyana - GMT -04:00 "), - m("option[value='America/Halifax']", "\n America/Halifax - GMT -04:00 "), - m("option[value='America/Havana']", "\n America/Havana - GMT -05:00 "), - m("option[value='America/Hermosillo']", "\n America/Hermosillo - GMT -07:00 "), - m("option[value='America/Indiana/Indianapolis']", "\n America/Indiana/Indianapolis - GMT -05:00 "), - m("option[value='America/Indiana/Knox']", "\n America/Indiana/Knox - GMT -06:00 "), - m("option[value='America/Indiana/Marengo']", "\n America/Indiana/Marengo - GMT -05:00 "), - m("option[value='America/Indiana/Petersburg']", "\n America/Indiana/Petersburg - GMT -05:00 "), - m("option[value='America/Indiana/Tell_City']", "\n America/Indiana/Tell_City - GMT -06:00 "), - m("option[value='America/Indiana/Vevay']", "\n America/Indiana/Vevay - GMT -05:00 "), - m("option[value='America/Indiana/Vincennes']", "\n America/Indiana/Vincennes - GMT -05:00 "), - m("option[value='America/Indiana/Winamac']", "\n America/Indiana/Winamac - GMT -05:00 "), - m("option[value='America/Inuvik']", "\n America/Inuvik - GMT -07:00 "), - m("option[value='America/Iqaluit']", "\n America/Iqaluit - GMT -05:00 "), - m("option[value='America/Jamaica']", "\n America/Jamaica - GMT -05:00 "), - m("option[value='America/Juneau']", "\n America/Juneau - GMT -09:00 "), - m("option[value='America/Kentucky/Louisville']", "\n America/Kentucky/Louisville - GMT -05:00 "), - m("option[value='America/Kentucky/Monticello']", "\n America/Kentucky/Monticello - GMT -05:00 "), - m("option[value='America/Kralendijk']", "\n America/Kralendijk - GMT -04:00 "), - m("option[value='America/La_Paz']", "\n America/La_Paz - GMT -04:00 "), - m("option[value='America/Lima']", "\n America/Lima - GMT -05:00 "), - m("option[value='America/Los_Angeles']", "\n America/Los_Angeles - GMT -08:00 "), - m("option[value='America/Lower_Princes']", "\n America/Lower_Princes - GMT -04:00 "), - m("option[value='America/Maceio']", "\n America/Maceio - GMT -03:00 "), - m("option[value='America/Managua']", "\n America/Managua - GMT -06:00 "), - m("option[value='America/Manaus']", "\n America/Manaus - GMT -04:00 "), - m("option[value='America/Marigot']", "\n America/Marigot - GMT -04:00 "), - m("option[value='America/Martinique']", "\n America/Martinique - GMT -04:00 "), - m("option[value='America/Matamoros']", "\n America/Matamoros - GMT -06:00 "), - m("option[value='America/Mazatlan']", "\n America/Mazatlan - GMT -07:00 "), - m("option[value='America/Menominee']", "\n America/Menominee - GMT -06:00 "), - m("option[value='America/Merida']", "\n America/Merida - GMT -06:00 "), - m("option[value='America/Metlakatla']", "\n America/Metlakatla - GMT -08:00 "), - m("option[value='America/Mexico_City']", "\n America/Mexico_City - GMT -06:00 "), - m("option[value='America/Miquelon']", "\n America/Miquelon - GMT -03:00 "), - m("option[value='America/Moncton']", "\n America/Moncton - GMT -04:00 "), - m("option[value='America/Monterrey']", "\n America/Monterrey - GMT -06:00 "), - m("option[value='America/Montevideo']", "\n America/Montevideo - GMT -02:00 "), - m("option[value='America/Montserrat']", "\n America/Montserrat - GMT -04:00 "), - m("option[value='America/Nassau']", "\n America/Nassau - GMT -05:00 "), - m("option[selected=''][value='America/New_York']", "\n America/New_York - GMT -05:00 "), - m("option[value='America/Nipigon']", "\n America/Nipigon - GMT -05:00 "), - m("option[value='America/Nome']", "\n America/Nome - GMT -09:00 "), - m("option[value='America/Noronha']", "\n America/Noronha - GMT -02:00 "), - m("option[value='America/North_Dakota/Beulah']", "\n America/North_Dakota/Beulah - GMT -06:00 "), - m("option[value='America/North_Dakota/Center']", "\n America/North_Dakota/Center - GMT -06:00 "), - m("option[value='America/North_Dakota/New_Salem']", "\n America/North_Dakota/New_Salem - GMT -06:00 "), - m("option[value='America/Ojinaga']", "\n America/Ojinaga - GMT -07:00 "), - m("option[value='America/Panama']", "\n America/Panama - GMT -05:00 "), - m("option[value='America/Pangnirtung']", "\n America/Pangnirtung - GMT -05:00 "), - m("option[value='America/Paramaribo']", "\n America/Paramaribo - GMT -03:00 "), - m("option[value='America/Phoenix']", "\n America/Phoenix - GMT -07:00 "), - m("option[value='America/Port-au-Prince']", "\n America/Port-au-Prince - GMT -05:00 "), - m("option[value='America/Port_of_Spain']", "\n America/Port_of_Spain - GMT -04:00 "), - m("option[value='America/Porto_Velho']", "\n America/Porto_Velho - GMT -04:00 "), - m("option[value='America/Puerto_Rico']", "\n America/Puerto_Rico - GMT -04:00 "), - m("option[value='America/Rainy_River']", "\n America/Rainy_River - GMT -06:00 "), - m("option[value='America/Rankin_Inlet']", "\n America/Rankin_Inlet - GMT -06:00 "), - m("option[value='America/Recife']", "\n America/Recife - GMT -03:00 "), - m("option[value='America/Regina']", "\n America/Regina - GMT -06:00 "), - m("option[value='America/Resolute']", "\n America/Resolute - GMT -06:00 "), - m("option[value='America/Rio_Branco']", "\n America/Rio_Branco - GMT -05:00 "), - m("option[value='America/Santa_Isabel']", "\n America/Santa_Isabel - GMT -08:00 "), - m("option[value='America/Santarem']", "\n America/Santarem - GMT -03:00 "), - m("option[value='America/Santiago']", "\n America/Santiago - GMT -03:00 "), - m("option[value='America/Santo_Domingo']", "\n America/Santo_Domingo - GMT -04:00 "), - m("option[value='America/Sao_Paulo']", "\n America/Sao_Paulo - GMT -02:00 "), - m("option[value='America/Scoresbysund']", "\n America/Scoresbysund - GMT -01:00 "), - m("option[value='America/Sitka']", "\n America/Sitka - GMT -09:00 "), - m("option[value='America/St_Barthelemy']", "\n America/St_Barthelemy - GMT -04:00 "), - m("option[value='America/St_Johns']", "\n America/St_Johns - GMT -03:30 "), - m("option[value='America/St_Kitts']", "\n America/St_Kitts - GMT -04:00 "), - m("option[value='America/St_Lucia']", "\n America/St_Lucia - GMT -04:00 "), - m("option[value='America/St_Thomas']", "\n America/St_Thomas - GMT -04:00 "), - m("option[value='America/St_Vincent']", "\n America/St_Vincent - GMT -04:00 "), - m("option[value='America/Swift_Current']", "\n America/Swift_Current - GMT -06:00 "), - m("option[value='America/Tegucigalpa']", "\n America/Tegucigalpa - GMT -06:00 "), - m("option[value='America/Thule']", "\n America/Thule - GMT -04:00 "), - m("option[value='America/Thunder_Bay']", "\n America/Thunder_Bay - GMT -05:00 "), - m("option[value='America/Tijuana']", "\n America/Tijuana - GMT -08:00 "), - m("option[value='America/Toronto']", "\n America/Toronto - GMT -05:00 "), - m("option[value='America/Tortola']", "\n America/Tortola - GMT -04:00 "), - m("option[value='America/Vancouver']", "\n America/Vancouver - GMT -08:00 "), - m("option[value='America/Whitehorse']", "\n America/Whitehorse - GMT -08:00 "), - m("option[value='America/Winnipeg']", "\n America/Winnipeg - GMT -06:00 "), - m("option[value='America/Yakutat']", "\n America/Yakutat - GMT -09:00 "), - m("option[value='America/Yellowknife']", "\n America/Yellowknife - GMT -07:00 "), - m("option[value='Antarctica/Casey']", "\n Antarctica/Casey - GMT +08:00 "), - m("option[value='Antarctica/Davis']", "\n Antarctica/Davis - GMT +07:00 "), - m("option[value='Antarctica/DumontDUrville']", "\n Antarctica/DumontDUrville - GMT +10:00 "), - m("option[value='Antarctica/Macquarie']", "\n Antarctica/Macquarie - GMT +11:00 "), - m("option[value='Antarctica/Mawson']", "\n Antarctica/Mawson - GMT +05:00 "), - m("option[value='Antarctica/McMurdo']", "\n Antarctica/McMurdo - GMT +13:00 "), - m("option[value='Antarctica/Palmer']", "\n Antarctica/Palmer - GMT -03:00 "), - m("option[value='Antarctica/Rothera']", "\n Antarctica/Rothera - GMT -03:00 "), - m("option[value='Antarctica/Syowa']", "\n Antarctica/Syowa - GMT +03:00 "), - m("option[value='Antarctica/Troll']", "\n Antarctica/Troll - GMT +00:00 "), - m("option[value='Antarctica/Vostok']", "\n Antarctica/Vostok - GMT +06:00 "), - m("option[value='Arctic/Longyearbyen']", "\n Arctic/Longyearbyen - GMT +01:00 "), - m("option[value='Asia/Aden']", "\n Asia/Aden - GMT +03:00 "), - m("option[value='Asia/Almaty']", "\n Asia/Almaty - GMT +06:00 "), - m("option[value='Asia/Amman']", "\n Asia/Amman - GMT +02:00 "), - m("option[value='Asia/Anadyr']", "\n Asia/Anadyr - GMT +12:00 "), - m("option[value='Asia/Aqtau']", "\n Asia/Aqtau - GMT +05:00 "), - m("option[value='Asia/Aqtobe']", "\n Asia/Aqtobe - GMT +05:00 "), - m("option[value='Asia/Ashgabat']", "\n Asia/Ashgabat - GMT +05:00 "), - m("option[value='Asia/Baghdad']", "\n Asia/Baghdad - GMT +03:00 "), - m("option[value='Asia/Bahrain']", "\n Asia/Bahrain - GMT +03:00 "), - m("option[value='Asia/Baku']", "\n Asia/Baku - GMT +04:00 "), - m("option[value='Asia/Bangkok']", "\n Asia/Bangkok - GMT +07:00 "), - m("option[value='Asia/Beirut']", "\n Asia/Beirut - GMT +02:00 "), - m("option[value='Asia/Bishkek']", "\n Asia/Bishkek - GMT +06:00 "), - m("option[value='Asia/Brunei']", "\n Asia/Brunei - GMT +08:00 "), - m("option[value='Asia/Chita']", "\n Asia/Chita - GMT +08:00 "), - m("option[value='Asia/Choibalsan']", "\n Asia/Choibalsan - GMT +08:00 "), - m("option[value='Asia/Colombo']", "\n Asia/Colombo - GMT +05:30 "), - m("option[value='Asia/Damascus']", "\n Asia/Damascus - GMT +02:00 "), - m("option[value='Asia/Dhaka']", "\n Asia/Dhaka - GMT +06:00 "), - m("option[value='Asia/Dili']", "\n Asia/Dili - GMT +09:00 "), - m("option[value='Asia/Dubai']", "\n Asia/Dubai - GMT +04:00 "), - m("option[value='Asia/Dushanbe']", "\n Asia/Dushanbe - GMT +05:00 "), - m("option[value='Asia/Gaza']", "\n Asia/Gaza - GMT +02:00 "), - m("option[value='Asia/Hebron']", "\n Asia/Hebron - GMT +02:00 "), - m("option[value='Asia/Ho_Chi_Minh']", "\n Asia/Ho_Chi_Minh - GMT +07:00 "), - m("option[value='Asia/Hong_Kong']", "\n Asia/Hong_Kong - GMT +08:00 "), - m("option[value='Asia/Hovd']", "\n Asia/Hovd - GMT +07:00 "), - m("option[value='Asia/Irkutsk']", "\n Asia/Irkutsk - GMT +08:00 "), - m("option[value='Asia/Jakarta']", "\n Asia/Jakarta - GMT +07:00 "), - m("option[value='Asia/Jayapura']", "\n Asia/Jayapura - GMT +09:00 "), - m("option[value='Asia/Jerusalem']", "\n Asia/Jerusalem - GMT +02:00 "), - m("option[value='Asia/Kabul']", "\n Asia/Kabul - GMT +04:30 "), - m("option[value='Asia/Kamchatka']", "\n Asia/Kamchatka - GMT +12:00 "), - m("option[value='Asia/Karachi']", "\n Asia/Karachi - GMT +05:00 "), - m("option[value='Asia/Kathmandu']", "\n Asia/Kathmandu - GMT +05:45 "), - m("option[value='Asia/Khandyga']", "\n Asia/Khandyga - GMT +09:00 "), - m("option[value='Asia/Kolkata']", "\n Asia/Kolkata - GMT +05:30 "), - m("option[value='Asia/Krasnoyarsk']", "\n Asia/Krasnoyarsk - GMT +07:00 "), - m("option[value='Asia/Kuala_Lumpur']", "\n Asia/Kuala_Lumpur - GMT +08:00 "), - m("option[value='Asia/Kuching']", "\n Asia/Kuching - GMT +08:00 "), - m("option[value='Asia/Kuwait']", "\n Asia/Kuwait - GMT +03:00 "), - m("option[value='Asia/Macau']", "\n Asia/Macau - GMT +08:00 "), - m("option[value='Asia/Magadan']", "\n Asia/Magadan - GMT +10:00 "), - m("option[value='Asia/Makassar']", "\n Asia/Makassar - GMT +08:00 "), - m("option[value='Asia/Manila']", "\n Asia/Manila - GMT +08:00 "), - m("option[value='Asia/Muscat']", "\n Asia/Muscat - GMT +04:00 "), - m("option[value='Asia/Nicosia']", "\n Asia/Nicosia - GMT +02:00 "), - m("option[value='Asia/Novokuznetsk']", "\n Asia/Novokuznetsk - GMT +07:00 "), - m("option[value='Asia/Novosibirsk']", "\n Asia/Novosibirsk - GMT +06:00 "), - m("option[value='Asia/Omsk']", "\n Asia/Omsk - GMT +06:00 "), - m("option[value='Asia/Oral']", "\n Asia/Oral - GMT +05:00 "), - m("option[value='Asia/Phnom_Penh']", "\n Asia/Phnom_Penh - GMT +07:00 "), - m("option[value='Asia/Pontianak']", "\n Asia/Pontianak - GMT +07:00 "), - m("option[value='Asia/Pyongyang']", "\n Asia/Pyongyang - GMT +09:00 "), - m("option[value='Asia/Qatar']", "\n Asia/Qatar - GMT +03:00 "), - m("option[value='Asia/Qyzylorda']", "\n Asia/Qyzylorda - GMT +06:00 "), - m("option[value='Asia/Rangoon']", "\n Asia/Rangoon - GMT +06:30 "), - m("option[value='Asia/Riyadh']", "\n Asia/Riyadh - GMT +03:00 "), - m("option[value='Asia/Sakhalin']", "\n Asia/Sakhalin - GMT +10:00 "), - m("option[value='Asia/Samarkand']", "\n Asia/Samarkand - GMT +05:00 "), - m("option[value='Asia/Seoul']", "\n Asia/Seoul - GMT +09:00 "), - m("option[value='Asia/Shanghai']", "\n Asia/Shanghai - GMT +08:00 "), - m("option[value='Asia/Singapore']", "\n Asia/Singapore - GMT +08:00 "), - m("option[value='Asia/Srednekolymsk']", "\n Asia/Srednekolymsk - GMT +11:00 "), - m("option[value='Asia/Taipei']", "\n Asia/Taipei - GMT +08:00 "), - m("option[value='Asia/Tashkent']", "\n Asia/Tashkent - GMT +05:00 "), - m("option[value='Asia/Tbilisi']", "\n Asia/Tbilisi - GMT +04:00 "), - m("option[value='Asia/Tehran']", "\n Asia/Tehran - GMT +03:30 "), - m("option[value='Asia/Thimphu']", "\n Asia/Thimphu - GMT +06:00 "), - m("option[value='Asia/Tokyo']", "\n Asia/Tokyo - GMT +09:00 "), - m("option[value='Asia/Ulaanbaatar']", "\n Asia/Ulaanbaatar - GMT +08:00 "), - m("option[value='Asia/Urumqi']", "\n Asia/Urumqi - GMT +06:00 "), - m("option[value='Asia/Ust-Nera']", "\n Asia/Ust-Nera - GMT +10:00 "), - m("option[value='Asia/Vientiane']", "\n Asia/Vientiane - GMT +07:00 "), - m("option[value='Asia/Vladivostok']", "\n Asia/Vladivostok - GMT +10:00 "), - m("option[value='Asia/Yakutsk']", "\n Asia/Yakutsk - GMT +09:00 "), - m("option[value='Asia/Yekaterinburg']", "\n Asia/Yekaterinburg - GMT +05:00 "), - m("option[value='Asia/Yerevan']", "\n Asia/Yerevan - GMT +04:00 "), - m("option[value='Atlantic/Azores']", "\n Atlantic/Azores - GMT -01:00 "), - m("option[value='Atlantic/Bermuda']", "\n Atlantic/Bermuda - GMT -04:00 "), - m("option[value='Atlantic/Canary']", "\n Atlantic/Canary - GMT +00:00 "), - m("option[value='Atlantic/Cape_Verde']", "\n Atlantic/Cape_Verde - GMT -01:00 "), - m("option[value='Atlantic/Faroe']", "\n Atlantic/Faroe - GMT +00:00 "), - m("option[value='Atlantic/Madeira']", "\n Atlantic/Madeira - GMT +00:00 "), - m("option[value='Atlantic/Reykjavik']", "\n Atlantic/Reykjavik - GMT +00:00 "), - m("option[value='Atlantic/South_Georgia']", "\n Atlantic/South_Georgia - GMT -02:00 "), - m("option[value='Atlantic/St_Helena']", "\n Atlantic/St_Helena - GMT +00:00 "), - m("option[value='Atlantic/Stanley']", "\n Atlantic/Stanley - GMT -03:00 "), - m("option[value='Australia/Adelaide']", "\n Australia/Adelaide - GMT +10:30 "), - m("option[value='Australia/Brisbane']", "\n Australia/Brisbane - GMT +10:00 "), - m("option[value='Australia/Broken_Hill']", "\n Australia/Broken_Hill - GMT +10:30 "), - m("option[value='Australia/Currie']", "\n Australia/Currie - GMT +11:00 "), - m("option[value='Australia/Darwin']", "\n Australia/Darwin - GMT +09:30 "), - m("option[value='Australia/Eucla']", "\n Australia/Eucla - GMT +08:45 "), - m("option[value='Australia/Hobart']", "\n Australia/Hobart - GMT +11:00 "), - m("option[value='Australia/Lindeman']", "\n Australia/Lindeman - GMT +10:00 "), - m("option[value='Australia/Lord_Howe']", "\n Australia/Lord_Howe - GMT +11:00 "), - m("option[value='Australia/Melbourne']", "\n Australia/Melbourne - GMT +11:00 "), - m("option[value='Australia/Perth']", "\n Australia/Perth - GMT +08:00 "), - m("option[value='Australia/Sydney']", "\n Australia/Sydney - GMT +11:00 "), - m("option[value='Europe/Amsterdam']", "\n Europe/Amsterdam - GMT +01:00 "), - m("option[value='Europe/Andorra']", "\n Europe/Andorra - GMT +01:00 "), - m("option[value='Europe/Athens']", "\n Europe/Athens - GMT +02:00 "), - m("option[value='Europe/Belgrade']", "\n Europe/Belgrade - GMT +01:00 "), - m("option[value='Europe/Berlin']", "\n Europe/Berlin - GMT +01:00 "), - m("option[value='Europe/Bratislava']", "\n Europe/Bratislava - GMT +01:00 "), - m("option[value='Europe/Brussels']", "\n Europe/Brussels - GMT +01:00 "), - m("option[value='Europe/Bucharest']", "\n Europe/Bucharest - GMT +02:00 "), - m("option[value='Europe/Budapest']", "\n Europe/Budapest - GMT +01:00 "), - m("option[value='Europe/Busingen']", "\n Europe/Busingen - GMT +01:00 "), - m("option[value='Europe/Chisinau']", "\n Europe/Chisinau - GMT +02:00 "), - m("option[value='Europe/Copenhagen']", "\n Europe/Copenhagen - GMT +01:00 "), - m("option[value='Europe/Dublin']", "\n Europe/Dublin - GMT +00:00 "), - m("option[value='Europe/Gibraltar']", "\n Europe/Gibraltar - GMT +01:00 "), - m("option[value='Europe/Guernsey']", "\n Europe/Guernsey - GMT +00:00 "), - m("option[value='Europe/Helsinki']", "\n Europe/Helsinki - GMT +02:00 "), - m("option[value='Europe/Isle_of_Man']", "\n Europe/Isle_of_Man - GMT +00:00 "), - m("option[value='Europe/Istanbul']", "\n Europe/Istanbul - GMT +02:00 "), - m("option[value='Europe/Jersey']", "\n Europe/Jersey - GMT +00:00 "), - m("option[value='Europe/Kaliningrad']", "\n Europe/Kaliningrad - GMT +02:00 "), - m("option[value='Europe/Kiev']", "\n Europe/Kiev - GMT +02:00 "), - m("option[value='Europe/Lisbon']", "\n Europe/Lisbon - GMT +00:00 "), - m("option[value='Europe/Ljubljana']", "\n Europe/Ljubljana - GMT +01:00 "), - m("option[value='Europe/London']", "\n Europe/London - GMT +00:00 "), - m("option[value='Europe/Luxembourg']", "\n Europe/Luxembourg - GMT +01:00 "), - m("option[value='Europe/Madrid']", "\n Europe/Madrid - GMT +01:00 "), - m("option[value='Europe/Malta']", "\n Europe/Malta - GMT +01:00 "), - m("option[value='Europe/Mariehamn']", "\n Europe/Mariehamn - GMT +02:00 "), - m("option[value='Europe/Minsk']", "\n Europe/Minsk - GMT +03:00 "), - m("option[value='Europe/Monaco']", "\n Europe/Monaco - GMT +01:00 "), - m("option[value='Europe/Moscow']", "\n Europe/Moscow - GMT +03:00 "), - m("option[value='Europe/Oslo']", "\n Europe/Oslo - GMT +01:00 "), - m("option[value='Europe/Paris']", "\n Europe/Paris - GMT +01:00 "), - m("option[value='Europe/Podgorica']", "\n Europe/Podgorica - GMT +01:00 "), - m("option[value='Europe/Prague']", "\n Europe/Prague - GMT +01:00 "), - m("option[value='Europe/Riga']", "\n Europe/Riga - GMT +02:00 "), - m("option[value='Europe/Rome']", "\n Europe/Rome - GMT +01:00 "), - m("option[value='Europe/Samara']", "\n Europe/Samara - GMT +04:00 "), - m("option[value='Europe/San_Marino']", "\n Europe/San_Marino - GMT +01:00 "), - m("option[value='Europe/Sarajevo']", "\n Europe/Sarajevo - GMT +01:00 "), - m("option[value='Europe/Simferopol']", "\n Europe/Simferopol - GMT +03:00 "), - m("option[value='Europe/Skopje']", "\n Europe/Skopje - GMT +01:00 "), - m("option[value='Europe/Sofia']", "\n Europe/Sofia - GMT +02:00 "), - m("option[value='Europe/Stockholm']", "\n Europe/Stockholm - GMT +01:00 "), - m("option[value='Europe/Tallinn']", "\n Europe/Tallinn - GMT +02:00 "), - m("option[value='Europe/Tirane']", "\n Europe/Tirane - GMT +01:00 "), - m("option[value='Europe/Uzhgorod']", "\n Europe/Uzhgorod - GMT +02:00 "), - m("option[value='Europe/Vaduz']", "\n Europe/Vaduz - GMT +01:00 "), - m("option[value='Europe/Vatican']", "\n Europe/Vatican - GMT +01:00 "), - m("option[value='Europe/Vienna']", "\n Europe/Vienna - GMT +01:00 "), - m("option[value='Europe/Vilnius']", "\n Europe/Vilnius - GMT +02:00 "), - m("option[value='Europe/Volgograd']", "\n Europe/Volgograd - GMT +03:00 "), - m("option[value='Europe/Warsaw']", "\n Europe/Warsaw - GMT +01:00 "), - m("option[value='Europe/Zagreb']", "\n Europe/Zagreb - GMT +01:00 "), - m("option[value='Europe/Zaporozhye']", "\n Europe/Zaporozhye - GMT +02:00 "), - m("option[value='Europe/Zurich']", "\n Europe/Zurich - GMT +01:00 "), - m("option[value='Indian/Antananarivo']", "\n Indian/Antananarivo - GMT +03:00 "), - m("option[value='Indian/Chagos']", "\n Indian/Chagos - GMT +06:00 "), - m("option[value='Indian/Christmas']", "\n Indian/Christmas - GMT +07:00 "), - m("option[value='Indian/Cocos']", "\n Indian/Cocos - GMT +06:30 "), - m("option[value='Indian/Comoro']", "\n Indian/Comoro - GMT +03:00 "), - m("option[value='Indian/Kerguelen']", "\n Indian/Kerguelen - GMT +05:00 "), - m("option[value='Indian/Mahe']", "\n Indian/Mahe - GMT +04:00 "), - m("option[value='Indian/Maldives']", "\n Indian/Maldives - GMT +05:00 "), - m("option[value='Indian/Mauritius']", "\n Indian/Mauritius - GMT +04:00 "), - m("option[value='Indian/Mayotte']", "\n Indian/Mayotte - GMT +03:00 "), - m("option[value='Indian/Reunion']", "\n Indian/Reunion - GMT +04:00 "), - m("option[value='Pacific/Apia']", "\n Pacific/Apia - GMT +14:00 "), - m("option[value='Pacific/Auckland']", "\n Pacific/Auckland - GMT +13:00 "), - m("option[value='Pacific/Chatham']", "\n Pacific/Chatham - GMT +13:45 "), - m("option[value='Pacific/Chuuk']", "\n Pacific/Chuuk - GMT +10:00 "), - m("option[value='Pacific/Easter']", "\n Pacific/Easter - GMT -05:00 "), - m("option[value='Pacific/Efate']", "\n Pacific/Efate - GMT +11:00 "), - m("option[value='Pacific/Enderbury']", "\n Pacific/Enderbury - GMT +13:00 "), - m("option[value='Pacific/Fakaofo']", "\n Pacific/Fakaofo - GMT +13:00 "), - m("option[value='Pacific/Fiji']", "\n Pacific/Fiji - GMT +13:00 "), - m("option[value='Pacific/Funafuti']", "\n Pacific/Funafuti - GMT +12:00 "), - m("option[value='Pacific/Galapagos']", "\n Pacific/Galapagos - GMT -06:00 "), - m("option[value='Pacific/Gambier']", "\n Pacific/Gambier - GMT -09:00 "), - m("option[value='Pacific/Guadalcanal']", "\n Pacific/Guadalcanal - GMT +11:00 "), - m("option[value='Pacific/Guam']", "\n Pacific/Guam - GMT +10:00 "), - m("option[value='Pacific/Honolulu']", "\n Pacific/Honolulu - GMT -10:00 "), - m("option[value='Pacific/Johnston']", "\n Pacific/Johnston - GMT -10:00 "), - m("option[value='Pacific/Kiritimati']", "\n Pacific/Kiritimati - GMT +14:00 "), - m("option[value='Pacific/Kosrae']", "\n Pacific/Kosrae - GMT +11:00 "), - m("option[value='Pacific/Kwajalein']", "\n Pacific/Kwajalein - GMT +12:00 "), - m("option[value='Pacific/Majuro']", "\n Pacific/Majuro - GMT +12:00 "), - m("option[value='Pacific/Marquesas']", "\n Pacific/Marquesas - GMT -09:30 "), - m("option[value='Pacific/Midway']", "\n Pacific/Midway - GMT -11:00 "), - m("option[value='Pacific/Nauru']", "\n Pacific/Nauru - GMT +12:00 "), - m("option[value='Pacific/Niue']", "\n Pacific/Niue - GMT -11:00 "), - m("option[value='Pacific/Norfolk']", "\n Pacific/Norfolk - GMT +11:30 "), - m("option[value='Pacific/Noumea']", "\n Pacific/Noumea - GMT +11:00 "), - m("option[value='Pacific/Pago_Pago']", "\n Pacific/Pago_Pago - GMT -11:00 "), - m("option[value='Pacific/Palau']", "\n Pacific/Palau - GMT +09:00 "), - m("option[value='Pacific/Pitcairn']", "\n Pacific/Pitcairn - GMT -08:00 "), - m("option[value='Pacific/Pohnpei']", "\n Pacific/Pohnpei - GMT +11:00 "), - m("option[value='Pacific/Port_Moresby']", "\n Pacific/Port_Moresby - GMT +10:00 "), - m("option[value='Pacific/Rarotonga']", "\n Pacific/Rarotonga - GMT -10:00 "), - m("option[value='Pacific/Saipan']", "\n Pacific/Saipan - GMT +10:00 "), - m("option[value='Pacific/Tahiti']", "\n Pacific/Tahiti - GMT -10:00 "), - m("option[value='Pacific/Tarawa']", "\n Pacific/Tarawa - GMT +12:00 "), - m("option[value='Pacific/Tongatapu']", "\n Pacific/Tongatapu - GMT +13:00 "), - m("option[value='Pacific/Wake']", "\n Pacific/Wake - GMT +12:00 "), - m("option[value='Pacific/Wallis']", "\n Pacific/Wallis - GMT +12:00 "), - m("option[value='UTC']", "\n UTC - GMT +00:00 ") - ]), - m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='America/New_York - GMT -05:00'][type='button']", [m("span.filter-option.pull-left", "\n America/New_York - GMT -05:00 "), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Abidjan - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Accra - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Addis_Ababa - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Algiers - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Asmara - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bamako - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bangui - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Banjul - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='8']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bissau - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='9']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Blantyre - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='10']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Brazzaville - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='11']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bujumbura - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='12']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Cairo - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='13']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Casablanca - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='14']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ceuta - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='15']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Conakry - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='16']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Dakar - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='17']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Dar_es_Salaam - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='18']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Djibouti - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='19']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Douala - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='20']", [m("a[tabindex='0']", [m("span.text", "\n Africa/El_Aaiun - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='21']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Freetown - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='22']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Gaborone - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='23']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Harare - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='24']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Johannesburg - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='25']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Juba - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='26']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kampala - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='27']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Khartoum - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='28']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kigali - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='29']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kinshasa - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='30']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lagos - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='31']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Libreville - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='32']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lome - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='33']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Luanda - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='34']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lubumbashi - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='35']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lusaka - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='36']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Malabo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='37']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Maputo - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='38']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Maseru - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='39']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Mbabane - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='40']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Mogadishu - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='41']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Monrovia - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='42']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Nairobi - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='43']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ndjamena - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='44']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Niamey - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='45']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Nouakchott - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='46']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ouagadougou - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='47']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Porto-Novo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='48']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Sao_Tome - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='49']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Tripoli - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='50']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Tunis - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='51']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Windhoek - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='52']", [m("a[tabindex='0']", [m("span.text", "\n America/Adak - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='53']", [m("a[tabindex='0']", [m("span.text", "\n America/Anchorage - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='54']", [m("a[tabindex='0']", [m("span.text", "\n America/Anguilla - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='55']", [m("a[tabindex='0']", [m("span.text", "\n America/Antigua - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='56']", [m("a[tabindex='0']", [m("span.text", "\n America/Araguaina - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='57']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Buenos_Aires - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='58']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Catamarca - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='59']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Cordoba - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='60']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Jujuy - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='61']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/La_Rioja - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='62']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Mendoza - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='63']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Rio_Gallegos - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='64']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Salta - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='65']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/San_Juan - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='66']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/San_Luis - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='67']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Tucuman - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='68']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Ushuaia - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='69']", [m("a[tabindex='0']", [m("span.text", "\n America/Aruba - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='70']", [m("a[tabindex='0']", [m("span.text", "\n America/Asuncion - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='71']", [m("a[tabindex='0']", [m("span.text", "\n America/Atikokan - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='72']", [m("a[tabindex='0']", [m("span.text", "\n America/Bahia - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='73']", [m("a[tabindex='0']", [m("span.text", "\n America/Bahia_Banderas - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='74']", [m("a[tabindex='0']", [m("span.text", "\n America/Barbados - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='75']", [m("a[tabindex='0']", [m("span.text", "\n America/Belem - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='76']", [m("a[tabindex='0']", [m("span.text", "\n America/Belize - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='77']", [m("a[tabindex='0']", [m("span.text", "\n America/Blanc-Sablon - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='78']", [m("a[tabindex='0']", [m("span.text", "\n America/Boa_Vista - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='79']", [m("a[tabindex='0']", [m("span.text", "\n America/Bogota - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='80']", [m("a[tabindex='0']", [m("span.text", "\n America/Boise - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='81']", [m("a[tabindex='0']", [m("span.text", "\n America/Cambridge_Bay - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='82']", [m("a[tabindex='0']", [m("span.text", "\n America/Campo_Grande - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='83']", [m("a[tabindex='0']", [m("span.text", "\n America/Cancun - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='84']", [m("a[tabindex='0']", [m("span.text", "\n America/Caracas - GMT -04:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='85']", [m("a[tabindex='0']", [m("span.text", "\n America/Cayenne - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='86']", [m("a[tabindex='0']", [m("span.text", "\n America/Cayman - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='87']", [m("a[tabindex='0']", [m("span.text", "\n America/Chicago - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='88']", [m("a[tabindex='0']", [m("span.text", "\n America/Chihuahua - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='89']", [m("a[tabindex='0']", [m("span.text", "\n America/Costa_Rica - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='90']", [m("a[tabindex='0']", [m("span.text", "\n America/Creston - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='91']", [m("a[tabindex='0']", [m("span.text", "\n America/Cuiaba - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='92']", [m("a[tabindex='0']", [m("span.text", "\n America/Curacao - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='93']", [m("a[tabindex='0']", [m("span.text", "\n America/Danmarkshavn - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='94']", [m("a[tabindex='0']", [m("span.text", "\n America/Dawson - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='95']", [m("a[tabindex='0']", [m("span.text", "\n America/Dawson_Creek - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='96']", [m("a[tabindex='0']", [m("span.text", "\n America/Denver - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='97']", [m("a[tabindex='0']", [m("span.text", "\n America/Detroit - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='98']", [m("a[tabindex='0']", [m("span.text", "\n America/Dominica - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='99']", [m("a[tabindex='0']", [m("span.text", "\n America/Edmonton - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='100']", [m("a[tabindex='0']", [m("span.text", "\n America/Eirunepe - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='101']", [m("a[tabindex='0']", [m("span.text", "\n America/El_Salvador - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='102']", [m("a[tabindex='0']", [m("span.text", "\n America/Fortaleza - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='103']", [m("a[tabindex='0']", [m("span.text", "\n America/Glace_Bay - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='104']", [m("a[tabindex='0']", [m("span.text", "\n America/Godthab - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='105']", [m("a[tabindex='0']", [m("span.text", "\n America/Goose_Bay - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='106']", [m("a[tabindex='0']", [m("span.text", "\n America/Grand_Turk - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='107']", [m("a[tabindex='0']", [m("span.text", "\n America/Grenada - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='108']", [m("a[tabindex='0']", [m("span.text", "\n America/Guadeloupe - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='109']", [m("a[tabindex='0']", [m("span.text", "\n America/Guatemala - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='110']", [m("a[tabindex='0']", [m("span.text", "\n America/Guayaquil - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='111']", [m("a[tabindex='0']", [m("span.text", "\n America/Guyana - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='112']", [m("a[tabindex='0']", [m("span.text", "\n America/Halifax - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='113']", [m("a[tabindex='0']", [m("span.text", "\n America/Havana - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='114']", [m("a[tabindex='0']", [m("span.text", "\n America/Hermosillo - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='115']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Indianapolis - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='116']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Knox - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='117']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Marengo - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='118']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Petersburg - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='119']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Tell_City - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='120']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Vevay - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='121']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Vincennes - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='122']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Winamac - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='123']", [m("a[tabindex='0']", [m("span.text", "\n America/Inuvik - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='124']", [m("a[tabindex='0']", [m("span.text", "\n America/Iqaluit - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='125']", [m("a[tabindex='0']", [m("span.text", "\n America/Jamaica - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='126']", [m("a[tabindex='0']", [m("span.text", "\n America/Juneau - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='127']", [m("a[tabindex='0']", [m("span.text", "\n America/Kentucky/Louisville - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='128']", [m("a[tabindex='0']", [m("span.text", "\n America/Kentucky/Monticello - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='129']", [m("a[tabindex='0']", [m("span.text", "\n America/Kralendijk - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='130']", [m("a[tabindex='0']", [m("span.text", "\n America/La_Paz - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='131']", [m("a[tabindex='0']", [m("span.text", "\n America/Lima - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='132']", [m("a[tabindex='0']", [m("span.text", "\n America/Los_Angeles - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='133']", [m("a[tabindex='0']", [m("span.text", "\n America/Lower_Princes - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='134']", [m("a[tabindex='0']", [m("span.text", "\n America/Maceio - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='135']", [m("a[tabindex='0']", [m("span.text", "\n America/Managua - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='136']", [m("a[tabindex='0']", [m("span.text", "\n America/Manaus - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='137']", [m("a[tabindex='0']", [m("span.text", "\n America/Marigot - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='138']", [m("a[tabindex='0']", [m("span.text", "\n America/Martinique - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='139']", [m("a[tabindex='0']", [m("span.text", "\n America/Matamoros - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='140']", [m("a[tabindex='0']", [m("span.text", "\n America/Mazatlan - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='141']", [m("a[tabindex='0']", [m("span.text", "\n America/Menominee - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='142']", [m("a[tabindex='0']", [m("span.text", "\n America/Merida - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='143']", [m("a[tabindex='0']", [m("span.text", "\n America/Metlakatla - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='144']", [m("a[tabindex='0']", [m("span.text", "\n America/Mexico_City - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='145']", [m("a[tabindex='0']", [m("span.text", "\n America/Miquelon - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='146']", [m("a[tabindex='0']", [m("span.text", "\n America/Moncton - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='147']", [m("a[tabindex='0']", [m("span.text", "\n America/Monterrey - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='148']", [m("a[tabindex='0']", [m("span.text", "\n America/Montevideo - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='149']", [m("a[tabindex='0']", [m("span.text", "\n America/Montserrat - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='150']", [m("a[tabindex='0']", [m("span.text", "\n America/Nassau - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='151']", [m("a[tabindex='0']", [m("span.text", "\n America/New_York - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='152']", [m("a[tabindex='0']", [m("span.text", "\n America/Nipigon - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='153']", [m("a[tabindex='0']", [m("span.text", "\n America/Nome - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='154']", [m("a[tabindex='0']", [m("span.text", "\n America/Noronha - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='155']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/Beulah - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='156']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/Center - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='157']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/New_Salem - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='158']", [m("a[tabindex='0']", [m("span.text", "\n America/Ojinaga - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='159']", [m("a[tabindex='0']", [m("span.text", "\n America/Panama - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='160']", [m("a[tabindex='0']", [m("span.text", "\n America/Pangnirtung - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='161']", [m("a[tabindex='0']", [m("span.text", "\n America/Paramaribo - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='162']", [m("a[tabindex='0']", [m("span.text", "\n America/Phoenix - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='163']", [m("a[tabindex='0']", [m("span.text", "\n America/Port-au-Prince - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='164']", [m("a[tabindex='0']", [m("span.text", "\n America/Port_of_Spain - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='165']", [m("a[tabindex='0']", [m("span.text", "\n America/Porto_Velho - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='166']", [m("a[tabindex='0']", [m("span.text", "\n America/Puerto_Rico - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='167']", [m("a[tabindex='0']", [m("span.text", "\n America/Rainy_River - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='168']", [m("a[tabindex='0']", [m("span.text", "\n America/Rankin_Inlet - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='169']", [m("a[tabindex='0']", [m("span.text", "\n America/Recife - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='170']", [m("a[tabindex='0']", [m("span.text", "\n America/Regina - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='171']", [m("a[tabindex='0']", [m("span.text", "\n America/Resolute - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='172']", [m("a[tabindex='0']", [m("span.text", "\n America/Rio_Branco - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='173']", [m("a[tabindex='0']", [m("span.text", "\n America/Santa_Isabel - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='174']", [m("a[tabindex='0']", [m("span.text", "\n America/Santarem - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='175']", [m("a[tabindex='0']", [m("span.text", "\n America/Santiago - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='176']", [m("a[tabindex='0']", [m("span.text", "\n America/Santo_Domingo - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='177']", [m("a[tabindex='0']", [m("span.text", "\n America/Sao_Paulo - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='178']", [m("a[tabindex='0']", [m("span.text", "\n America/Scoresbysund - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='179']", [m("a[tabindex='0']", [m("span.text", "\n America/Sitka - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='180']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Barthelemy - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='181']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Johns - GMT -03:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='182']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Kitts - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='183']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Lucia - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='184']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Thomas - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='185']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Vincent - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='186']", [m("a[tabindex='0']", [m("span.text", "\n America/Swift_Current - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='187']", [m("a[tabindex='0']", [m("span.text", "\n America/Tegucigalpa - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='188']", [m("a[tabindex='0']", [m("span.text", "\n America/Thule - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='189']", [m("a[tabindex='0']", [m("span.text", "\n America/Thunder_Bay - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='190']", [m("a[tabindex='0']", [m("span.text", "\n America/Tijuana - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='191']", [m("a[tabindex='0']", [m("span.text", "\n America/Toronto - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='192']", [m("a[tabindex='0']", [m("span.text", "\n America/Tortola - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='193']", [m("a[tabindex='0']", [m("span.text", "\n America/Vancouver - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='194']", [m("a[tabindex='0']", [m("span.text", "\n America/Whitehorse - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='195']", [m("a[tabindex='0']", [m("span.text", "\n America/Winnipeg - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='196']", [m("a[tabindex='0']", [m("span.text", "\n America/Yakutat - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='197']", [m("a[tabindex='0']", [m("span.text", "\n America/Yellowknife - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='198']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Casey - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='199']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Davis - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='200']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/DumontDUrville - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='201']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Macquarie - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='202']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Mawson - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='203']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/McMurdo - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='204']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Palmer - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='205']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Rothera - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='206']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Syowa - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='207']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Troll - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='208']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Vostok - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='209']", [m("a[tabindex='0']", [m("span.text", "\n Arctic/Longyearbyen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='210']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aden - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='211']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Almaty - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='212']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Amman - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='213']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Anadyr - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='214']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aqtau - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='215']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aqtobe - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='216']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ashgabat - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='217']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Baghdad - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='218']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bahrain - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='219']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Baku - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='220']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bangkok - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='221']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Beirut - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='222']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bishkek - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='223']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Brunei - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='224']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Chita - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='225']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Choibalsan - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='226']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Colombo - GMT +05:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='227']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Damascus - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='228']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dhaka - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='229']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dili - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='230']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dubai - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='231']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dushanbe - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='232']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Gaza - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='233']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hebron - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='234']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ho_Chi_Minh - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='235']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hong_Kong - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='236']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hovd - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='237']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Irkutsk - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='238']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jakarta - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='239']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jayapura - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='240']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jerusalem - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='241']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kabul - GMT +04:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='242']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kamchatka - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='243']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Karachi - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='244']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kathmandu - GMT +05:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='245']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Khandyga - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='246']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kolkata - GMT +05:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='247']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Krasnoyarsk - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='248']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuala_Lumpur - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='249']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuching - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='250']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuwait - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='251']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Macau - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='252']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Magadan - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='253']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Makassar - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='254']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Manila - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='255']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Muscat - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='256']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Nicosia - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='257']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Novokuznetsk - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='258']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Novosibirsk - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='259']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Omsk - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='260']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Oral - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='261']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Phnom_Penh - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='262']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Pontianak - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='263']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Pyongyang - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='264']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Qatar - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='265']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Qyzylorda - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='266']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Rangoon - GMT +06:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='267']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Riyadh - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='268']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Sakhalin - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='269']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Samarkand - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='270']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Seoul - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='271']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Shanghai - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='272']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Singapore - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='273']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Srednekolymsk - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='274']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Taipei - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='275']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tashkent - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='276']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tbilisi - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='277']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tehran - GMT +03:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='278']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Thimphu - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='279']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tokyo - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='280']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ulaanbaatar - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='281']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Urumqi - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='282']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ust-Nera - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='283']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Vientiane - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='284']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Vladivostok - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='285']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yakutsk - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='286']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yekaterinburg - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='287']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yerevan - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='288']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Azores - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='289']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Bermuda - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='290']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Canary - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='291']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Cape_Verde - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='292']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Faroe - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='293']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Madeira - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='294']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Reykjavik - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='295']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/South_Georgia - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='296']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/St_Helena - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='297']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Stanley - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='298']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Adelaide - GMT +10:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='299']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Brisbane - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='300']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Broken_Hill - GMT +10:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='301']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Currie - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='302']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Darwin - GMT +09:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='303']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Eucla - GMT +08:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='304']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Hobart - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='305']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Lindeman - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='306']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Lord_Howe - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='307']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Melbourne - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='308']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Perth - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='309']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Sydney - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='310']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Amsterdam - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='311']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Andorra - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='312']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Athens - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='313']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Belgrade - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='314']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Berlin - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='315']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Bratislava - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='316']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Brussels - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='317']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Bucharest - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='318']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Budapest - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='319']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Busingen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='320']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Chisinau - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='321']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Copenhagen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='322']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Dublin - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='323']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Gibraltar - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='324']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Guernsey - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='325']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Helsinki - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='326']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Isle_of_Man - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='327']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Istanbul - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='328']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Jersey - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='329']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Kaliningrad - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='330']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Kiev - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='331']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Lisbon - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='332']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Ljubljana - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='333']", [m("a[tabindex='0']", [m("span.text", "\n Europe/London - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='334']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Luxembourg - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='335']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Madrid - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='336']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Malta - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='337']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Mariehamn - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='338']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Minsk - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='339']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Monaco - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='340']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Moscow - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='341']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Oslo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='342']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Paris - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='343']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Podgorica - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='344']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Prague - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='345']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Riga - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='346']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Rome - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='347']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Samara - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='348']", [m("a[tabindex='0']", [m("span.text", "\n Europe/San_Marino - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='349']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Sarajevo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='350']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Simferopol - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='351']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Skopje - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='352']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Sofia - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='353']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Stockholm - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='354']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Tallinn - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='355']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Tirane - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='356']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Uzhgorod - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='357']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vaduz - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='358']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vatican - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='359']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vienna - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='360']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vilnius - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='361']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Volgograd - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='362']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Warsaw - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='363']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zagreb - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='364']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zaporozhye - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='365']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zurich - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='366']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Antananarivo - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='367']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Chagos - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='368']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Christmas - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='369']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Cocos - GMT +06:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='370']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Comoro - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='371']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Kerguelen - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='372']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mahe - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='373']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Maldives - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='374']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mauritius - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='375']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mayotte - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='376']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Reunion - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='377']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Apia - GMT +14:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='378']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Auckland - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='379']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Chatham - GMT +13:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='380']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Chuuk - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='381']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Easter - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='382']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Efate - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='383']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Enderbury - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='384']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Fakaofo - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='385']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Fiji - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='386']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Funafuti - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='387']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Galapagos - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='388']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Gambier - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='389']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Guadalcanal - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='390']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Guam - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='391']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Honolulu - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='392']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Johnston - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='393']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kiritimati - GMT +14:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='394']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kosrae - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='395']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kwajalein - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='396']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Majuro - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='397']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Marquesas - GMT -09:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='398']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Midway - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='399']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Nauru - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='400']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Niue - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='401']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Norfolk - GMT +11:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='402']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Noumea - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='403']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pago_Pago - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='404']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Palau - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='405']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pitcairn - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='406']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pohnpei - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='407']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Port_Moresby - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='408']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Rarotonga - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='409']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Saipan - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='410']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tahiti - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='411']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tarawa - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='412']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tongatapu - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='413']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Wake - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='414']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Wallis - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='415']", [m("a[tabindex='0']", [m("span.text", "\n UTC - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), - m("span.help-block", "Set the system timezone.") - ]) - ]), - m(".form-group.form-actions", [ - m(".col-sm-offset-2.col-sm-10", [ - m("button.btn.btn-primary.btn-lg[name='save'][type='submit'][value='save']", "Apply settings") - ]) - ]) - ]) - ]), - m("form.form-horizontal[method='post'][role='form']", [ - m("fieldset", [ - m("legend", "RuneOS kernel settings"), - m(".form-group", [ - m("label.control-label.col-sm-2[for='i2smodule']", "Linux Kernel"), - m(".col-sm-10", [ - m("select.selectpicker[data-style='btn-default btn-lg'][name='kernel']", { style: { "display": " none" } }, [ - m("option[selected=''][value='linux-arch-rpi_3.12.26-1-ARCH']", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), - m("option[value='linux-rune-rpi_3.12.19-2-ARCH']", "Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]"), - m("option[value='linux-rune-rpi_3.6.11-18-ARCH+']", "Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]"), - m("option[value='linux-rune-rpi_3.12.13-rt21_wosa']", "Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]") - ]), - m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='Linux kernel 3.12.26-1   ARCH [RuneAudio v0.3-beta]'][type='button']", [m("span.filter-option.pull-left", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li.selected[rel='0']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), - m("span.help-block", ["Switch Linux Kernel version (REBOOT REQUIRED). ", m("strong", "Linux kernel 3.12.26-1"), " is the default kernel in the current release, ", m("strong", "Linux kernel 3.12.19-2"), " is the kernel used in RuneAudio v0.3-alpha, ", m("strong", "Linux kernel 3.6.11-18"), " is the kernel used in RuneAudio v0.1-beta/v0.2-beta (it has no support for I²S), ", m("strong", "Linux kernel 3.12.13-rt"), " is an EXPERIMENTAL kernel (not suitable for all configurations), it is optimized for ", m("strong", "Wolfson Audio Card"), " support and it is the default option for that type of soundcard."]) - ]), - m("label.control-label.col-sm-2[for='i2smodule']", "I²S kernel modules"), - m(".col-sm-10", [ - m("select.selectpicker[data-style='btn-default btn-lg'][name='i2smodule']", { style: { "display": " none" } }, [ - m("option[value='none']", "I²S disabled (default)"), - m("option[value='berrynos']", "G2Labs BerryNOS"), - m("option[value='berrynosmini']", "G2Labs BerryNOS mini"), - m("option[value='hifiberrydac']", "HiFiBerry DAC"), - m("option[value='hifiberrydacplus']", "HiFiBerry DAC+"), - m("option[value='hifiberrydigi']", "HiFiBerry Digi / Digi+"), - m("option[value='iqaudiopidac']", "IQaudIO Pi-DAC / Pi-DAC+"), - m("option[value='raspyplay3']", "RaspyPlay3"), - m("option[value='raspyplay4']", "RaspyPlay4"), - m("option[selected=''][value='transducer']", "Transducer") - ]), - m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='Transducer'][type='button']", [m("span.filter-option.pull-left", "Transducer"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "I²S disabled (default)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "G2Labs BerryNOS"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "G2Labs BerryNOS mini"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry DAC"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry DAC+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry Digi / Digi+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "IQaudIO Pi-DAC / Pi-DAC+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "RaspyPlay3"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='8']", [m("a[tabindex='0']", [m("span.text", "RaspyPlay4"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='9']", [m("a[tabindex='0']", [m("span.text", "Transducer"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), - m("span.help-block", ["Enable I²S output selecting one of the available sets of modules, specific for each hardware. Once set, the output interface will appear in the ", m("a[href='/mpd/']", "MPD configuration select menu"), ", and modules will also auto-load from the next reboot."]) - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='orionprofile']", "Sound Signature (optimization profiles)"), - m(".col-sm-10", [ - m("select.selectpicker[data-style='btn-default btn-lg'][name='orionprofile']", { style: { "display": " none" } }, [ - m("option[value='default']", "ArchLinux default"), - m("option[value='RuneAudio']", "RuneAudio"), - m("option[selected=''][value='ACX']", "ACX"), - m("option[value='Orion']", "Orion"), - m("option[value='OrionV2']", "OrionV2"), - m("option[value='OrionV3_berrynosmini']", "OrionV3 - (BerryNOS-mini)"), - m("option[value='OrionV3_iqaudio']", "OrionV3 - (IQaudioPi-DAC)"), - m("option[value='Um3ggh1U']", "Um3ggh1U") - ]), - m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='ACX'][type='button']", [m("span.filter-option.pull-left", "ACX"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "ArchLinux default"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "RuneAudio"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='2']", [m("a[tabindex='0']", [m("span.text", "ACX"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "Orion"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "OrionV2"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "OrionV3 - (BerryNOS-mini)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "OrionV3 - (IQaudioPi-DAC)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "Um3ggh1U"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), - m("span.help-block", ["These profiles include a set of performance tweaks that act on some system kernel parameters.\n It does not have anything to do with DSPs or other sound effects: the output is kept untouched (bit perfect).\n It happens that these parameters introduce an audible impact on the overall sound quality, acting on kernel latency parameters (and probably on the amount of overall \n ", m("a[href='http://www.thewelltemperedcomputer.com/KB/BitPerfectJitter.htm'][target='_blank'][title='Bit Perfect Jitter by Vincent Kars']", "jitter"), ").\n Sound results may vary depending on where music is listened, so choose according to your personal taste.\n (If you can't hear any tangible differences... nevermind, just stick to the default settings.)"]) - ]) - ]), - m(".form-group.form-actions", [ - m(".col-sm-offset-2.col-sm-10", [ - m("button.btn.btn-primary.btn-lg[name='save'][type='submit'][value='save']", "Apply settings") - ]) - ]) - ]) - ]), - m("form.form-horizontal[action=''][data-parsley-validate=''][method='post'][novalidate=''][role='form']", [ - m("fieldset[id='features-management']", [ - m("legend", "Features management"), - m("p", "Enable/disable optional modules that best suit your needs. Disabling unusued features will free system resources and might improve the overall performance."), - m("[id='airplayBox']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='airplay']", "AirPlay"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[data-parsley-id='0451'][data-parsley-multiple='featuresairplayenable'][id='airplay'][name='features[airplay][enable]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featuresairplayenable']"), - m("span.help-block", "Toggle the capability of receiving wireless streaming of audio via AirPlay protocol") - ]) - ]), - m(".hide[id='airplayName']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='airplay-name']", "AirPlay name"), - m(".col-sm-10", [ - m("input.form-control.input-lg[data-parsley-id='0928'][data-trigger='change'][id='airplay_name'][name='features[airplay][name]'][placeholder='runeaudio'][type='text'][value='RuneAudio']"), - m("ul.parsley-errors-list[id='parsley-id-0928']"), - m("span.help-block", "AirPlay broadcast name") - ]) - ]) - ]) - ]), - m("[id='spotifyBox']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='spotify']", "Spotify"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[data-parsley-id='3701'][data-parsley-multiple='featuresspotifyenable'][id='spotify'][name='features[spotify][enable]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary.") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featuresspotifyenable']"), - m("span.help-block", ["Enable Spotify client [EXPERIMENTAL]. You must have a ", m("strong", [m("a[href='https://www.spotify.com/uk/premium/'][target='_blank']", "Spotify PREMIUM")]), " account."]) - ]) - ]), - m(".hide[id='spotifyAuth']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='spotify-usr']", "Username"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='0174'][data-trigger='change'][id='spotify_user'][name='features[spotify][user]'][placeholder='user'][type='text'][value='user']"), - m("ul.parsley-errors-list[id='parsley-id-0174']"), - m("span.help-block", ["Insert your Spotify ", m("i", "username")]) - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='spotify-pasw']", "Password"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='0985'][id='spotify_pass'][name='features[spotify][pass]'][placeholder='pass'][type='password'][value='pass']"), - m("ul.parsley-errors-list[id='parsley-id-0985']"), - m("span.help-block", ["Insert your Spotify ", m("i", "password"), " (case sensitive)"]) - ]) - ]) - ]) - ]), - m("[id='dlnaBox']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='dlna']", "UPnP / DLNA"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[data-parsley-id='1837'][data-parsley-multiple='featuresdlnaenable'][id='dlna'][name='features[dlna][enable]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featuresdlnaenable']"), - m("span.help-block", "Toggle the capability of receiving wireless streaming of audio via UPnP / DLNA protocol") - ]) - ]), - m(".hide[id='dlnaName']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='dlna-name']", "UPnP / DLNA name"), - m(".col-sm-10", [ - m("input.form-control.input-lg[data-parsley-id='8193'][data-trigger='change'][id='dlna_name'][name='features[dlna][name]'][placeholder='runeaudio'][type='text'][value='RuneAudio']"), - m("ul.parsley-errors-list[id='parsley-id-8193']"), - m("span.help-block", "UPnP / DLNA broadcast name") - ]) - ]) - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='udevil']", "USB Automount"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[data-parsley-id='1024'][data-parsley-multiple='featuresudevil'][name='features[udevil]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featuresudevil']"), - m("span.help-block", "Toggle automount for USB drives") - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='coverart']", "Display album cover"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[checked='checked'][data-parsley-id='5818'][data-parsley-multiple='featurescoverart'][name='features[coverart]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featurescoverart']"), - m("span.help-block", "Toggle the display of album art on the Playback main screen") - ]) - ]), - m("[id='lastfmBox']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='lastfm']", [m("i.fa.fa.fa-lastfm-square"), " Last.fm"]), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[data-parsley-id='6913'][data-parsley-multiple='featureslastfmenable'][id='scrobbling-lastfm'][name='features[lastfm][enable]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("ul.parsley-errors-list[id='parsley-id-multiple-featureslastfmenable']"), - m("span.help-block", "Send to Last.fm informations about the music you are listening to (requires a Last.fm account)") - ]) - ]), - m(".hide[id='lastfmAuth']", [ - m(".form-group", [ - m("label.control-label.col-sm-2[for='lastfm-usr']", "Username"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='9931'][data-trigger='change'][id='lastfm_user'][name='features[lastfm][user]'][placeholder='user'][type='text'][value='user']"), - m("ul.parsley-errors-list[id='parsley-id-9931']"), - m("span.help-block", ["Insert your Last.fm ", m("i", "username")]) - ]) - ]), - m(".form-group", [ - m("label.control-label.col-sm-2[for='lastfm-pasw']", "Password"), - m(".col-sm-10", [ - m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='2505'][id='lastfm_pass'][name='features[lastfm][pass]'][placeholder='pass'][type='password'][value='pass']"), - m("ul.parsley-errors-list[id='parsley-id-2505']"), - m("span.help-block", ["Insert your Last.fm ", m("i", "password"), " (case sensitive)"]) - ]) - ]) - ]) - ]), - m(".form-group.form-actions", [ - m(".col-sm-offset-2.col-sm-10", [ - m("button.btn.btn-primary.btn-lg[name='features[submit]'][type='submit'][value='1']", "apply settings") - ]) - ]) - ]) - ]), - m("form.form-horizontal[action=''][method='post'][role='form']", [ - m("fieldset", [ - m("legend", "Compatibility fixes"), - m("p", "For people suffering problems with some receivers and DACs."), - m(".form-group", [ - m("label.control-label.col-sm-2[for='cmediafix']", "CMedia fix"), - m(".col-sm-10", [ - m("label.switch-light.well[onclick='']", [ - m("input[name='cmediafix[1]'][type='checkbox'][value='1']"), - m("span", [m("span", "OFF"), m("span", "ON")]), - m("a.btn.btn-primary") - ]), - m("span.help-block", ["For those who have a CM6631 receiver and experiment issues (noise, crackling) between tracks with different sample rates and/or bit depth.", m("br"), " \n A \"dirty\" fix that should avoid the problem, do NOT use if everything works normally."]) - ]) - ]), - m(".form-group.form-actions", [ - m(".col-sm-offset-2.col-sm-10", [ - m("button.btn.btn-primary.btn-lg[name='cmediafix[0]'][type='submit'][value='1']", "Apply fixes") - ]) - ]) - ]) - ]), - m("form.form-horizontal[method='post']", [ - m("fieldset", [ - m("legend", "Backup / Restore configuration"), - m("p", "Transfer settings between multiple RuneAudio installations, saving time during new/upgrade installations."), - m(".form-group", [ - m("label.control-label.col-sm-2", "Backup player config"), - m(".col-sm-10", [ - m("input.btn.btn-primary.btn-lg[id='syscmd-backup'][name='syscmd'][type='submit'][value='backup']"), - m("span.help-block", "NOTE: restore feature will come in 0.4 release.") - ]) - ]) - ]) - ]), - "\n"]; + return [ + m("h1", "Settings"), + m("form.form-horizontal[action=''][method='post'][role='form']", [ + m("fieldset", [ + m("legend", "Environment"), + m(".form-group[id='systemstatus']", [ + m("label.control-label.col-sm-2", "Check system status"), + m(".col-sm-10", [ + m("a.btn.btn-default.btn-lg[data-toggle='modal'][href='#modal-sysinfo']", [m("i.fa.fa-info-circle.sx"), "show status"]), + m("span.help-block", "See information regarding the system and its status.") + ]) + ]), + m(".form-group[id='environment']", [ + m("label.control-label.col-sm-2[for='hostname']", "Player hostname"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][id='hostname'][name='hostname'][placeholder='runeaudio'][type='text'][value='a-cappella']"), + m("span.help-block", "Set the player hostname. This will change the address used to reach the RuneUI.") + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='ntpserver']", "NTP server"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][id='ntpserver'][name='ntpserver'][placeholder='pool.ntp.org'][type='text'][value='pool.ntp.org']"), + m("span.help-block", ["Set your reference time sync server ", m("i", "(NTP server)"), "."]) + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='timezone']", "Timezone"), + m(".col-sm-10", [ + m("select.selectpicker[data-style='btn-default btn-lg'][name='timezone']", { style: { "display": " none" } }, [ + m("option[value='Africa/Abidjan']", "\n Africa/Abidjan - GMT +00:00 "), + m("option[value='Africa/Accra']", "\n Africa/Accra - GMT +00:00 "), + m("option[value='Africa/Addis_Ababa']", "\n Africa/Addis_Ababa - GMT +03:00 "), + m("option[value='Africa/Algiers']", "\n Africa/Algiers - GMT +01:00 "), + m("option[value='Africa/Asmara']", "\n Africa/Asmara - GMT +03:00 "), + m("option[value='Africa/Bamako']", "\n Africa/Bamako - GMT +00:00 "), + m("option[value='Africa/Bangui']", "\n Africa/Bangui - GMT +01:00 "), + m("option[value='Africa/Banjul']", "\n Africa/Banjul - GMT +00:00 "), + m("option[value='Africa/Bissau']", "\n Africa/Bissau - GMT +00:00 "), + m("option[value='Africa/Blantyre']", "\n Africa/Blantyre - GMT +02:00 "), + m("option[value='Africa/Brazzaville']", "\n Africa/Brazzaville - GMT +01:00 "), + m("option[value='Africa/Bujumbura']", "\n Africa/Bujumbura - GMT +02:00 "), + m("option[value='Africa/Cairo']", "\n Africa/Cairo - GMT +02:00 "), + m("option[value='Africa/Casablanca']", "\n Africa/Casablanca - GMT +00:00 "), + m("option[value='Africa/Ceuta']", "\n Africa/Ceuta - GMT +01:00 "), + m("option[value='Africa/Conakry']", "\n Africa/Conakry - GMT +00:00 "), + m("option[value='Africa/Dakar']", "\n Africa/Dakar - GMT +00:00 "), + m("option[value='Africa/Dar_es_Salaam']", "\n Africa/Dar_es_Salaam - GMT +03:00 "), + m("option[value='Africa/Djibouti']", "\n Africa/Djibouti - GMT +03:00 "), + m("option[value='Africa/Douala']", "\n Africa/Douala - GMT +01:00 "), + m("option[value='Africa/El_Aaiun']", "\n Africa/El_Aaiun - GMT +00:00 "), + m("option[value='Africa/Freetown']", "\n Africa/Freetown - GMT +00:00 "), + m("option[value='Africa/Gaborone']", "\n Africa/Gaborone - GMT +02:00 "), + m("option[value='Africa/Harare']", "\n Africa/Harare - GMT +02:00 "), + m("option[value='Africa/Johannesburg']", "\n Africa/Johannesburg - GMT +02:00 "), + m("option[value='Africa/Juba']", "\n Africa/Juba - GMT +03:00 "), + m("option[value='Africa/Kampala']", "\n Africa/Kampala - GMT +03:00 "), + m("option[value='Africa/Khartoum']", "\n Africa/Khartoum - GMT +03:00 "), + m("option[value='Africa/Kigali']", "\n Africa/Kigali - GMT +02:00 "), + m("option[value='Africa/Kinshasa']", "\n Africa/Kinshasa - GMT +01:00 "), + m("option[value='Africa/Lagos']", "\n Africa/Lagos - GMT +01:00 "), + m("option[value='Africa/Libreville']", "\n Africa/Libreville - GMT +01:00 "), + m("option[value='Africa/Lome']", "\n Africa/Lome - GMT +00:00 "), + m("option[value='Africa/Luanda']", "\n Africa/Luanda - GMT +01:00 "), + m("option[value='Africa/Lubumbashi']", "\n Africa/Lubumbashi - GMT +02:00 "), + m("option[value='Africa/Lusaka']", "\n Africa/Lusaka - GMT +02:00 "), + m("option[value='Africa/Malabo']", "\n Africa/Malabo - GMT +01:00 "), + m("option[value='Africa/Maputo']", "\n Africa/Maputo - GMT +02:00 "), + m("option[value='Africa/Maseru']", "\n Africa/Maseru - GMT +02:00 "), + m("option[value='Africa/Mbabane']", "\n Africa/Mbabane - GMT +02:00 "), + m("option[value='Africa/Mogadishu']", "\n Africa/Mogadishu - GMT +03:00 "), + m("option[value='Africa/Monrovia']", "\n Africa/Monrovia - GMT +00:00 "), + m("option[value='Africa/Nairobi']", "\n Africa/Nairobi - GMT +03:00 "), + m("option[value='Africa/Ndjamena']", "\n Africa/Ndjamena - GMT +01:00 "), + m("option[value='Africa/Niamey']", "\n Africa/Niamey - GMT +01:00 "), + m("option[value='Africa/Nouakchott']", "\n Africa/Nouakchott - GMT +00:00 "), + m("option[value='Africa/Ouagadougou']", "\n Africa/Ouagadougou - GMT +00:00 "), + m("option[value='Africa/Porto-Novo']", "\n Africa/Porto-Novo - GMT +01:00 "), + m("option[value='Africa/Sao_Tome']", "\n Africa/Sao_Tome - GMT +00:00 "), + m("option[value='Africa/Tripoli']", "\n Africa/Tripoli - GMT +02:00 "), + m("option[value='Africa/Tunis']", "\n Africa/Tunis - GMT +01:00 "), + m("option[value='Africa/Windhoek']", "\n Africa/Windhoek - GMT +02:00 "), + m("option[value='America/Adak']", "\n America/Adak - GMT -10:00 "), + m("option[value='America/Anchorage']", "\n America/Anchorage - GMT -09:00 "), + m("option[value='America/Anguilla']", "\n America/Anguilla - GMT -04:00 "), + m("option[value='America/Antigua']", "\n America/Antigua - GMT -04:00 "), + m("option[value='America/Araguaina']", "\n America/Araguaina - GMT -03:00 "), + m("option[value='America/Argentina/Buenos_Aires']", "\n America/Argentina/Buenos_Aires - GMT -03:00 "), + m("option[value='America/Argentina/Catamarca']", "\n America/Argentina/Catamarca - GMT -03:00 "), + m("option[value='America/Argentina/Cordoba']", "\n America/Argentina/Cordoba - GMT -03:00 "), + m("option[value='America/Argentina/Jujuy']", "\n America/Argentina/Jujuy - GMT -03:00 "), + m("option[value='America/Argentina/La_Rioja']", "\n America/Argentina/La_Rioja - GMT -03:00 "), + m("option[value='America/Argentina/Mendoza']", "\n America/Argentina/Mendoza - GMT -03:00 "), + m("option[value='America/Argentina/Rio_Gallegos']", "\n America/Argentina/Rio_Gallegos - GMT -03:00 "), + m("option[value='America/Argentina/Salta']", "\n America/Argentina/Salta - GMT -03:00 "), + m("option[value='America/Argentina/San_Juan']", "\n America/Argentina/San_Juan - GMT -03:00 "), + m("option[value='America/Argentina/San_Luis']", "\n America/Argentina/San_Luis - GMT -03:00 "), + m("option[value='America/Argentina/Tucuman']", "\n America/Argentina/Tucuman - GMT -03:00 "), + m("option[value='America/Argentina/Ushuaia']", "\n America/Argentina/Ushuaia - GMT -03:00 "), + m("option[value='America/Aruba']", "\n America/Aruba - GMT -04:00 "), + m("option[value='America/Asuncion']", "\n America/Asuncion - GMT -03:00 "), + m("option[value='America/Atikokan']", "\n America/Atikokan - GMT -05:00 "), + m("option[value='America/Bahia']", "\n America/Bahia - GMT -03:00 "), + m("option[value='America/Bahia_Banderas']", "\n America/Bahia_Banderas - GMT -06:00 "), + m("option[value='America/Barbados']", "\n America/Barbados - GMT -04:00 "), + m("option[value='America/Belem']", "\n America/Belem - GMT -03:00 "), + m("option[value='America/Belize']", "\n America/Belize - GMT -06:00 "), + m("option[value='America/Blanc-Sablon']", "\n America/Blanc-Sablon - GMT -04:00 "), + m("option[value='America/Boa_Vista']", "\n America/Boa_Vista - GMT -04:00 "), + m("option[value='America/Bogota']", "\n America/Bogota - GMT -05:00 "), + m("option[value='America/Boise']", "\n America/Boise - GMT -07:00 "), + m("option[value='America/Cambridge_Bay']", "\n America/Cambridge_Bay - GMT -07:00 "), + m("option[value='America/Campo_Grande']", "\n America/Campo_Grande - GMT -03:00 "), + m("option[value='America/Cancun']", "\n America/Cancun - GMT -06:00 "), + m("option[value='America/Caracas']", "\n America/Caracas - GMT -04:30 "), + m("option[value='America/Cayenne']", "\n America/Cayenne - GMT -03:00 "), + m("option[value='America/Cayman']", "\n America/Cayman - GMT -05:00 "), + m("option[value='America/Chicago']", "\n America/Chicago - GMT -06:00 "), + m("option[value='America/Chihuahua']", "\n America/Chihuahua - GMT -07:00 "), + m("option[value='America/Costa_Rica']", "\n America/Costa_Rica - GMT -06:00 "), + m("option[value='America/Creston']", "\n America/Creston - GMT -07:00 "), + m("option[value='America/Cuiaba']", "\n America/Cuiaba - GMT -03:00 "), + m("option[value='America/Curacao']", "\n America/Curacao - GMT -04:00 "), + m("option[value='America/Danmarkshavn']", "\n America/Danmarkshavn - GMT +00:00 "), + m("option[value='America/Dawson']", "\n America/Dawson - GMT -08:00 "), + m("option[value='America/Dawson_Creek']", "\n America/Dawson_Creek - GMT -07:00 "), + m("option[value='America/Denver']", "\n America/Denver - GMT -07:00 "), + m("option[value='America/Detroit']", "\n America/Detroit - GMT -05:00 "), + m("option[value='America/Dominica']", "\n America/Dominica - GMT -04:00 "), + m("option[value='America/Edmonton']", "\n America/Edmonton - GMT -07:00 "), + m("option[value='America/Eirunepe']", "\n America/Eirunepe - GMT -05:00 "), + m("option[value='America/El_Salvador']", "\n America/El_Salvador - GMT -06:00 "), + m("option[value='America/Fortaleza']", "\n America/Fortaleza - GMT -03:00 "), + m("option[value='America/Glace_Bay']", "\n America/Glace_Bay - GMT -04:00 "), + m("option[value='America/Godthab']", "\n America/Godthab - GMT -03:00 "), + m("option[value='America/Goose_Bay']", "\n America/Goose_Bay - GMT -04:00 "), + m("option[value='America/Grand_Turk']", "\n America/Grand_Turk - GMT -04:00 "), + m("option[value='America/Grenada']", "\n America/Grenada - GMT -04:00 "), + m("option[value='America/Guadeloupe']", "\n America/Guadeloupe - GMT -04:00 "), + m("option[value='America/Guatemala']", "\n America/Guatemala - GMT -06:00 "), + m("option[value='America/Guayaquil']", "\n America/Guayaquil - GMT -05:00 "), + m("option[value='America/Guyana']", "\n America/Guyana - GMT -04:00 "), + m("option[value='America/Halifax']", "\n America/Halifax - GMT -04:00 "), + m("option[value='America/Havana']", "\n America/Havana - GMT -05:00 "), + m("option[value='America/Hermosillo']", "\n America/Hermosillo - GMT -07:00 "), + m("option[value='America/Indiana/Indianapolis']", "\n America/Indiana/Indianapolis - GMT -05:00 "), + m("option[value='America/Indiana/Knox']", "\n America/Indiana/Knox - GMT -06:00 "), + m("option[value='America/Indiana/Marengo']", "\n America/Indiana/Marengo - GMT -05:00 "), + m("option[value='America/Indiana/Petersburg']", "\n America/Indiana/Petersburg - GMT -05:00 "), + m("option[value='America/Indiana/Tell_City']", "\n America/Indiana/Tell_City - GMT -06:00 "), + m("option[value='America/Indiana/Vevay']", "\n America/Indiana/Vevay - GMT -05:00 "), + m("option[value='America/Indiana/Vincennes']", "\n America/Indiana/Vincennes - GMT -05:00 "), + m("option[value='America/Indiana/Winamac']", "\n America/Indiana/Winamac - GMT -05:00 "), + m("option[value='America/Inuvik']", "\n America/Inuvik - GMT -07:00 "), + m("option[value='America/Iqaluit']", "\n America/Iqaluit - GMT -05:00 "), + m("option[value='America/Jamaica']", "\n America/Jamaica - GMT -05:00 "), + m("option[value='America/Juneau']", "\n America/Juneau - GMT -09:00 "), + m("option[value='America/Kentucky/Louisville']", "\n America/Kentucky/Louisville - GMT -05:00 "), + m("option[value='America/Kentucky/Monticello']", "\n America/Kentucky/Monticello - GMT -05:00 "), + m("option[value='America/Kralendijk']", "\n America/Kralendijk - GMT -04:00 "), + m("option[value='America/La_Paz']", "\n America/La_Paz - GMT -04:00 "), + m("option[value='America/Lima']", "\n America/Lima - GMT -05:00 "), + m("option[value='America/Los_Angeles']", "\n America/Los_Angeles - GMT -08:00 "), + m("option[value='America/Lower_Princes']", "\n America/Lower_Princes - GMT -04:00 "), + m("option[value='America/Maceio']", "\n America/Maceio - GMT -03:00 "), + m("option[value='America/Managua']", "\n America/Managua - GMT -06:00 "), + m("option[value='America/Manaus']", "\n America/Manaus - GMT -04:00 "), + m("option[value='America/Marigot']", "\n America/Marigot - GMT -04:00 "), + m("option[value='America/Martinique']", "\n America/Martinique - GMT -04:00 "), + m("option[value='America/Matamoros']", "\n America/Matamoros - GMT -06:00 "), + m("option[value='America/Mazatlan']", "\n America/Mazatlan - GMT -07:00 "), + m("option[value='America/Menominee']", "\n America/Menominee - GMT -06:00 "), + m("option[value='America/Merida']", "\n America/Merida - GMT -06:00 "), + m("option[value='America/Metlakatla']", "\n America/Metlakatla - GMT -08:00 "), + m("option[value='America/Mexico_City']", "\n America/Mexico_City - GMT -06:00 "), + m("option[value='America/Miquelon']", "\n America/Miquelon - GMT -03:00 "), + m("option[value='America/Moncton']", "\n America/Moncton - GMT -04:00 "), + m("option[value='America/Monterrey']", "\n America/Monterrey - GMT -06:00 "), + m("option[value='America/Montevideo']", "\n America/Montevideo - GMT -02:00 "), + m("option[value='America/Montserrat']", "\n America/Montserrat - GMT -04:00 "), + m("option[value='America/Nassau']", "\n America/Nassau - GMT -05:00 "), + m("option[selected=''][value='America/New_York']", "\n America/New_York - GMT -05:00 "), + m("option[value='America/Nipigon']", "\n America/Nipigon - GMT -05:00 "), + m("option[value='America/Nome']", "\n America/Nome - GMT -09:00 "), + m("option[value='America/Noronha']", "\n America/Noronha - GMT -02:00 "), + m("option[value='America/North_Dakota/Beulah']", "\n America/North_Dakota/Beulah - GMT -06:00 "), + m("option[value='America/North_Dakota/Center']", "\n America/North_Dakota/Center - GMT -06:00 "), + m("option[value='America/North_Dakota/New_Salem']", "\n America/North_Dakota/New_Salem - GMT -06:00 "), + m("option[value='America/Ojinaga']", "\n America/Ojinaga - GMT -07:00 "), + m("option[value='America/Panama']", "\n America/Panama - GMT -05:00 "), + m("option[value='America/Pangnirtung']", "\n America/Pangnirtung - GMT -05:00 "), + m("option[value='America/Paramaribo']", "\n America/Paramaribo - GMT -03:00 "), + m("option[value='America/Phoenix']", "\n America/Phoenix - GMT -07:00 "), + m("option[value='America/Port-au-Prince']", "\n America/Port-au-Prince - GMT -05:00 "), + m("option[value='America/Port_of_Spain']", "\n America/Port_of_Spain - GMT -04:00 "), + m("option[value='America/Porto_Velho']", "\n America/Porto_Velho - GMT -04:00 "), + m("option[value='America/Puerto_Rico']", "\n America/Puerto_Rico - GMT -04:00 "), + m("option[value='America/Rainy_River']", "\n America/Rainy_River - GMT -06:00 "), + m("option[value='America/Rankin_Inlet']", "\n America/Rankin_Inlet - GMT -06:00 "), + m("option[value='America/Recife']", "\n America/Recife - GMT -03:00 "), + m("option[value='America/Regina']", "\n America/Regina - GMT -06:00 "), + m("option[value='America/Resolute']", "\n America/Resolute - GMT -06:00 "), + m("option[value='America/Rio_Branco']", "\n America/Rio_Branco - GMT -05:00 "), + m("option[value='America/Santa_Isabel']", "\n America/Santa_Isabel - GMT -08:00 "), + m("option[value='America/Santarem']", "\n America/Santarem - GMT -03:00 "), + m("option[value='America/Santiago']", "\n America/Santiago - GMT -03:00 "), + m("option[value='America/Santo_Domingo']", "\n America/Santo_Domingo - GMT -04:00 "), + m("option[value='America/Sao_Paulo']", "\n America/Sao_Paulo - GMT -02:00 "), + m("option[value='America/Scoresbysund']", "\n America/Scoresbysund - GMT -01:00 "), + m("option[value='America/Sitka']", "\n America/Sitka - GMT -09:00 "), + m("option[value='America/St_Barthelemy']", "\n America/St_Barthelemy - GMT -04:00 "), + m("option[value='America/St_Johns']", "\n America/St_Johns - GMT -03:30 "), + m("option[value='America/St_Kitts']", "\n America/St_Kitts - GMT -04:00 "), + m("option[value='America/St_Lucia']", "\n America/St_Lucia - GMT -04:00 "), + m("option[value='America/St_Thomas']", "\n America/St_Thomas - GMT -04:00 "), + m("option[value='America/St_Vincent']", "\n America/St_Vincent - GMT -04:00 "), + m("option[value='America/Swift_Current']", "\n America/Swift_Current - GMT -06:00 "), + m("option[value='America/Tegucigalpa']", "\n America/Tegucigalpa - GMT -06:00 "), + m("option[value='America/Thule']", "\n America/Thule - GMT -04:00 "), + m("option[value='America/Thunder_Bay']", "\n America/Thunder_Bay - GMT -05:00 "), + m("option[value='America/Tijuana']", "\n America/Tijuana - GMT -08:00 "), + m("option[value='America/Toronto']", "\n America/Toronto - GMT -05:00 "), + m("option[value='America/Tortola']", "\n America/Tortola - GMT -04:00 "), + m("option[value='America/Vancouver']", "\n America/Vancouver - GMT -08:00 "), + m("option[value='America/Whitehorse']", "\n America/Whitehorse - GMT -08:00 "), + m("option[value='America/Winnipeg']", "\n America/Winnipeg - GMT -06:00 "), + m("option[value='America/Yakutat']", "\n America/Yakutat - GMT -09:00 "), + m("option[value='America/Yellowknife']", "\n America/Yellowknife - GMT -07:00 "), + m("option[value='Antarctica/Casey']", "\n Antarctica/Casey - GMT +08:00 "), + m("option[value='Antarctica/Davis']", "\n Antarctica/Davis - GMT +07:00 "), + m("option[value='Antarctica/DumontDUrville']", "\n Antarctica/DumontDUrville - GMT +10:00 "), + m("option[value='Antarctica/Macquarie']", "\n Antarctica/Macquarie - GMT +11:00 "), + m("option[value='Antarctica/Mawson']", "\n Antarctica/Mawson - GMT +05:00 "), + m("option[value='Antarctica/McMurdo']", "\n Antarctica/McMurdo - GMT +13:00 "), + m("option[value='Antarctica/Palmer']", "\n Antarctica/Palmer - GMT -03:00 "), + m("option[value='Antarctica/Rothera']", "\n Antarctica/Rothera - GMT -03:00 "), + m("option[value='Antarctica/Syowa']", "\n Antarctica/Syowa - GMT +03:00 "), + m("option[value='Antarctica/Troll']", "\n Antarctica/Troll - GMT +00:00 "), + m("option[value='Antarctica/Vostok']", "\n Antarctica/Vostok - GMT +06:00 "), + m("option[value='Arctic/Longyearbyen']", "\n Arctic/Longyearbyen - GMT +01:00 "), + m("option[value='Asia/Aden']", "\n Asia/Aden - GMT +03:00 "), + m("option[value='Asia/Almaty']", "\n Asia/Almaty - GMT +06:00 "), + m("option[value='Asia/Amman']", "\n Asia/Amman - GMT +02:00 "), + m("option[value='Asia/Anadyr']", "\n Asia/Anadyr - GMT +12:00 "), + m("option[value='Asia/Aqtau']", "\n Asia/Aqtau - GMT +05:00 "), + m("option[value='Asia/Aqtobe']", "\n Asia/Aqtobe - GMT +05:00 "), + m("option[value='Asia/Ashgabat']", "\n Asia/Ashgabat - GMT +05:00 "), + m("option[value='Asia/Baghdad']", "\n Asia/Baghdad - GMT +03:00 "), + m("option[value='Asia/Bahrain']", "\n Asia/Bahrain - GMT +03:00 "), + m("option[value='Asia/Baku']", "\n Asia/Baku - GMT +04:00 "), + m("option[value='Asia/Bangkok']", "\n Asia/Bangkok - GMT +07:00 "), + m("option[value='Asia/Beirut']", "\n Asia/Beirut - GMT +02:00 "), + m("option[value='Asia/Bishkek']", "\n Asia/Bishkek - GMT +06:00 "), + m("option[value='Asia/Brunei']", "\n Asia/Brunei - GMT +08:00 "), + m("option[value='Asia/Chita']", "\n Asia/Chita - GMT +08:00 "), + m("option[value='Asia/Choibalsan']", "\n Asia/Choibalsan - GMT +08:00 "), + m("option[value='Asia/Colombo']", "\n Asia/Colombo - GMT +05:30 "), + m("option[value='Asia/Damascus']", "\n Asia/Damascus - GMT +02:00 "), + m("option[value='Asia/Dhaka']", "\n Asia/Dhaka - GMT +06:00 "), + m("option[value='Asia/Dili']", "\n Asia/Dili - GMT +09:00 "), + m("option[value='Asia/Dubai']", "\n Asia/Dubai - GMT +04:00 "), + m("option[value='Asia/Dushanbe']", "\n Asia/Dushanbe - GMT +05:00 "), + m("option[value='Asia/Gaza']", "\n Asia/Gaza - GMT +02:00 "), + m("option[value='Asia/Hebron']", "\n Asia/Hebron - GMT +02:00 "), + m("option[value='Asia/Ho_Chi_Minh']", "\n Asia/Ho_Chi_Minh - GMT +07:00 "), + m("option[value='Asia/Hong_Kong']", "\n Asia/Hong_Kong - GMT +08:00 "), + m("option[value='Asia/Hovd']", "\n Asia/Hovd - GMT +07:00 "), + m("option[value='Asia/Irkutsk']", "\n Asia/Irkutsk - GMT +08:00 "), + m("option[value='Asia/Jakarta']", "\n Asia/Jakarta - GMT +07:00 "), + m("option[value='Asia/Jayapura']", "\n Asia/Jayapura - GMT +09:00 "), + m("option[value='Asia/Jerusalem']", "\n Asia/Jerusalem - GMT +02:00 "), + m("option[value='Asia/Kabul']", "\n Asia/Kabul - GMT +04:30 "), + m("option[value='Asia/Kamchatka']", "\n Asia/Kamchatka - GMT +12:00 "), + m("option[value='Asia/Karachi']", "\n Asia/Karachi - GMT +05:00 "), + m("option[value='Asia/Kathmandu']", "\n Asia/Kathmandu - GMT +05:45 "), + m("option[value='Asia/Khandyga']", "\n Asia/Khandyga - GMT +09:00 "), + m("option[value='Asia/Kolkata']", "\n Asia/Kolkata - GMT +05:30 "), + m("option[value='Asia/Krasnoyarsk']", "\n Asia/Krasnoyarsk - GMT +07:00 "), + m("option[value='Asia/Kuala_Lumpur']", "\n Asia/Kuala_Lumpur - GMT +08:00 "), + m("option[value='Asia/Kuching']", "\n Asia/Kuching - GMT +08:00 "), + m("option[value='Asia/Kuwait']", "\n Asia/Kuwait - GMT +03:00 "), + m("option[value='Asia/Macau']", "\n Asia/Macau - GMT +08:00 "), + m("option[value='Asia/Magadan']", "\n Asia/Magadan - GMT +10:00 "), + m("option[value='Asia/Makassar']", "\n Asia/Makassar - GMT +08:00 "), + m("option[value='Asia/Manila']", "\n Asia/Manila - GMT +08:00 "), + m("option[value='Asia/Muscat']", "\n Asia/Muscat - GMT +04:00 "), + m("option[value='Asia/Nicosia']", "\n Asia/Nicosia - GMT +02:00 "), + m("option[value='Asia/Novokuznetsk']", "\n Asia/Novokuznetsk - GMT +07:00 "), + m("option[value='Asia/Novosibirsk']", "\n Asia/Novosibirsk - GMT +06:00 "), + m("option[value='Asia/Omsk']", "\n Asia/Omsk - GMT +06:00 "), + m("option[value='Asia/Oral']", "\n Asia/Oral - GMT +05:00 "), + m("option[value='Asia/Phnom_Penh']", "\n Asia/Phnom_Penh - GMT +07:00 "), + m("option[value='Asia/Pontianak']", "\n Asia/Pontianak - GMT +07:00 "), + m("option[value='Asia/Pyongyang']", "\n Asia/Pyongyang - GMT +09:00 "), + m("option[value='Asia/Qatar']", "\n Asia/Qatar - GMT +03:00 "), + m("option[value='Asia/Qyzylorda']", "\n Asia/Qyzylorda - GMT +06:00 "), + m("option[value='Asia/Rangoon']", "\n Asia/Rangoon - GMT +06:30 "), + m("option[value='Asia/Riyadh']", "\n Asia/Riyadh - GMT +03:00 "), + m("option[value='Asia/Sakhalin']", "\n Asia/Sakhalin - GMT +10:00 "), + m("option[value='Asia/Samarkand']", "\n Asia/Samarkand - GMT +05:00 "), + m("option[value='Asia/Seoul']", "\n Asia/Seoul - GMT +09:00 "), + m("option[value='Asia/Shanghai']", "\n Asia/Shanghai - GMT +08:00 "), + m("option[value='Asia/Singapore']", "\n Asia/Singapore - GMT +08:00 "), + m("option[value='Asia/Srednekolymsk']", "\n Asia/Srednekolymsk - GMT +11:00 "), + m("option[value='Asia/Taipei']", "\n Asia/Taipei - GMT +08:00 "), + m("option[value='Asia/Tashkent']", "\n Asia/Tashkent - GMT +05:00 "), + m("option[value='Asia/Tbilisi']", "\n Asia/Tbilisi - GMT +04:00 "), + m("option[value='Asia/Tehran']", "\n Asia/Tehran - GMT +03:30 "), + m("option[value='Asia/Thimphu']", "\n Asia/Thimphu - GMT +06:00 "), + m("option[value='Asia/Tokyo']", "\n Asia/Tokyo - GMT +09:00 "), + m("option[value='Asia/Ulaanbaatar']", "\n Asia/Ulaanbaatar - GMT +08:00 "), + m("option[value='Asia/Urumqi']", "\n Asia/Urumqi - GMT +06:00 "), + m("option[value='Asia/Ust-Nera']", "\n Asia/Ust-Nera - GMT +10:00 "), + m("option[value='Asia/Vientiane']", "\n Asia/Vientiane - GMT +07:00 "), + m("option[value='Asia/Vladivostok']", "\n Asia/Vladivostok - GMT +10:00 "), + m("option[value='Asia/Yakutsk']", "\n Asia/Yakutsk - GMT +09:00 "), + m("option[value='Asia/Yekaterinburg']", "\n Asia/Yekaterinburg - GMT +05:00 "), + m("option[value='Asia/Yerevan']", "\n Asia/Yerevan - GMT +04:00 "), + m("option[value='Atlantic/Azores']", "\n Atlantic/Azores - GMT -01:00 "), + m("option[value='Atlantic/Bermuda']", "\n Atlantic/Bermuda - GMT -04:00 "), + m("option[value='Atlantic/Canary']", "\n Atlantic/Canary - GMT +00:00 "), + m("option[value='Atlantic/Cape_Verde']", "\n Atlantic/Cape_Verde - GMT -01:00 "), + m("option[value='Atlantic/Faroe']", "\n Atlantic/Faroe - GMT +00:00 "), + m("option[value='Atlantic/Madeira']", "\n Atlantic/Madeira - GMT +00:00 "), + m("option[value='Atlantic/Reykjavik']", "\n Atlantic/Reykjavik - GMT +00:00 "), + m("option[value='Atlantic/South_Georgia']", "\n Atlantic/South_Georgia - GMT -02:00 "), + m("option[value='Atlantic/St_Helena']", "\n Atlantic/St_Helena - GMT +00:00 "), + m("option[value='Atlantic/Stanley']", "\n Atlantic/Stanley - GMT -03:00 "), + m("option[value='Australia/Adelaide']", "\n Australia/Adelaide - GMT +10:30 "), + m("option[value='Australia/Brisbane']", "\n Australia/Brisbane - GMT +10:00 "), + m("option[value='Australia/Broken_Hill']", "\n Australia/Broken_Hill - GMT +10:30 "), + m("option[value='Australia/Currie']", "\n Australia/Currie - GMT +11:00 "), + m("option[value='Australia/Darwin']", "\n Australia/Darwin - GMT +09:30 "), + m("option[value='Australia/Eucla']", "\n Australia/Eucla - GMT +08:45 "), + m("option[value='Australia/Hobart']", "\n Australia/Hobart - GMT +11:00 "), + m("option[value='Australia/Lindeman']", "\n Australia/Lindeman - GMT +10:00 "), + m("option[value='Australia/Lord_Howe']", "\n Australia/Lord_Howe - GMT +11:00 "), + m("option[value='Australia/Melbourne']", "\n Australia/Melbourne - GMT +11:00 "), + m("option[value='Australia/Perth']", "\n Australia/Perth - GMT +08:00 "), + m("option[value='Australia/Sydney']", "\n Australia/Sydney - GMT +11:00 "), + m("option[value='Europe/Amsterdam']", "\n Europe/Amsterdam - GMT +01:00 "), + m("option[value='Europe/Andorra']", "\n Europe/Andorra - GMT +01:00 "), + m("option[value='Europe/Athens']", "\n Europe/Athens - GMT +02:00 "), + m("option[value='Europe/Belgrade']", "\n Europe/Belgrade - GMT +01:00 "), + m("option[value='Europe/Berlin']", "\n Europe/Berlin - GMT +01:00 "), + m("option[value='Europe/Bratislava']", "\n Europe/Bratislava - GMT +01:00 "), + m("option[value='Europe/Brussels']", "\n Europe/Brussels - GMT +01:00 "), + m("option[value='Europe/Bucharest']", "\n Europe/Bucharest - GMT +02:00 "), + m("option[value='Europe/Budapest']", "\n Europe/Budapest - GMT +01:00 "), + m("option[value='Europe/Busingen']", "\n Europe/Busingen - GMT +01:00 "), + m("option[value='Europe/Chisinau']", "\n Europe/Chisinau - GMT +02:00 "), + m("option[value='Europe/Copenhagen']", "\n Europe/Copenhagen - GMT +01:00 "), + m("option[value='Europe/Dublin']", "\n Europe/Dublin - GMT +00:00 "), + m("option[value='Europe/Gibraltar']", "\n Europe/Gibraltar - GMT +01:00 "), + m("option[value='Europe/Guernsey']", "\n Europe/Guernsey - GMT +00:00 "), + m("option[value='Europe/Helsinki']", "\n Europe/Helsinki - GMT +02:00 "), + m("option[value='Europe/Isle_of_Man']", "\n Europe/Isle_of_Man - GMT +00:00 "), + m("option[value='Europe/Istanbul']", "\n Europe/Istanbul - GMT +02:00 "), + m("option[value='Europe/Jersey']", "\n Europe/Jersey - GMT +00:00 "), + m("option[value='Europe/Kaliningrad']", "\n Europe/Kaliningrad - GMT +02:00 "), + m("option[value='Europe/Kiev']", "\n Europe/Kiev - GMT +02:00 "), + m("option[value='Europe/Lisbon']", "\n Europe/Lisbon - GMT +00:00 "), + m("option[value='Europe/Ljubljana']", "\n Europe/Ljubljana - GMT +01:00 "), + m("option[value='Europe/London']", "\n Europe/London - GMT +00:00 "), + m("option[value='Europe/Luxembourg']", "\n Europe/Luxembourg - GMT +01:00 "), + m("option[value='Europe/Madrid']", "\n Europe/Madrid - GMT +01:00 "), + m("option[value='Europe/Malta']", "\n Europe/Malta - GMT +01:00 "), + m("option[value='Europe/Mariehamn']", "\n Europe/Mariehamn - GMT +02:00 "), + m("option[value='Europe/Minsk']", "\n Europe/Minsk - GMT +03:00 "), + m("option[value='Europe/Monaco']", "\n Europe/Monaco - GMT +01:00 "), + m("option[value='Europe/Moscow']", "\n Europe/Moscow - GMT +03:00 "), + m("option[value='Europe/Oslo']", "\n Europe/Oslo - GMT +01:00 "), + m("option[value='Europe/Paris']", "\n Europe/Paris - GMT +01:00 "), + m("option[value='Europe/Podgorica']", "\n Europe/Podgorica - GMT +01:00 "), + m("option[value='Europe/Prague']", "\n Europe/Prague - GMT +01:00 "), + m("option[value='Europe/Riga']", "\n Europe/Riga - GMT +02:00 "), + m("option[value='Europe/Rome']", "\n Europe/Rome - GMT +01:00 "), + m("option[value='Europe/Samara']", "\n Europe/Samara - GMT +04:00 "), + m("option[value='Europe/San_Marino']", "\n Europe/San_Marino - GMT +01:00 "), + m("option[value='Europe/Sarajevo']", "\n Europe/Sarajevo - GMT +01:00 "), + m("option[value='Europe/Simferopol']", "\n Europe/Simferopol - GMT +03:00 "), + m("option[value='Europe/Skopje']", "\n Europe/Skopje - GMT +01:00 "), + m("option[value='Europe/Sofia']", "\n Europe/Sofia - GMT +02:00 "), + m("option[value='Europe/Stockholm']", "\n Europe/Stockholm - GMT +01:00 "), + m("option[value='Europe/Tallinn']", "\n Europe/Tallinn - GMT +02:00 "), + m("option[value='Europe/Tirane']", "\n Europe/Tirane - GMT +01:00 "), + m("option[value='Europe/Uzhgorod']", "\n Europe/Uzhgorod - GMT +02:00 "), + m("option[value='Europe/Vaduz']", "\n Europe/Vaduz - GMT +01:00 "), + m("option[value='Europe/Vatican']", "\n Europe/Vatican - GMT +01:00 "), + m("option[value='Europe/Vienna']", "\n Europe/Vienna - GMT +01:00 "), + m("option[value='Europe/Vilnius']", "\n Europe/Vilnius - GMT +02:00 "), + m("option[value='Europe/Volgograd']", "\n Europe/Volgograd - GMT +03:00 "), + m("option[value='Europe/Warsaw']", "\n Europe/Warsaw - GMT +01:00 "), + m("option[value='Europe/Zagreb']", "\n Europe/Zagreb - GMT +01:00 "), + m("option[value='Europe/Zaporozhye']", "\n Europe/Zaporozhye - GMT +02:00 "), + m("option[value='Europe/Zurich']", "\n Europe/Zurich - GMT +01:00 "), + m("option[value='Indian/Antananarivo']", "\n Indian/Antananarivo - GMT +03:00 "), + m("option[value='Indian/Chagos']", "\n Indian/Chagos - GMT +06:00 "), + m("option[value='Indian/Christmas']", "\n Indian/Christmas - GMT +07:00 "), + m("option[value='Indian/Cocos']", "\n Indian/Cocos - GMT +06:30 "), + m("option[value='Indian/Comoro']", "\n Indian/Comoro - GMT +03:00 "), + m("option[value='Indian/Kerguelen']", "\n Indian/Kerguelen - GMT +05:00 "), + m("option[value='Indian/Mahe']", "\n Indian/Mahe - GMT +04:00 "), + m("option[value='Indian/Maldives']", "\n Indian/Maldives - GMT +05:00 "), + m("option[value='Indian/Mauritius']", "\n Indian/Mauritius - GMT +04:00 "), + m("option[value='Indian/Mayotte']", "\n Indian/Mayotte - GMT +03:00 "), + m("option[value='Indian/Reunion']", "\n Indian/Reunion - GMT +04:00 "), + m("option[value='Pacific/Apia']", "\n Pacific/Apia - GMT +14:00 "), + m("option[value='Pacific/Auckland']", "\n Pacific/Auckland - GMT +13:00 "), + m("option[value='Pacific/Chatham']", "\n Pacific/Chatham - GMT +13:45 "), + m("option[value='Pacific/Chuuk']", "\n Pacific/Chuuk - GMT +10:00 "), + m("option[value='Pacific/Easter']", "\n Pacific/Easter - GMT -05:00 "), + m("option[value='Pacific/Efate']", "\n Pacific/Efate - GMT +11:00 "), + m("option[value='Pacific/Enderbury']", "\n Pacific/Enderbury - GMT +13:00 "), + m("option[value='Pacific/Fakaofo']", "\n Pacific/Fakaofo - GMT +13:00 "), + m("option[value='Pacific/Fiji']", "\n Pacific/Fiji - GMT +13:00 "), + m("option[value='Pacific/Funafuti']", "\n Pacific/Funafuti - GMT +12:00 "), + m("option[value='Pacific/Galapagos']", "\n Pacific/Galapagos - GMT -06:00 "), + m("option[value='Pacific/Gambier']", "\n Pacific/Gambier - GMT -09:00 "), + m("option[value='Pacific/Guadalcanal']", "\n Pacific/Guadalcanal - GMT +11:00 "), + m("option[value='Pacific/Guam']", "\n Pacific/Guam - GMT +10:00 "), + m("option[value='Pacific/Honolulu']", "\n Pacific/Honolulu - GMT -10:00 "), + m("option[value='Pacific/Johnston']", "\n Pacific/Johnston - GMT -10:00 "), + m("option[value='Pacific/Kiritimati']", "\n Pacific/Kiritimati - GMT +14:00 "), + m("option[value='Pacific/Kosrae']", "\n Pacific/Kosrae - GMT +11:00 "), + m("option[value='Pacific/Kwajalein']", "\n Pacific/Kwajalein - GMT +12:00 "), + m("option[value='Pacific/Majuro']", "\n Pacific/Majuro - GMT +12:00 "), + m("option[value='Pacific/Marquesas']", "\n Pacific/Marquesas - GMT -09:30 "), + m("option[value='Pacific/Midway']", "\n Pacific/Midway - GMT -11:00 "), + m("option[value='Pacific/Nauru']", "\n Pacific/Nauru - GMT +12:00 "), + m("option[value='Pacific/Niue']", "\n Pacific/Niue - GMT -11:00 "), + m("option[value='Pacific/Norfolk']", "\n Pacific/Norfolk - GMT +11:30 "), + m("option[value='Pacific/Noumea']", "\n Pacific/Noumea - GMT +11:00 "), + m("option[value='Pacific/Pago_Pago']", "\n Pacific/Pago_Pago - GMT -11:00 "), + m("option[value='Pacific/Palau']", "\n Pacific/Palau - GMT +09:00 "), + m("option[value='Pacific/Pitcairn']", "\n Pacific/Pitcairn - GMT -08:00 "), + m("option[value='Pacific/Pohnpei']", "\n Pacific/Pohnpei - GMT +11:00 "), + m("option[value='Pacific/Port_Moresby']", "\n Pacific/Port_Moresby - GMT +10:00 "), + m("option[value='Pacific/Rarotonga']", "\n Pacific/Rarotonga - GMT -10:00 "), + m("option[value='Pacific/Saipan']", "\n Pacific/Saipan - GMT +10:00 "), + m("option[value='Pacific/Tahiti']", "\n Pacific/Tahiti - GMT -10:00 "), + m("option[value='Pacific/Tarawa']", "\n Pacific/Tarawa - GMT +12:00 "), + m("option[value='Pacific/Tongatapu']", "\n Pacific/Tongatapu - GMT +13:00 "), + m("option[value='Pacific/Wake']", "\n Pacific/Wake - GMT +12:00 "), + m("option[value='Pacific/Wallis']", "\n Pacific/Wallis - GMT +12:00 "), + m("option[value='UTC']", "\n UTC - GMT +00:00 ") + ]), + m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='America/New_York - GMT -05:00'][type='button']", [m("span.filter-option.pull-left", "\n America/New_York - GMT -05:00 "), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Abidjan - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Accra - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Addis_Ababa - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Algiers - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Asmara - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bamako - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bangui - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Banjul - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='8']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bissau - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='9']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Blantyre - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='10']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Brazzaville - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='11']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Bujumbura - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='12']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Cairo - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='13']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Casablanca - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='14']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ceuta - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='15']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Conakry - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='16']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Dakar - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='17']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Dar_es_Salaam - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='18']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Djibouti - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='19']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Douala - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='20']", [m("a[tabindex='0']", [m("span.text", "\n Africa/El_Aaiun - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='21']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Freetown - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='22']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Gaborone - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='23']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Harare - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='24']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Johannesburg - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='25']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Juba - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='26']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kampala - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='27']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Khartoum - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='28']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kigali - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='29']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Kinshasa - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='30']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lagos - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='31']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Libreville - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='32']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lome - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='33']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Luanda - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='34']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lubumbashi - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='35']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Lusaka - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='36']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Malabo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='37']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Maputo - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='38']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Maseru - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='39']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Mbabane - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='40']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Mogadishu - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='41']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Monrovia - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='42']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Nairobi - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='43']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ndjamena - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='44']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Niamey - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='45']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Nouakchott - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='46']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Ouagadougou - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='47']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Porto-Novo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='48']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Sao_Tome - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='49']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Tripoli - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='50']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Tunis - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='51']", [m("a[tabindex='0']", [m("span.text", "\n Africa/Windhoek - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='52']", [m("a[tabindex='0']", [m("span.text", "\n America/Adak - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='53']", [m("a[tabindex='0']", [m("span.text", "\n America/Anchorage - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='54']", [m("a[tabindex='0']", [m("span.text", "\n America/Anguilla - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='55']", [m("a[tabindex='0']", [m("span.text", "\n America/Antigua - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='56']", [m("a[tabindex='0']", [m("span.text", "\n America/Araguaina - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='57']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Buenos_Aires - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='58']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Catamarca - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='59']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Cordoba - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='60']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Jujuy - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='61']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/La_Rioja - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='62']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Mendoza - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='63']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Rio_Gallegos - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='64']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Salta - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='65']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/San_Juan - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='66']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/San_Luis - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='67']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Tucuman - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='68']", [m("a[tabindex='0']", [m("span.text", "\n America/Argentina/Ushuaia - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='69']", [m("a[tabindex='0']", [m("span.text", "\n America/Aruba - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='70']", [m("a[tabindex='0']", [m("span.text", "\n America/Asuncion - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='71']", [m("a[tabindex='0']", [m("span.text", "\n America/Atikokan - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='72']", [m("a[tabindex='0']", [m("span.text", "\n America/Bahia - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='73']", [m("a[tabindex='0']", [m("span.text", "\n America/Bahia_Banderas - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='74']", [m("a[tabindex='0']", [m("span.text", "\n America/Barbados - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='75']", [m("a[tabindex='0']", [m("span.text", "\n America/Belem - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='76']", [m("a[tabindex='0']", [m("span.text", "\n America/Belize - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='77']", [m("a[tabindex='0']", [m("span.text", "\n America/Blanc-Sablon - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='78']", [m("a[tabindex='0']", [m("span.text", "\n America/Boa_Vista - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='79']", [m("a[tabindex='0']", [m("span.text", "\n America/Bogota - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='80']", [m("a[tabindex='0']", [m("span.text", "\n America/Boise - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='81']", [m("a[tabindex='0']", [m("span.text", "\n America/Cambridge_Bay - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='82']", [m("a[tabindex='0']", [m("span.text", "\n America/Campo_Grande - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='83']", [m("a[tabindex='0']", [m("span.text", "\n America/Cancun - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='84']", [m("a[tabindex='0']", [m("span.text", "\n America/Caracas - GMT -04:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='85']", [m("a[tabindex='0']", [m("span.text", "\n America/Cayenne - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='86']", [m("a[tabindex='0']", [m("span.text", "\n America/Cayman - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='87']", [m("a[tabindex='0']", [m("span.text", "\n America/Chicago - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='88']", [m("a[tabindex='0']", [m("span.text", "\n America/Chihuahua - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='89']", [m("a[tabindex='0']", [m("span.text", "\n America/Costa_Rica - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='90']", [m("a[tabindex='0']", [m("span.text", "\n America/Creston - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='91']", [m("a[tabindex='0']", [m("span.text", "\n America/Cuiaba - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='92']", [m("a[tabindex='0']", [m("span.text", "\n America/Curacao - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='93']", [m("a[tabindex='0']", [m("span.text", "\n America/Danmarkshavn - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='94']", [m("a[tabindex='0']", [m("span.text", "\n America/Dawson - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='95']", [m("a[tabindex='0']", [m("span.text", "\n America/Dawson_Creek - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='96']", [m("a[tabindex='0']", [m("span.text", "\n America/Denver - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='97']", [m("a[tabindex='0']", [m("span.text", "\n America/Detroit - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='98']", [m("a[tabindex='0']", [m("span.text", "\n America/Dominica - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='99']", [m("a[tabindex='0']", [m("span.text", "\n America/Edmonton - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='100']", [m("a[tabindex='0']", [m("span.text", "\n America/Eirunepe - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='101']", [m("a[tabindex='0']", [m("span.text", "\n America/El_Salvador - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='102']", [m("a[tabindex='0']", [m("span.text", "\n America/Fortaleza - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='103']", [m("a[tabindex='0']", [m("span.text", "\n America/Glace_Bay - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='104']", [m("a[tabindex='0']", [m("span.text", "\n America/Godthab - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='105']", [m("a[tabindex='0']", [m("span.text", "\n America/Goose_Bay - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='106']", [m("a[tabindex='0']", [m("span.text", "\n America/Grand_Turk - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='107']", [m("a[tabindex='0']", [m("span.text", "\n America/Grenada - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='108']", [m("a[tabindex='0']", [m("span.text", "\n America/Guadeloupe - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='109']", [m("a[tabindex='0']", [m("span.text", "\n America/Guatemala - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='110']", [m("a[tabindex='0']", [m("span.text", "\n America/Guayaquil - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='111']", [m("a[tabindex='0']", [m("span.text", "\n America/Guyana - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='112']", [m("a[tabindex='0']", [m("span.text", "\n America/Halifax - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='113']", [m("a[tabindex='0']", [m("span.text", "\n America/Havana - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='114']", [m("a[tabindex='0']", [m("span.text", "\n America/Hermosillo - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='115']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Indianapolis - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='116']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Knox - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='117']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Marengo - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='118']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Petersburg - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='119']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Tell_City - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='120']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Vevay - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='121']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Vincennes - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='122']", [m("a[tabindex='0']", [m("span.text", "\n America/Indiana/Winamac - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='123']", [m("a[tabindex='0']", [m("span.text", "\n America/Inuvik - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='124']", [m("a[tabindex='0']", [m("span.text", "\n America/Iqaluit - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='125']", [m("a[tabindex='0']", [m("span.text", "\n America/Jamaica - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='126']", [m("a[tabindex='0']", [m("span.text", "\n America/Juneau - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='127']", [m("a[tabindex='0']", [m("span.text", "\n America/Kentucky/Louisville - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='128']", [m("a[tabindex='0']", [m("span.text", "\n America/Kentucky/Monticello - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='129']", [m("a[tabindex='0']", [m("span.text", "\n America/Kralendijk - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='130']", [m("a[tabindex='0']", [m("span.text", "\n America/La_Paz - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='131']", [m("a[tabindex='0']", [m("span.text", "\n America/Lima - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='132']", [m("a[tabindex='0']", [m("span.text", "\n America/Los_Angeles - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='133']", [m("a[tabindex='0']", [m("span.text", "\n America/Lower_Princes - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='134']", [m("a[tabindex='0']", [m("span.text", "\n America/Maceio - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='135']", [m("a[tabindex='0']", [m("span.text", "\n America/Managua - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='136']", [m("a[tabindex='0']", [m("span.text", "\n America/Manaus - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='137']", [m("a[tabindex='0']", [m("span.text", "\n America/Marigot - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='138']", [m("a[tabindex='0']", [m("span.text", "\n America/Martinique - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='139']", [m("a[tabindex='0']", [m("span.text", "\n America/Matamoros - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='140']", [m("a[tabindex='0']", [m("span.text", "\n America/Mazatlan - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='141']", [m("a[tabindex='0']", [m("span.text", "\n America/Menominee - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='142']", [m("a[tabindex='0']", [m("span.text", "\n America/Merida - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='143']", [m("a[tabindex='0']", [m("span.text", "\n America/Metlakatla - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='144']", [m("a[tabindex='0']", [m("span.text", "\n America/Mexico_City - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='145']", [m("a[tabindex='0']", [m("span.text", "\n America/Miquelon - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='146']", [m("a[tabindex='0']", [m("span.text", "\n America/Moncton - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='147']", [m("a[tabindex='0']", [m("span.text", "\n America/Monterrey - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='148']", [m("a[tabindex='0']", [m("span.text", "\n America/Montevideo - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='149']", [m("a[tabindex='0']", [m("span.text", "\n America/Montserrat - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='150']", [m("a[tabindex='0']", [m("span.text", "\n America/Nassau - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='151']", [m("a[tabindex='0']", [m("span.text", "\n America/New_York - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='152']", [m("a[tabindex='0']", [m("span.text", "\n America/Nipigon - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='153']", [m("a[tabindex='0']", [m("span.text", "\n America/Nome - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='154']", [m("a[tabindex='0']", [m("span.text", "\n America/Noronha - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='155']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/Beulah - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='156']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/Center - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='157']", [m("a[tabindex='0']", [m("span.text", "\n America/North_Dakota/New_Salem - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='158']", [m("a[tabindex='0']", [m("span.text", "\n America/Ojinaga - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='159']", [m("a[tabindex='0']", [m("span.text", "\n America/Panama - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='160']", [m("a[tabindex='0']", [m("span.text", "\n America/Pangnirtung - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='161']", [m("a[tabindex='0']", [m("span.text", "\n America/Paramaribo - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='162']", [m("a[tabindex='0']", [m("span.text", "\n America/Phoenix - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='163']", [m("a[tabindex='0']", [m("span.text", "\n America/Port-au-Prince - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='164']", [m("a[tabindex='0']", [m("span.text", "\n America/Port_of_Spain - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='165']", [m("a[tabindex='0']", [m("span.text", "\n America/Porto_Velho - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='166']", [m("a[tabindex='0']", [m("span.text", "\n America/Puerto_Rico - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='167']", [m("a[tabindex='0']", [m("span.text", "\n America/Rainy_River - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='168']", [m("a[tabindex='0']", [m("span.text", "\n America/Rankin_Inlet - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='169']", [m("a[tabindex='0']", [m("span.text", "\n America/Recife - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='170']", [m("a[tabindex='0']", [m("span.text", "\n America/Regina - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='171']", [m("a[tabindex='0']", [m("span.text", "\n America/Resolute - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='172']", [m("a[tabindex='0']", [m("span.text", "\n America/Rio_Branco - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='173']", [m("a[tabindex='0']", [m("span.text", "\n America/Santa_Isabel - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='174']", [m("a[tabindex='0']", [m("span.text", "\n America/Santarem - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='175']", [m("a[tabindex='0']", [m("span.text", "\n America/Santiago - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='176']", [m("a[tabindex='0']", [m("span.text", "\n America/Santo_Domingo - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='177']", [m("a[tabindex='0']", [m("span.text", "\n America/Sao_Paulo - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='178']", [m("a[tabindex='0']", [m("span.text", "\n America/Scoresbysund - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='179']", [m("a[tabindex='0']", [m("span.text", "\n America/Sitka - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='180']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Barthelemy - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='181']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Johns - GMT -03:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='182']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Kitts - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='183']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Lucia - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='184']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Thomas - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='185']", [m("a[tabindex='0']", [m("span.text", "\n America/St_Vincent - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='186']", [m("a[tabindex='0']", [m("span.text", "\n America/Swift_Current - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='187']", [m("a[tabindex='0']", [m("span.text", "\n America/Tegucigalpa - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='188']", [m("a[tabindex='0']", [m("span.text", "\n America/Thule - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='189']", [m("a[tabindex='0']", [m("span.text", "\n America/Thunder_Bay - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='190']", [m("a[tabindex='0']", [m("span.text", "\n America/Tijuana - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='191']", [m("a[tabindex='0']", [m("span.text", "\n America/Toronto - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='192']", [m("a[tabindex='0']", [m("span.text", "\n America/Tortola - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='193']", [m("a[tabindex='0']", [m("span.text", "\n America/Vancouver - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='194']", [m("a[tabindex='0']", [m("span.text", "\n America/Whitehorse - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='195']", [m("a[tabindex='0']", [m("span.text", "\n America/Winnipeg - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='196']", [m("a[tabindex='0']", [m("span.text", "\n America/Yakutat - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='197']", [m("a[tabindex='0']", [m("span.text", "\n America/Yellowknife - GMT -07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='198']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Casey - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='199']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Davis - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='200']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/DumontDUrville - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='201']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Macquarie - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='202']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Mawson - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='203']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/McMurdo - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='204']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Palmer - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='205']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Rothera - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='206']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Syowa - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='207']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Troll - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='208']", [m("a[tabindex='0']", [m("span.text", "\n Antarctica/Vostok - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='209']", [m("a[tabindex='0']", [m("span.text", "\n Arctic/Longyearbyen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='210']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aden - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='211']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Almaty - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='212']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Amman - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='213']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Anadyr - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='214']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aqtau - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='215']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Aqtobe - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='216']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ashgabat - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='217']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Baghdad - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='218']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bahrain - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='219']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Baku - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='220']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bangkok - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='221']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Beirut - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='222']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Bishkek - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='223']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Brunei - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='224']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Chita - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='225']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Choibalsan - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='226']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Colombo - GMT +05:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='227']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Damascus - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='228']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dhaka - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='229']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dili - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='230']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dubai - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='231']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Dushanbe - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='232']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Gaza - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='233']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hebron - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='234']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ho_Chi_Minh - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='235']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hong_Kong - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='236']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Hovd - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='237']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Irkutsk - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='238']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jakarta - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='239']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jayapura - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='240']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Jerusalem - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='241']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kabul - GMT +04:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='242']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kamchatka - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='243']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Karachi - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='244']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kathmandu - GMT +05:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='245']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Khandyga - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='246']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kolkata - GMT +05:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='247']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Krasnoyarsk - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='248']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuala_Lumpur - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='249']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuching - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='250']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Kuwait - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='251']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Macau - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='252']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Magadan - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='253']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Makassar - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='254']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Manila - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='255']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Muscat - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='256']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Nicosia - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='257']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Novokuznetsk - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='258']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Novosibirsk - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='259']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Omsk - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='260']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Oral - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='261']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Phnom_Penh - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='262']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Pontianak - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='263']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Pyongyang - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='264']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Qatar - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='265']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Qyzylorda - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='266']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Rangoon - GMT +06:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='267']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Riyadh - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='268']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Sakhalin - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='269']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Samarkand - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='270']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Seoul - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='271']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Shanghai - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='272']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Singapore - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='273']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Srednekolymsk - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='274']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Taipei - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='275']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tashkent - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='276']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tbilisi - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='277']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tehran - GMT +03:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='278']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Thimphu - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='279']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Tokyo - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='280']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ulaanbaatar - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='281']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Urumqi - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='282']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Ust-Nera - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='283']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Vientiane - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='284']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Vladivostok - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='285']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yakutsk - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='286']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yekaterinburg - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='287']", [m("a[tabindex='0']", [m("span.text", "\n Asia/Yerevan - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='288']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Azores - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='289']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Bermuda - GMT -04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='290']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Canary - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='291']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Cape_Verde - GMT -01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='292']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Faroe - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='293']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Madeira - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='294']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Reykjavik - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='295']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/South_Georgia - GMT -02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='296']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/St_Helena - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='297']", [m("a[tabindex='0']", [m("span.text", "\n Atlantic/Stanley - GMT -03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='298']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Adelaide - GMT +10:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='299']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Brisbane - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='300']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Broken_Hill - GMT +10:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='301']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Currie - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='302']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Darwin - GMT +09:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='303']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Eucla - GMT +08:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='304']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Hobart - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='305']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Lindeman - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='306']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Lord_Howe - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='307']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Melbourne - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='308']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Perth - GMT +08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='309']", [m("a[tabindex='0']", [m("span.text", "\n Australia/Sydney - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='310']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Amsterdam - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='311']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Andorra - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='312']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Athens - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='313']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Belgrade - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='314']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Berlin - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='315']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Bratislava - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='316']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Brussels - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='317']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Bucharest - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='318']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Budapest - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='319']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Busingen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='320']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Chisinau - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='321']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Copenhagen - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='322']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Dublin - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='323']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Gibraltar - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='324']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Guernsey - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='325']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Helsinki - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='326']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Isle_of_Man - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='327']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Istanbul - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='328']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Jersey - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='329']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Kaliningrad - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='330']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Kiev - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='331']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Lisbon - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='332']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Ljubljana - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='333']", [m("a[tabindex='0']", [m("span.text", "\n Europe/London - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='334']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Luxembourg - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='335']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Madrid - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='336']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Malta - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='337']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Mariehamn - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='338']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Minsk - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='339']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Monaco - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='340']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Moscow - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='341']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Oslo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='342']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Paris - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='343']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Podgorica - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='344']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Prague - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='345']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Riga - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='346']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Rome - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='347']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Samara - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='348']", [m("a[tabindex='0']", [m("span.text", "\n Europe/San_Marino - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='349']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Sarajevo - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='350']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Simferopol - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='351']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Skopje - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='352']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Sofia - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='353']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Stockholm - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='354']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Tallinn - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='355']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Tirane - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='356']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Uzhgorod - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='357']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vaduz - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='358']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vatican - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='359']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vienna - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='360']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Vilnius - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='361']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Volgograd - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='362']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Warsaw - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='363']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zagreb - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='364']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zaporozhye - GMT +02:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='365']", [m("a[tabindex='0']", [m("span.text", "\n Europe/Zurich - GMT +01:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='366']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Antananarivo - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='367']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Chagos - GMT +06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='368']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Christmas - GMT +07:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='369']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Cocos - GMT +06:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='370']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Comoro - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='371']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Kerguelen - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='372']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mahe - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='373']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Maldives - GMT +05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='374']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mauritius - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='375']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Mayotte - GMT +03:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='376']", [m("a[tabindex='0']", [m("span.text", "\n Indian/Reunion - GMT +04:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='377']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Apia - GMT +14:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='378']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Auckland - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='379']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Chatham - GMT +13:45 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='380']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Chuuk - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='381']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Easter - GMT -05:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='382']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Efate - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='383']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Enderbury - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='384']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Fakaofo - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='385']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Fiji - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='386']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Funafuti - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='387']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Galapagos - GMT -06:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='388']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Gambier - GMT -09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='389']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Guadalcanal - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='390']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Guam - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='391']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Honolulu - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='392']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Johnston - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='393']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kiritimati - GMT +14:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='394']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kosrae - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='395']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Kwajalein - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='396']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Majuro - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='397']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Marquesas - GMT -09:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='398']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Midway - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='399']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Nauru - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='400']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Niue - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='401']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Norfolk - GMT +11:30 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='402']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Noumea - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='403']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pago_Pago - GMT -11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='404']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Palau - GMT +09:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='405']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pitcairn - GMT -08:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='406']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Pohnpei - GMT +11:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='407']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Port_Moresby - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='408']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Rarotonga - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='409']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Saipan - GMT +10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='410']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tahiti - GMT -10:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='411']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tarawa - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='412']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Tongatapu - GMT +13:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='413']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Wake - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='414']", [m("a[tabindex='0']", [m("span.text", "\n Pacific/Wallis - GMT +12:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='415']", [m("a[tabindex='0']", [m("span.text", "\n UTC - GMT +00:00 "), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), + m("span.help-block", "Set the system timezone.") + ]) + ]), + m(".form-group.form-actions", [ + m(".col-sm-offset-2.col-sm-10", [ + m("button.btn.btn-primary.btn-lg[name='save'][type='submit'][value='save']", "Apply settings") + ]) + ]) + ]) + ]), + m("form.form-horizontal[method='post'][role='form']", [ + m("fieldset", [ + m("legend", "RuneOS kernel settings"), + m(".form-group", [ + m("label.control-label.col-sm-2[for='i2smodule']", "Linux Kernel"), + m(".col-sm-10", [ + m("select.selectpicker[data-style='btn-default btn-lg'][name='kernel']", { style: { "display": " none" } }, [ + m("option[selected=''][value='linux-arch-rpi_3.12.26-1-ARCH']", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), + m("option[value='linux-rune-rpi_3.12.19-2-ARCH']", "Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]"), + m("option[value='linux-rune-rpi_3.6.11-18-ARCH+']", "Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]"), + m("option[value='linux-rune-rpi_3.12.13-rt21_wosa']", "Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]") + ]), + m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='Linux kernel 3.12.26-1   ARCH [RuneAudio v0.3-beta]'][type='button']", [m("span.filter-option.pull-left", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li.selected[rel='0']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), + m("span.help-block", ["Switch Linux Kernel version (REBOOT REQUIRED). ", m("strong", "Linux kernel 3.12.26-1"), " is the default kernel in the current release, ", m("strong", "Linux kernel 3.12.19-2"), " is the kernel used in RuneAudio v0.3-alpha, ", m("strong", "Linux kernel 3.6.11-18"), " is the kernel used in RuneAudio v0.1-beta/v0.2-beta (it has no support for I²S), ", m("strong", "Linux kernel 3.12.13-rt"), " is an EXPERIMENTAL kernel (not suitable for all configurations), it is optimized for ", m("strong", "Wolfson Audio Card"), " support and it is the default option for that type of soundcard."]) + ]), + m("label.control-label.col-sm-2[for='i2smodule']", "I²S kernel modules"), + m(".col-sm-10", [ + m("select.selectpicker[data-style='btn-default btn-lg'][name='i2smodule']", { style: { "display": " none" } }, [ + m("option[value='none']", "I²S disabled (default)"), + m("option[value='berrynos']", "G2Labs BerryNOS"), + m("option[value='berrynosmini']", "G2Labs BerryNOS mini"), + m("option[value='hifiberrydac']", "HiFiBerry DAC"), + m("option[value='hifiberrydacplus']", "HiFiBerry DAC+"), + m("option[value='hifiberrydigi']", "HiFiBerry Digi / Digi+"), + m("option[value='iqaudiopidac']", "IQaudIO Pi-DAC / Pi-DAC+"), + m("option[value='raspyplay3']", "RaspyPlay3"), + m("option[value='raspyplay4']", "RaspyPlay4"), + m("option[selected=''][value='transducer']", "Transducer") + ]), + m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='Transducer'][type='button']", [m("span.filter-option.pull-left", "Transducer"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "I²S disabled (default)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "G2Labs BerryNOS"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='2']", [m("a[tabindex='0']", [m("span.text", "G2Labs BerryNOS mini"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry DAC"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry DAC+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "HiFiBerry Digi / Digi+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "IQaudIO Pi-DAC / Pi-DAC+"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "RaspyPlay3"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='8']", [m("a[tabindex='0']", [m("span.text", "RaspyPlay4"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='9']", [m("a[tabindex='0']", [m("span.text", "Transducer"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), + m("span.help-block", ["Enable I²S output selecting one of the available sets of modules, specific for each hardware. Once set, the output interface will appear in the ", m("a[href='/mpd/']", "MPD configuration select menu"), ", and modules will also auto-load from the next reboot."]) + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='orionprofile']", "Sound Signature (optimization profiles)"), + m(".col-sm-10", [ + m("select.selectpicker[data-style='btn-default btn-lg'][name='orionprofile']", { style: { "display": " none" } }, [ + m("option[value='default']", "ArchLinux default"), + m("option[value='RuneAudio']", "RuneAudio"), + m("option[selected=''][value='ACX']", "ACX"), + m("option[value='Orion']", "Orion"), + m("option[value='OrionV2']", "OrionV2"), + m("option[value='OrionV3_berrynosmini']", "OrionV3 - (BerryNOS-mini)"), + m("option[value='OrionV3_iqaudio']", "OrionV3 - (IQaudioPi-DAC)"), + m("option[value='Um3ggh1U']", "Um3ggh1U") + ]), + m(".btn-group.bootstrap-select", [m("button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle='dropdown'][title='ACX'][type='button']", [m("span.filter-option.pull-left", "ACX"), " ", m("span.caret")]), m(".dropdown-menu.open", [m("ul.dropdown-menu.inner.selectpicker[role='menu']", [m("li[rel='0']", [m("a[tabindex='0']", [m("span.text", "ArchLinux default"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='1']", [m("a[tabindex='0']", [m("span.text", "RuneAudio"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li.selected[rel='2']", [m("a[tabindex='0']", [m("span.text", "ACX"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='3']", [m("a[tabindex='0']", [m("span.text", "Orion"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='4']", [m("a[tabindex='0']", [m("span.text", "OrionV2"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='5']", [m("a[tabindex='0']", [m("span.text", "OrionV3 - (BerryNOS-mini)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='6']", [m("a[tabindex='0']", [m("span.text", "OrionV3 - (IQaudioPi-DAC)"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])]), m("li[rel='7']", [m("a[tabindex='0']", [m("span.text", "Um3ggh1U"), m("i.glyphicon.glyphicon-ok.icon-ok.check-mark")])])])])]), + m("span.help-block", ["These profiles include a set of performance tweaks that act on some system kernel parameters.\n It does not have anything to do with DSPs or other sound effects: the output is kept untouched (bit perfect).\n It happens that these parameters introduce an audible impact on the overall sound quality, acting on kernel latency parameters (and probably on the amount of overall \n ", m("a[href='http://www.thewelltemperedcomputer.com/KB/BitPerfectJitter.htm'][target='_blank'][title='Bit Perfect Jitter by Vincent Kars']", "jitter"), ").\n Sound results may vary depending on where music is listened, so choose according to your personal taste.\n (If you can't hear any tangible differences... nevermind, just stick to the default settings.)"]) + ]) + ]), + m(".form-group.form-actions", [ + m(".col-sm-offset-2.col-sm-10", [ + m("button.btn.btn-primary.btn-lg[name='save'][type='submit'][value='save']", "Apply settings") + ]) + ]) + ]) + ]), + m("form.form-horizontal[action=''][data-parsley-validate=''][method='post'][novalidate=''][role='form']", [ + m("fieldset[id='features-management']", [ + m("legend", "Features management"), + m("p", "Enable/disable optional modules that best suit your needs. Disabling unusued features will free system resources and might improve the overall performance."), + m("[id='airplayBox']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='airplay']", "AirPlay"), + m(".col-sm-10", [ + //m("label.switch-light.well[onclick='']", [ + // m("input[data-parsley-id='0451'][data-parsley-multiple='featuresairplayenable'][id='airplay'][name='features[airplay][enable]'][type='checkbox'][value='1']"), + // m("span", [m("span", "OFF"), m("span", "ON")]), + // m("a.btn.btn-primary") + //]), + //m("ul.parsley-errors-list[id='parsley-id-multiple-featuresairplayenable']"), + m("span.help-block", "Toggle the capability of receiving wireless streaming of audio via AirPlay protocol") + ]) + ]), + m(".hide[id='airplayName']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='airplay-name']", "AirPlay name"), + m(".col-sm-10", [ + m("input.form-control.input-lg[data-parsley-id='0928'][data-trigger='change'][id='airplay_name'][name='features[airplay][name]'][placeholder='runeaudio'][type='text'][value='RuneAudio']"), + m("ul.parsley-errors-list[id='parsley-id-0928']"), + m("span.help-block", "AirPlay broadcast name") + ]) + ]) + ]) + ]), + m("[id='spotifyBox']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='spotify']", "Spotify"), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[data-parsley-id='3701'][data-parsley-multiple='featuresspotifyenable'][id='spotify'][name='features[spotify][enable]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary.") + ]), + m("ul.parsley-errors-list[id='parsley-id-multiple-featuresspotifyenable']"), + m("span.help-block", ["Enable Spotify client [EXPERIMENTAL]. You must have a ", m("strong", [m("a[href='https://www.spotify.com/uk/premium/'][target='_blank']", "Spotify PREMIUM")]), " account."]) + ]) + ]), + m(".hide[id='spotifyAuth']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='spotify-usr']", "Username"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='0174'][data-trigger='change'][id='spotify_user'][name='features[spotify][user]'][placeholder='user'][type='text'][value='user']"), + m("ul.parsley-errors-list[id='parsley-id-0174']"), + m("span.help-block", ["Insert your Spotify ", m("i", "username")]) + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='spotify-pasw']", "Password"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='0985'][id='spotify_pass'][name='features[spotify][pass]'][placeholder='pass'][type='password'][value='pass']"), + m("ul.parsley-errors-list[id='parsley-id-0985']"), + m("span.help-block", ["Insert your Spotify ", m("i", "password"), " (case sensitive)"]) + ]) + ]) + ]) + ]), + m("[id='dlnaBox']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='dlna']", "UPnP / DLNA"), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[data-parsley-id='1837'][data-parsley-multiple='featuresdlnaenable'][id='dlna'][name='features[dlna][enable]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary") + ]), + m("ul.parsley-errors-list[id='parsley-id-multiple-featuresdlnaenable']"), + m("span.help-block", "Toggle the capability of receiving wireless streaming of audio via UPnP / DLNA protocol") + ]) + ]), + m(".hide[id='dlnaName']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='dlna-name']", "UPnP / DLNA name"), + m(".col-sm-10", [ + m("input.form-control.input-lg[data-parsley-id='8193'][data-trigger='change'][id='dlna_name'][name='features[dlna][name]'][placeholder='runeaudio'][type='text'][value='RuneAudio']"), + m("ul.parsley-errors-list[id='parsley-id-8193']"), + m("span.help-block", "UPnP / DLNA broadcast name") + ]) + ]) + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='udevil']", "USB Automount"), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[data-parsley-id='1024'][data-parsley-multiple='featuresudevil'][name='features[udevil]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary") + ]), + m("ul.parsley-errors-list[id='parsley-id-multiple-featuresudevil']"), + m("span.help-block", "Toggle automount for USB drives") + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='coverart']", "Display album cover"), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[checked='checked'][data-parsley-id='5818'][data-parsley-multiple='featurescoverart'][name='features[coverart]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary") + ]), + m("ul.parsley-errors-list[id='parsley-id-multiple-featurescoverart']"), + m("span.help-block", "Toggle the display of album art on the Playback main screen") + ]) + ]), + m("[id='lastfmBox']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='lastfm']", [m("i.fa.fa.fa-lastfm-square"), " Last.fm"]), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[data-parsley-id='6913'][data-parsley-multiple='featureslastfmenable'][id='scrobbling-lastfm'][name='features[lastfm][enable]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary") + ]), + m("ul.parsley-errors-list[id='parsley-id-multiple-featureslastfmenable']"), + m("span.help-block", "Send to Last.fm informations about the music you are listening to (requires a Last.fm account)") + ]) + ]), + m(".hide[id='lastfmAuth']", [ + m(".form-group", [ + m("label.control-label.col-sm-2[for='lastfm-usr']", "Username"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='9931'][data-trigger='change'][id='lastfm_user'][name='features[lastfm][user]'][placeholder='user'][type='text'][value='user']"), + m("ul.parsley-errors-list[id='parsley-id-9931']"), + m("span.help-block", ["Insert your Last.fm ", m("i", "username")]) + ]) + ]), + m(".form-group", [ + m("label.control-label.col-sm-2[for='lastfm-pasw']", "Password"), + m(".col-sm-10", [ + m("input.form-control.input-lg[autocomplete='off'][data-parsley-id='2505'][id='lastfm_pass'][name='features[lastfm][pass]'][placeholder='pass'][type='password'][value='pass']"), + m("ul.parsley-errors-list[id='parsley-id-2505']"), + m("span.help-block", ["Insert your Last.fm ", m("i", "password"), " (case sensitive)"]) + ]) + ]) + ]) + ]), + m(".form-group.form-actions", [ + m(".col-sm-offset-2.col-sm-10", [ + m("button.btn.btn-primary.btn-lg[name='features[submit]'][type='submit'][value='1']", "apply settings") + ]) + ]) + ]) + ]), + m("form.form-horizontal[action=''][method='post'][role='form']", [ + m("fieldset", [ + m("legend", "Compatibility fixes"), + m("p", "For people suffering problems with some receivers and DACs."), + m(".form-group", [ + m("label.control-label.col-sm-2[for='cmediafix']", "CMedia fix"), + m(".col-sm-10", [ + m("label.switch-light.well[onclick='']", [ + m("input[name='cmediafix[1]'][type='checkbox'][value='1']"), + m("span", [m("span", "OFF"), m("span", "ON")]), + m("a.btn.btn-primary") + ]), + m("span.help-block", ["For those who have a CM6631 receiver and experiment issues (noise, crackling) between tracks with different sample rates and/or bit depth.", m("br"), " \n A \"dirty\" fix that should avoid the problem, do NOT use if everything works normally."]) + ]) + ]), + m(".form-group.form-actions", [ + m(".col-sm-offset-2.col-sm-10", [ + m("button.btn.btn-primary.btn-lg[name='cmediafix[0]'][type='submit'][value='1']", "Apply fixes") + ]) + ]) + ]) + ]), + m("form.form-horizontal[method='post']", [ + m("fieldset", [ + m("legend", "Backup / Restore configuration"), + m("p", "Transfer settings between multiple RuneAudio installations, saving time during new/upgrade installations."), + m(".form-group", [ + m("label.control-label.col-sm-2", "Backup player config"), + m(".col-sm-10", [ + m("input.btn.btn-primary.btn-lg[id='syscmd-backup'][name='syscmd'][type='submit'][value='backup']"), + m("span.help-block", "NOTE: restore feature will come in 0.4 release.") + ]) + ]) + ]) + ]), + "\n"]; }; @@ -912,7 +987,7 @@ mpd.view = function (ctrl) { m('option[value="disabled"]', 'disabled'), m('option[value="software"]', 'enabled - software'), m('option[value="hardware"]', 'enabled - hardware') - ]), + ]), m('span.help-block', [ m('strong', 'disabled'), ' - Volume knob disabled. Use this option to achieve the ', @@ -947,7 +1022,7 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="daemon-user"]', 'Daemon user : group'), m('.col-sm-10', [ - m('select[data-style="btn-default btn-lg"][id="log-level"][name="conf[user]"]', { config: selectpicker }, [ + m('select[data-style="btn-default btn-lg"][id="user"][name="conf[user]"]', bind2(mpd.vm.data.conf, 'user', selectpicker), [ m('option[selected=""][value="mpd"]', 'mpd : audio (default)'), m('option[value="root"]', 'root : root') ]), @@ -957,7 +1032,7 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="log-level"]', 'Log level'), m('.col-sm-10', [ - m('select[data-style="btn-default btn-lg"][id="log-level"][name="conf[log_level]"]', { config: selectpicker }, [ + m('select[data-style="btn-default btn-lg"][id="log-level"][name="conf[log_level]"]', bind2(mpd.vm.data.conf, 'log_level', selectpicker), [ m('option[selected=""][value="none"]', 'disabled'), m('option[value="default"]', 'default'), m('option[value="secure"]', 'secure'), @@ -970,7 +1045,7 @@ mpd.view = function (ctrl) { m('label.col-sm-2.control-label[for="state-file"]', 'State file'), m('.col-sm-10', [ // (id, container, field, config) - createSelectYesNo('log-level', mpd.vm.data.conf, 'log-level', selectpicker), + createYesNo('state_file', mpd.vm.data.conf, 'state_file', selectpicker), //m('select[data-style="btn-default btn-lg"][id="log-level"][name="conf[state_file]"]', { config: selectpicker }, [ // m('option[selected=""][value="yes"]', 'enabled'), // m('option[value="no"]', 'disabled') @@ -981,42 +1056,42 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="ffmpeg"]', 'FFmpeg decoder plugin'), m('.col-sm-10', [ - createSelectYesNo('ffmpeg', mpd.vm.data.conf, 'ffmpeg', selectpicker), + createYesNo('ffmpeg', mpd.vm.data.conf, 'ffmpeg', selectpicker), m('span.help-block', 'FFmpeg decoder plugin. Enable this setting if you need AAC / ALAC support. May slow down MPD database refresh.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="gapless-mp3-playback"]', 'Gapless mp3 playback'), m('.col-sm-10', [ - createSelectYesNo('gapless-mp3-playback', mpd.vm.data.conf, 'gapless-mp3-playback', selectpicker), + createYesNo('gapless-mp3-playback', mpd.vm.data.conf, 'gapless_mp3_playback', selectpicker), m('span.help-block', 'If you have a problem with your MP3s ending abruptly it is recommended that you set this argument to \'no\' to attempt to fix the problem. If this solves the problem, it is highly recommended to fix the MP3 files with vbrfix (available as vbrfix in the debian archive), at which point gapless MP3 playback can be enabled.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="dsd-usb"]', 'DSD support'), m('.col-sm-10', [ - createSelectYesNo('dsd-usb', mpd.vm.data.conf, 'dsd-usb', selectpicker), + createYesNo('dsd-usb', mpd.vm.data.conf, 'dsd_usb', selectpicker), m('span.help-block', 'Enable DSD audio support.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="volume-normalization"]', 'Volume normalization'), m('.col-sm-10', [ - createSelectYesNo('volume-normalization', mpd.vm.data.conf, 'volume-normalization', selectpicker), + createYesNo('volume-normalization', mpd.vm.data.conf, 'volume_normalization', selectpicker), m('span.help-block', 'If yes, mpd will normalize the volume of songs as they play. The default is no') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="port"]', 'Audio buffer size'), m('.col-sm-10', [ - m('input.form-control.input-lg[data-trigger="change"][id="audio-buffer-size"][min="512"][name="conf[audio_buffer_size]"][type="number"]', bind2(mpd.vm.data, 'audio_buffer_size')), + m('input.form-control.input-lg[data-trigger="change"][id="audio-buffer-size"][min="512"][name="conf[audio_buffer_size]"][type="number"]', bind2(mpd.vm.data.conf, 'audio_buffer_size')), m('span.help-block', 'This specifies the size of the audio buffer in kibibytes. The default is 2048, large enough for nearly 12 seconds of CD-quality audio.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="dsd-usb"]', 'Buffer before play'), m('.col-sm-10', [ - m('select[data-style="btn-default btn-lg"][id="buffer-before-play"][name="conf[buffer_before_play]"]', { config: selectpicker }, [ + m('select[data-style="btn-default btn-lg"][id="buffer-before-play"][name="conf[buffer_before_play]"]', bind2(mpd.vm.data.conf, 'buffer_before_play', selectpicker), [ m('option[value="0%"]', 'disabled'), '\n \n\';\n ', m('option[selected=""][value="10%"]', '10%'), @@ -1032,7 +1107,7 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="auto-update"]', 'Auto update'), m('.col-sm-10', [ - createSelectYesNo('auto-update', mpd.vm.data.conf, 'auto-update', selectpicker), + createYesNo('auto-update', mpd.vm.data.conf, 'auto_update', selectpicker), m('span.help-block', 'This setting enables automatic update of MPD"s database when files in music_directory are changed.') ]) ]) diff --git a/command/cachectl.php b/command/cachectl.php index 0cb6ae97..e97f3a5a 100755 --- a/command/cachectl.php +++ b/command/cachectl.php @@ -47,7 +47,7 @@ OpCacheCtl('reset', '/srv/http/'); opcache_reset(); runelog('cacheCTL RESET'); - echo "PHP OPCACHE CLEARED"; + echo "PHP OPCACHE CLEARED " . (new \DateTime())->format('Y-m-d H:i:s'); break; case 'debug': // opcache_reset(); diff --git a/app/config/index.html b/config/index.html similarity index 86% rename from app/config/index.html rename to config/index.html index 4e99474f..80a1ab39 100644 --- a/app/config/index.html +++ b/config/index.html @@ -65,7 +65,7 @@ */ --> ",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) +}}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageYold=0,pageYdiff=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){isCustomScroll||(pageY=window.pageYOffset,pageYdiff=Math.abs(pageYold-pageY),pageYdiff>6*pageHeight&&(pageYold=pageY,console.log("REDRAW ",pageY),m.redraw()))},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=8,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file From 2fd965c2918baf08e2c163a5e07057c06d91a0b6 Mon Sep 17 00:00:00 2001 From: kdubious Date: Sun, 21 Dec 2014 15:06:43 -0500 Subject: [PATCH 36/80] Show the friendly name of the selected card --- app/api/mpd_ctl.php | 14 ++++++++++++-- assets/js/runeui-static.js | 4 ++-- db/phpinfo.php | 8 ++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 db/phpinfo.php diff --git a/app/api/mpd_ctl.php b/app/api/mpd_ctl.php index 6f7db125..4e246c35 100644 --- a/app/api/mpd_ctl.php +++ b/app/api/mpd_ctl.php @@ -66,6 +66,11 @@ } waitSyWrk($redis, $jobID); + +$ao = ''; +$aoValue = $redis->get('ao'); + + // check integrity of /etc/network/interfaces if(!hashCFG('check_mpd', $redis)) { $template->mpdconf = file_get_contents('/etc/mpd.conf'); @@ -103,14 +108,19 @@ $audio_cards[] = $sub_int_details; } } - if ($details->extlabel !== 'none') $acard_data->extlabel = $details->extlabel; + if ($details->extlabel !== 'none') { + $acard_data->extlabel = $details->extlabel; + } } } + if ($acard_data->name == $aoValue) { + $ao = $acard_data->extlabel; + } $audio_cards[] = $acard_data; } osort($audio_cards, 'extlabel'); // debug // print_r($audio_cards); $template->acards = $audio_cards; - $template->ao = $redis->get('ao'); + $template->ao = $ao; } diff --git a/assets/js/runeui-static.js b/assets/js/runeui-static.js index 5b001d5a..62166881 100644 --- a/assets/js/runeui-static.js +++ b/assets/js/runeui-static.js @@ -29,7 +29,7 @@ var bind2 = function (container, field, config, readonly) { var attributes = { config: config, onchange: m.withAttr('value', function (value) { container[field] = value; }), - value: container[field], + value: decodeURI(container[field]) }; if (readonly) { @@ -293,7 +293,7 @@ var volume = {}; audio.view = function (ctrl) { - return m('h1', 'Audio Configuration') + return m('h1', 'Audio Configuration'); }; // Settings diff --git a/db/phpinfo.php b/db/phpinfo.php new file mode 100644 index 00000000..3576cd12 --- /dev/null +++ b/db/phpinfo.php @@ -0,0 +1,8 @@ +pconnect('127.0.0.1'); +$sub_interfaces = $redis->sMembers($card); + +//phpinfo(); +?> \ No newline at end of file From d0c86bde4221705ef4d5f73e8f6e4fe2af082c80 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sun, 21 Dec 2014 21:13:42 +0100 Subject: [PATCH 37/80] Single page app moved to /config --- app/templates/config.php | 4 +- app/templates/footer.php | 8 +- app/templates/header.php | 17 +- assets/img/logo.png | Bin 74506 -> 2096 bytes assets/js/runeui-static.js | 4 +- assets/js/vendor/mithril.js | 989 ++++++++++++++++++++++++++++++++++++ config/index.html | 115 ----- config/local.html | 114 ----- 8 files changed, 1012 insertions(+), 239 deletions(-) create mode 100644 assets/js/vendor/mithril.js delete mode 100644 config/index.html delete mode 100644 config/local.html diff --git a/app/templates/config.php b/app/templates/config.php index e9275538..51b7809d 100644 --- a/app/templates/config.php +++ b/app/templates/config.php @@ -1 +1,3 @@ -
    \ No newline at end of file + +
    +
    diff --git a/app/templates/footer.php b/app/templates/footer.php index cd2583d0..a9b9209e 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -16,12 +16,14 @@ +section !== 'config'): ?>
    section == 'dev') { ?> class="hide">
    connecting...
    + - + section == 'debug'): ?> @@ -37,12 +39,16 @@ +section !== 'config'): ?> dev === '0'):?> + + + diff --git a/app/templates/header.php b/app/templates/header.php index d5bbc24c..62c9d60e 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -67,19 +67,24 @@ */ --> + +
    + +
    +
    + Volume control +
    + +
    + + + disabled - Volume knob disabled. Use this option to achieve the best audio quality.
    + software - Volume knob enabled, controlled by software mixer. This option reduces the overall sound quality.
    + hardware - Volume knob enabled, controlled by hardware mixer. This option enables the volume control and let you achieve very good overall sound quality.
    + Note: hardware mixer must be supported directly from your sound card hardware. +
    +
    +
    +
    +
    + General music daemon options +
    + +
    + + This setting is the TCP port that is desired for the daemon to get assigned to. +
    +
    +
    + +
    + + This specifies the system user : group that MPD will run as. +
    +
    +
    + +
    + + This setting controls the type of information which is logged. Available setting arguments are "disabled", "default", "secure" or "verbose". + The "verbose" setting argument is recommended for troubleshooting, though can quickly stretch available resources on limited hardware storage. +
    +
    +
    + +
    + + This setting specifies if a state file is used. If the state file is active, the state of mpd will be saved when mpd is terminated by a TERM signal or by the "kill" command. When mpd is restarted, it will read the state file and restore the state of mpd (including the playlist). +
    +
    +
    + +
    + + FFmpeg decoder plugin. Enable this setting if you need AAC / ALAC support. May slow down MPD database refresh. +
    +
    +
    + +
    + + If you have a problem with your MP3s ending abruptly it is recommended that you set this argument to "no" to attempt to fix the problem. If this solves the problem, + it is highly recommended to fix the MP3 files with vbrfix (available as vbrfix in the debian archive), at which point gapless MP3 playback can be enabled. +
    +
    +
    + +
    + + Enable DSD audio support. +
    +
    +
    + +
    + + If yes, mpd will normalize the volume of songs as they play. The default is no +
    +
    +
    + +
    + + This specifies the size of the audio buffer in kibibytes. The default is 2048, large enough for nearly 12 seconds of CD-quality audio. +
    +
    +
    + +
    + + This specifies how much of the audio buffer should be filled before playing a song. Try increasing this if you hear skipping when manually changing songs. The default is 10%, a little over 1 second of CD-quality audio with the default buffer size +
    +
    +
    + +
    + + This setting enables automatic update of MPD's database when files in music_directory are changed. +
    +
    +
    +
    +
    + Cancel + +
    +
    +
    + + \ No newline at end of file diff --git a/assets/js/runeui-static.js b/assets/js/runeui-static.js index 151bf9d4..8b636980 100644 --- a/assets/js/runeui-static.js +++ b/assets/js/runeui-static.js @@ -12,6 +12,14 @@ function selectpicker(element, isInitialized) { } } +// encode(decode) html text into html entity +function decodeHtmlEntity(str) { + return str.replace(/&#(\d+);/g, function(match, dec) { + return String.fromCharCode(dec); + }); +}; + + // MITHRIL // ---------------------------------------------------------------------------------------------------- @@ -21,7 +29,7 @@ var playback = {}; // helpers -// base 2-way binding helper +// base 2-way binding helper var bind2 = function (container, field, config, readonly) { // container: for example 'mpd.vm.data.conf' // field: for example 'port or audio_mixer' @@ -29,7 +37,7 @@ var bind2 = function (container, field, config, readonly) { var attributes = { config: config, onchange: m.withAttr('value', function (value) { container[field] = value; }), - value: decodeURI(container[field]) + value: decodeHtmlEntity(container[field]) }; if (readonly) { From bbb03942c6a43e3c374350674cbe61fcf1cb1357 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sun, 21 Dec 2014 21:54:02 +0100 Subject: [PATCH 39/80] Helper functions to encode/decode html entities --- assets/js/runeui-static.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/assets/js/runeui-static.js b/assets/js/runeui-static.js index 8b636980..dbb3912e 100644 --- a/assets/js/runeui-static.js +++ b/assets/js/runeui-static.js @@ -12,11 +12,19 @@ function selectpicker(element, isInitialized) { } } -// encode(decode) html text into html entity -function decodeHtmlEntity(str) { +// decode html text into html entity +var decodeHtmlEntity = function(str) { return str.replace(/&#(\d+);/g, function(match, dec) { return String.fromCharCode(dec); }); +}; +// encode html text into html entity +var encodeHtmlEntity = function(str) { + var buf = []; + for (var i=str.length-1;i>=0;i--) { + buf.unshift(['&#', str[i].charCodeAt(), ';'].join('')); + } + return buf.join(''); }; From ca2e2bfeb233560c75bdaeb18c4ed31ee886be59 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Mon, 22 Dec 2014 03:09:07 +0100 Subject: [PATCH 40/80] Removed boxed class around Audio Output --- assets/js/runeui-static.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/assets/js/runeui-static.js b/assets/js/runeui-static.js index dbb3912e..d7b53192 100644 --- a/assets/js/runeui-static.js +++ b/assets/js/runeui-static.js @@ -1020,23 +1020,14 @@ mpd.view = function (ctrl) { m('form.form-horizontal[action=""][method="post"]', [ m('fieldset', [ m('legend', 'Audio Output'), - m('.boxed-group', [ m('.form-group', [ createLabel('audio-output-interface', 'Audio output interface'), m('.col-sm-10', [ //(id, container, field, list, valueField, displayField, config) m('input.form-control.input-lg[data-trigger="change"][id="ao"][type="text"]', bind2(mpd.vm.data, 'ao', null, true)), //createSelect('audio-output-interface', mpd.vm.data, 'ao', 'acards', 'name', 'extlabel', selectpicker), - m('span.help-block', ['This is the current output interface. It can be ', m('a[href="/audio"]', { config: m.route }, 'configured here'), '.']) - //]), - //m('.form-group.form-actions', [ - // m('.col-sm-offset-2.col-sm-10', [ - // //m('a.btn.btn-default.btn-lg[href="/mpd/"]', { config: m.route }, 'Cancel'), //TODO: Do we navigate, or re-init the data? - // m('button.btn.btn-default.btn-lg[name="cancel"][value="cancel"][type="button"]', { onclick: mpd.vm.cancel }, 'Cancel'), - // m('button.btn.btn-primary.btn-lg[name="save"][value="save"][type="button"]', { onclick: mpd.vm.save }, 'Save and apply') - // ]) - //]) - ]) + m('span.help-block', ['This is the current output interface. It can be ', m('a[href="/audio"]', { config: m.route }, 'configured here'), '.' + ]) ]) ]) ]) From a9f9bad29b6ee5cd9f7b1585a92e3063e0f3248b Mon Sep 17 00:00:00 2001 From: ACXgit Date: Mon, 22 Dec 2014 14:20:53 +0100 Subject: [PATCH 41/80] Better menu icon --- app/templates/header.php | 2 +- assets/js/runeui-static.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/templates/header.php b/app/templates/header.php index 62c9d60e..726dba82 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -69,7 +69,7 @@ "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&GUI.currentqueuepos&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) }}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;b
    back')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageYold=0,pageYdiff=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){isCustomScroll||(pageY=window.pageYOffset,pageYdiff=Math.abs(pageYold-pageY),pageYdiff>6*pageHeight&&(pageYold=pageY,console.log("REDRAW ",pageY),m.redraw()))},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=8,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file From 59be13bb5d4538e1c9bee2c8eb2ad1e121e97282 Mon Sep 17 00:00:00 2001 From: Kevin Welsh Date: Thu, 8 Jan 2015 00:05:37 -0500 Subject: [PATCH 56/80] Notify ported to Mithril code --- _TEST/index.html | 7 ++ app/api/mpd_ctl.php | 19 ++- app/api/settings_ctl.php | 13 +- app/config/config.php | 10 +- app/libs/runeaudio.php | 7 +- assets/js/runeui._helpers.js | 24 +++- assets/js/runeui._init.js | 222 ++++++++++++++++++++++++++++++++++- assets/js/runeui.mpd.js | 24 ++-- assets/js/runeui.settings.js | 1 + command/rune_SY_wrk | 2 +- 10 files changed, 297 insertions(+), 32 deletions(-) diff --git a/_TEST/index.html b/_TEST/index.html index 29177e37..2ad6e38c 100644 --- a/_TEST/index.html +++ b/_TEST/index.html @@ -9,6 +9,7 @@
    +
    + + \ No newline at end of file diff --git a/app/api/mpd_ctl.php b/app/api/mpd_ctl.php index 6e444cfd..3597e13b 100644 --- a/app/api/mpd_ctl.php +++ b/app/api/mpd_ctl.php @@ -51,6 +51,13 @@ } // update MPD configuration if (isset($json['conf'])) { + foreach ($json['conf'] as $mpdfield => $data) { + if ($data === TRUE) { + $json['conf'][$mpdfield] = 'yes'; + } else if ($data === FALSE) { + $json['conf'][$mpdfield] = 'no'; + } + } $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'update', 'args' => $json['conf'])); $template->CCC = "conf"; } @@ -71,14 +78,20 @@ // set manual config template $template->content = "mpd_manual"; } else { - $template->conf = $redis->hGetAll('mpdconf'); // At the moment, the UI needs to convert the // file name being present to a 'yes' $mpdconf = $redis->hGetAll('mpdconf'); if (isset($mpdconf['state_file'])) { - $mpdconf['state_file'] = 'yes'; + $mpdconf['state_file'] = TRUE; } else { - $mpdconf['state_file'] = 'no'; + $mpdconf['state_file'] = FALSE; + } + foreach ($mpdconf as $mpdfield => $data) { + if ($data === 'yes') { + $mpdconf[$mpdfield] = TRUE; + } else if ($data === 'no') { + $mpdconf[$mpdfield] = FALSE; + } } $template->conf = $mpdconf; $i2smodule = $redis->get('i2smodule'); diff --git a/app/api/settings_ctl.php b/app/api/settings_ctl.php index d261f2d5..4ee91422 100644 --- a/app/api/settings_ctl.php +++ b/app/api/settings_ctl.php @@ -186,7 +186,7 @@ public function __construct($n, $v) { //} $template->YYYY = $jobID; - waitSyWrk($redis,$jobID); + // waitSyWrk($redis,$jobID); } else { @@ -195,7 +195,7 @@ public function __construct($n, $v) { foreach (ui_timezone() as $t) { $timezones[] = new NameValuePair($t['zone'].' - '.$t['diff_from_GMT'], $t['zone']); } -$environment['timezones'] = $timezones; +// $environment['timezones'] = $timezones; $environment['hostname'] = $redis->get('hostname'); $environment['ntpserver'] = $redis->get('ntpserver'); $environment['timezone'] = $redis->get('timezone'); @@ -209,14 +209,21 @@ public function __construct($n, $v) { // features section $features['airplay'] = $redis->hGetAll('airplay'); -$features['airplay']['enable'] = ($features['airplay']['enable'] === '1'); // [TODO] remove this line when boolean values will come from the backend +$features['airplay']['enable'] = ($features['airplay']['enable'] === '1'); $features['dlna'] = $redis->hGetAll('dlna'); +$features['dlna']['enable'] = ($features['dlna']['enable'] === '1'); $features['udevil'] = $redis->get('udevil'); +$features['udevil'] = ($features['udevil'] === '1'); $features['coverart'] = $redis->get('coverart'); +$features['coverart'] = ($features['coverart'] === '1'); $features['globalrandom'] = $redis->get('globalrandom'); +$features['globalrandom'] = ($features['globalrandom'] === '1'); $features['lastfm'] = $redis->hGetAll('lastfm'); +$features['lastfm']['enable'] = ($features['lastfm']['enable'] === '1'); $features['proxy'] = $redis->hGetAll('proxy'); +$features['proxy']['enable'] = ($features['proxy']['enable'] === '1'); $features['spotify'] = $redis->hGetAll('spotify'); +$features['spotify']['enable'] = ($features['spotify']['enable'] === '1'); $features['hwplatformid'] = $redis->get('hwplatformid'); $template->features = $features; diff --git a/app/config/config.php b/app/config/config.php index 0094849c..5c8db40c 100755 --- a/app/config/config.php +++ b/app/config/config.php @@ -47,11 +47,6 @@ $redis->pconnect('127.0.0.1'); //$redis->pconnect('/tmp/redis.sock'); $devmode = $redis->get('dev'); -if($devmode) { - error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); // track them all? - ini_set('track_errors', 1); //Lets us get the errors with: $php_errormsg -} - $activePlayer = $redis->get('activePlayer'); // LogSettings if ($redis->get('debug') > 0 ) { @@ -61,7 +56,8 @@ } ini_set('log_errors', $activeLog); ini_set('error_log', '/var/log/runeaudio/runeui.log'); -ini_set('display_errors', $activeLog); +// ini_set('display_errors', $activeLog); +ini_set('display_errors', 0); // connect to MPD daemon if ($_SERVER["SCRIPT_FILENAME"] === '/var/www/command/index.php' && $activePlayer === 'MPD') { // debug @@ -73,4 +69,4 @@ $mpd = openMpdSocket('/run/mpd.sock', 1); } elseif ($redis->hGet('spotify', 'enable') === '1' && $activePlayer === 'Spotify') { $spop = openSpopSocket('localhost', 6602, 1); -} +} \ No newline at end of file diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index b01755a4..b1910315 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -1258,7 +1258,7 @@ function wrk_control($redis, $action, $data) break; } // debug - runelog('[wrk] wrk_control($redis,'.$action.','.$data.') jobID=', $jobID); + runelog('[wrk] wrk_control($redis,'.$action.','.$data.') jobID=', $jobID); // [TODO] check this return $jobID; } @@ -2111,6 +2111,11 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) $output .="}\n"; continue; } + // if ($value === '1') { + // $value = 'yes'; + // } else if ($value === '0') { + // $value = 'no'; + // } $output .= $param." \t\"".$value."\"\n"; } $output = $header.$output; diff --git a/assets/js/runeui._helpers.js b/assets/js/runeui._helpers.js index 2a2a81f6..52e3c7e8 100644 --- a/assets/js/runeui._helpers.js +++ b/assets/js/runeui._helpers.js @@ -50,4 +50,26 @@ helpers.encodeHtmlEntity = function (str) { buf.unshift(['&#', str[i].charCodeAt(), ';'].join('')); } return buf.join(''); -}; \ No newline at end of file +}; + +// check WebSocket support +helpers.checkWebSocket = function(){ + if (window.WebSocket){ + // console.log('WebSockets supported'); + return 'websocket'; + } else { + // console.log('WebSockets not supported'); + return 'longpolling'; + } +} + +// check HTML5 Workers support +helpers.checkWorkers = function(){ + if ((window.Worker && window.Blob) || (Modernizr.webworkers && Modernizr.blobconstructor)) { + // console.log('WebWorkers supported'); + return true; + } else { + // console.log('WebWorkers not supported'); + return false; + } +} \ No newline at end of file diff --git a/assets/js/runeui._init.js b/assets/js/runeui._init.js index 74d85a67..11747d15 100644 --- a/assets/js/runeui._init.js +++ b/assets/js/runeui._init.js @@ -1,3 +1,31 @@ +var GUI = { + DBentry: ['','',''], + DBupdate: 0, + activePlayer: '', + browsemode: 'file', + currentDBpos: [0,0,0,0,0,0,0,0,0,0,0], + currentDBpath: ['','','','','','','','','','',''], + currentalbum: null, + currentknob: null, + currentpath: '', + currentsong: null, + currentqueuepos: 0, + json: 0, + libraryhome: '', + mode: 'websocket', + noticeUI: {}, + playlist: null, + plugin: '', + state: '', + stepVolumeDelta: 0, + stepVolumeInt: 0, + stream: '', + visibility: 'visible', + volume: null +}; + + + // ROUTING // ---------------------------------------------------------------------------------------------------- @@ -16,9 +44,199 @@ m.route(document.getElementById('app'), '/', { }); + +// NGINX PUSHSTREAM MODULE CHANNELS +// ---------------------------------------------------------------------------------------------------- + +// custom complex notifies +function customNotify(notify) { + if (notify.custom === 'kernelswitch') { + if (GUI.noticeUI.kernelswitch !== undefined) { + GUI.noticeUI.kernelswitch.remove(); + } + GUI.noticeUI.kernelswitch = new PNotify({ + title: ('title' in notify) ? notify.title : '[missing title]', + text: ('text' in notify) ? notify.text : '[missing text]', + icon: 'fa fa-refresh', + hide: false, + confirm: { + confirm: true, + buttons: [{ + text: notify.btntext, + addClass: 'btn-default btn-block uppercase', + click: function() { + $.post('/settings/', { 'syscmd' : 'reboot' }); + toggleLoader(); + } + }, + { + text: 'Cancel', + addClass: 'hide' + }] + }, + buttons: { + closer: false, + sticker: false + } + }); + } +} + +// notify messages rendering +function renderMSG(text) { + // console.log(text); + var notify = text[0]; + if ('custom' in notify && notify.custom !== null) { + customNotify(notify); + return; + } + var noticeOptions = { + title: ('title' in notify) ? notify.title : '[missing title]', + text: ('text' in notify) ? notify.text : '[missing text]', + icon: (notify.icon === undefined) ? 'fa fa-check' : notify.icon, + opacity: (notify.opacity === undefined) ? 0.9 : notify.opacity, + hide: (notify.hide === undefined && notify.permanotice === undefined), + buttons: { + closer: (notify.permanotice === undefined), + sticker: (notify.permanotice === undefined) + }, + delay: (notify.delay === undefined) ? 8000 : notify.delay, + mouse_reset: false + }; + if ('permanotice' in notify) { + if (GUI.noticeUI[notify.permanotice] === undefined) { + GUI.noticeUI[notify.permanotice] = new PNotify(noticeOptions); + } else { + if ('permaremove' in notify) { + GUI.noticeUI[notify.permanotice].remove(); + GUI.noticeUI[notify.permanotice] = undefined; + } else { + GUI.noticeUI[notify.permanotice].open(); + } + } + } else { + new PNotify(noticeOptions); + } +} + +// open the Playback UI refresh channel +function playbackChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode, + reconnectOnChannelUnavailableInterval: 5000 + }); + pushstream.onmessage = renderUI; + pushstream.onstatuschange = function(status) { + // console.log('[nginx pushtream module] status = ', status); + if (status === 2) { + $('#loader').addClass('hide'); + sendCmd('renderui'); // force UI rendering (backend-call) + } else { + // console.log('[nginx pushtream module] status change (' + status + ')'); + if (status === 0) { + // console.log('[nginx pushtream module] status disconnected (0)'); + toggleLoader(); + } + } + }; + // pushstream.onerror = function() { + // toggleLoader(); + // console.log('[nginx pushtream module] error'); + // }; + pushstream.addChannel('playback'); + pushstream.connect(); +} + +// open the playing queue channel +function queueChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode + }); + pushstream.onmessage = renderQueue; + // pushstream.onstatuschange = function(status) { + // force queue rendering (backend-call) + // if (status === 2) sendCmd('renderpl'); + // }; + pushstream.addChannel('queue'); + pushstream.connect(); +} + +// open the library channel +function libraryChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode + }); + pushstream.onmessage = libraryHome; + pushstream.addChannel('library'); + pushstream.connect(); +} + +// open the notify messages channel +function notifyChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode + }); + pushstream.onmessage = renderMSG; + pushstream.addChannel('notify'); + pushstream.connect(); +} + +// open the in range Wi-Fi networks list channel +function wlansChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode + }); + pushstream.onmessage = listWLANs; + pushstream.addChannel('wlans'); + pushstream.connect(); + $.ajax({url: '/command/?cmd=wifiscan'}); +} + +// open the NIC details channel +function nicsChannel(){ + var pushstream = new PushStream({ + host: window.location.hostname, + port: window.location.port, + modes: GUI.mode + }); + pushstream.onmessage = nicsDetails; + pushstream.addChannel('nics'); + pushstream.connect(); +} + + + // INIT // ---------------------------------------------------------------------------------------------------- -jQuery(document).ready(function ($) { - 'use strict'; +jQuery(document).ready(function ($) { 'use strict'; + + // check WebSocket support + GUI.mode = helpers.checkWebSocket(); + + // first connection with MPD daemon + // open UI rendering channel; + // playbackChannel(); + + // PNotify init options + PNotify.prototype.options.styling = 'fontawesome'; + PNotify.prototype.options.stack.dir1 = 'up'; + PNotify.prototype.options.stack.dir2 = 'left'; + PNotify.prototype.options.stack.firstpos1 = 90; + PNotify.prototype.options.stack.firstpos2 = 50; + PNotify.prototype.options.stack.spacing1 = 10; + PNotify.prototype.options.stack.spacing2 = 10; + // open notify channel + notifyChannel(); + }); \ No newline at end of file diff --git a/assets/js/runeui.mpd.js b/assets/js/runeui.mpd.js index 0bbd271f..1cb2580d 100644 --- a/assets/js/runeui.mpd.js +++ b/assets/js/runeui.mpd.js @@ -12,7 +12,7 @@ mpd.vm.saveAudioOutput = function () { // 'MPD' view mpd.view = function (ctrl) { return [m('h1', 'MPD Configuration'), '\n', m('p', ['\n If you mess up with this configuration you can ', m('a[href="javascript:;"]', { onclick: function (e) { m.module(document.getElementById('dialog'), modal.resetmpd); } }, 'reset to default'), '.\n']), '\n', - m('fieldset', [ + m('fieldset.form-horizontal', [ m('legend', 'Audio Output'), m('.form-group', [ mithril.createLabel('ao', 'Audio output interface'), @@ -25,7 +25,7 @@ mpd.view = function (ctrl) { ]) ]) ]), - m('fieldset', [ + m('fieldset.form-horizontal', [ m('legend', 'Volume control'), m('.form-group', [ mithril.createLabel('mixer-type', 'Volume control'), @@ -36,7 +36,7 @@ mpd.view = function (ctrl) { ]) ]) ]), - m('fieldset', [ + m('fieldset.form-horizontal', [ m('legend', 'General music daemon options'), m('.form-group', [ m('label.col-sm-2.control-label[for="port"]', 'Port'), @@ -70,40 +70,36 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="state-file"]', 'State file'), m('.col-sm-10', [ - // (id, container, field, config) - mithril.createYesNo('state_file', mpd.vm.data.conf, 'state_file', helpers.selectpicker), - //m('select[data-style="btn-default btn-lg"][id="log-level"][name="conf[state_file]"]', { config: selectpicker }, [ - // m('option[selected=""][value="yes"]', 'enabled'), - // m('option[value="no"]', 'disabled') - //]) + // (id, container, field, config) + mithril.createYesNo('state_file', mpd.vm.data.conf, 'state_file'), m('span.help-block', 'This setting specifies if a state file is used. If the state file is active, the state of mpd will be saved when mpd is terminated by a TERM signal or by the \'kill\' command. When mpd is restarted, it will read the state file and restore the state of mpd (including the playlist).') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="ffmpeg"]', 'FFmpeg decoder plugin'), m('.col-sm-10', [ - mithril.createYesNo('ffmpeg', mpd.vm.data.conf, 'ffmpeg', helpers.selectpicker), + mithril.createYesNo('ffmpeg', mpd.vm.data.conf, 'ffmpeg'), m('span.help-block', 'FFmpeg decoder plugin. Enable this setting if you need AAC / ALAC support. May slow down MPD database refresh.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="gapless-mp3-playback"]', 'Gapless mp3 playback'), m('.col-sm-10', [ - mithril.createYesNo('gapless-mp3-playback', mpd.vm.data.conf, 'gapless_mp3_playback', helpers.selectpicker), + mithril.createYesNo('gapless-mp3-playback', mpd.vm.data.conf, 'gapless_mp3_playback'), m('span.help-block', 'If you have a problem with your MP3s ending abruptly it is recommended that you set this argument to \'no\' to attempt to fix the problem. If this solves the problem, it is highly recommended to fix the MP3 files with vbrfix (available as vbrfix in the debian archive), at which point gapless MP3 playback can be enabled.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="dsd-usb"]', 'DSD support'), m('.col-sm-10', [ - mithril.createYesNo('dsd-usb', mpd.vm.data.conf, 'dsd_usb', helpers.selectpicker), + mithril.createYesNo('dsd-usb', mpd.vm.data.conf, 'dsd_usb'), m('span.help-block', 'Enable DSD audio support.') ]) ]), m('.form-group', [ m('label.col-sm-2.control-label[for="volume-normalization"]', 'Volume normalization'), m('.col-sm-10', [ - mithril.createYesNo('volume-normalization', mpd.vm.data.conf, 'volume_normalization', helpers.selectpicker), + mithril.createYesNo('volume-normalization', mpd.vm.data.conf, 'volume_normalization'), m('span.help-block', 'If yes, mpd will normalize the volume of songs as they play. The default is no') ]) ]), @@ -133,7 +129,7 @@ mpd.view = function (ctrl) { m('.form-group', [ m('label.col-sm-2.control-label[for="auto-update"]', 'Auto update'), m('.col-sm-10', [ - mithril.createYesNo('auto-update', mpd.vm.data.conf, 'auto_update', helpers.selectpicker), + mithril.createYesNo('auto-update', mpd.vm.data.conf, 'auto_update'), m('span.help-block', 'This setting enables automatic update of MPD"s database when files in music_directory are changed.') ]) ]) diff --git a/assets/js/runeui.settings.js b/assets/js/runeui.settings.js index 9d96a66a..06d624eb 100644 --- a/assets/js/runeui.settings.js +++ b/assets/js/runeui.settings.js @@ -38,6 +38,7 @@ settings.view = function (ctrl) { m('.form-group', [ m('label.control-label.col-sm-2[for="timezone"]', 'Timezone'), m('.col-sm-10', [ + // [TODO] re-enable this when the rendering performance issue is solved // m('select[data-style="btn-default btn-lg"][id="timezone"]', { config: helpers.selectpicker }, [m('option[value="Africa/Abidjan"]', 'Africa/Abidjan - GMT +00:00'), m('option[value="Africa/Accra"]', 'Africa/Accra - GMT +00:00'), m('option[value="Africa/Addis_Ababa"]', 'Africa/Addis_Ababa - GMT +03:00'), m('option[value="Africa/Algiers"]', 'Africa/Algiers - GMT +00:00'), m('option[value="Africa/Asmara"]', 'Africa/Asmara - GMT +03:00'), m('option[value="Africa/Bamako"]', 'Africa/Bamako - GMT +00:00'), m('option[value="Africa/Bangui"]', 'Africa/Bangui - GMT +01:00'), m('option[value="Africa/Banjul"]', 'Africa/Banjul - GMT +00:00'), m('option[value="Africa/Bissau"]', 'Africa/Bissau - GMT -01:00'), m('option[value="Africa/Blantyre"]', 'Africa/Blantyre - GMT +02:00'), m('option[value="Africa/Brazzaville"]', 'Africa/Brazzaville - GMT +01:00'), m('option[value="Africa/Bujumbura"]', 'Africa/Bujumbura - GMT +02:00'), m('option[value="Africa/Cairo"]', 'Africa/Cairo - GMT +02:00'), m('option[value="Africa/Casablanca"]', 'Africa/Casablanca - GMT +00:00'), m('option[value="Africa/Ceuta"]', 'Africa/Ceuta - GMT +00:00'), m('option[value="Africa/Conakry"]', 'Africa/Conakry - GMT +00:00'), m('option[value="Africa/Dakar"]', 'Africa/Dakar - GMT +00:00'), m('option[value="Africa/Dar_es_Salaam"]', 'Africa/Dar_es_Salaam - GMT +03:00'), m('option[value="Africa/Djibouti"]', 'Africa/Djibouti - GMT +03:00'), m('option[value="Africa/Douala"]', 'Africa/Douala - GMT +01:00'), m('option[value="Africa/El_Aaiun"]', 'Africa/El_Aaiun - GMT -01:00'), m('option[value="Africa/Freetown"]', 'Africa/Freetown - GMT +00:00'), m('option[value="Africa/Gaborone"]', 'Africa/Gaborone - GMT +02:00'), m('option[value="Africa/Harare"]', 'Africa/Harare - GMT +02:00'), m('option[value="Africa/Johannesburg"]', 'Africa/Johannesburg - GMT +02:00'), m('option[value="Africa/Juba"]', 'Africa/Juba - GMT +02:00'), m('option[value="Africa/Kampala"]', 'Africa/Kampala - GMT +03:00'), m('option[value="Africa/Khartoum"]', 'Africa/Khartoum - GMT +02:00'), m('option[value="Africa/Kigali"]', 'Africa/Kigali - GMT +02:00'), m('option[value="Africa/Kinshasa"]', 'Africa/Kinshasa - GMT +01:00'), m('option[value="Africa/Lagos"]', 'Africa/Lagos - GMT +01:00'), m('option[value="Africa/Libreville"]', 'Africa/Libreville - GMT +01:00'), m('option[value="Africa/Lome"]', 'Africa/Lome - GMT +00:00'), m('option[value="Africa/Luanda"]', 'Africa/Luanda - GMT +01:00'), m('option[value="Africa/Lubumbashi"]', 'Africa/Lubumbashi - GMT +02:00'), m('option[value="Africa/Lusaka"]', 'Africa/Lusaka - GMT +02:00'), m('option[value="Africa/Malabo"]', 'Africa/Malabo - GMT +01:00'), m('option[value="Africa/Maputo"]', 'Africa/Maputo - GMT +02:00'), m('option[value="Africa/Maseru"]', 'Africa/Maseru - GMT +02:00'), m('option[value="Africa/Mbabane"]', 'Africa/Mbabane - GMT +02:00'), m('option[value="Africa/Mogadishu"]', 'Africa/Mogadishu - GMT +03:00'), m('option[value="Africa/Monrovia"]', 'Africa/Monrovia - GMT -00:44'), m('option[value="Africa/Nairobi"]', 'Africa/Nairobi - GMT +03:00'), m('option[value="Africa/Ndjamena"]', 'Africa/Ndjamena - GMT +01:00'), m('option[value="Africa/Niamey"]', 'Africa/Niamey - GMT +01:00'), m('option[value="Africa/Nouakchott"]', 'Africa/Nouakchott - GMT +00:00'), m('option[value="Africa/Ouagadougou"]', 'Africa/Ouagadougou - GMT +00:00'), m('option[value="Africa/Porto-Novo"]', 'Africa/Porto-Novo - GMT +01:00'), m('option[value="Africa/Sao_Tome"]', 'Africa/Sao_Tome - GMT +00:00'), m('option[value="Africa/Tripoli"]', 'Africa/Tripoli - GMT +02:00'), m('option[value="Africa/Tunis"]', 'Africa/Tunis - GMT +01:00'), m('option[value="Africa/Windhoek"]', 'Africa/Windhoek - GMT +02:00'), m('option[value="America/Adak"]', 'America/Adak - GMT -11:00'), m('option[value="America/Anchorage"]', 'America/Anchorage - GMT -10:00'), m('option[value="America/Anguilla"]', 'America/Anguilla - GMT -04:00'), m('option[value="America/Antigua"]', 'America/Antigua - GMT -04:00'), m('option[value="America/Araguaina"]', 'America/Araguaina - GMT -03:00'), m('option[value="America/Argentina/Buenos_Aires"]', 'America/Argentina/Buenos_Aires - GMT -03:00'), m('option[value="America/Argentina/Catamarca"]', 'America/Argentina/Catamarca - GMT -03:00'), m('option[value="America/Argentina/Cordoba"]', 'America/Argentina/Cordoba - GMT -03:00'), m('option[value="America/Argentina/Jujuy"]', 'America/Argentina/Jujuy - GMT -03:00'), m('option[value="America/Argentina/La_Rioja"]', 'America/Argentina/La_Rioja - GMT -03:00'), m('option[value="America/Argentina/Mendoza"]', 'America/Argentina/Mendoza - GMT -03:00'), m('option[value="America/Argentina/Rio_Gallegos"]', 'America/Argentina/Rio_Gallegos - GMT -03:00'), m('option[value="America/Argentina/Salta"]', 'America/Argentina/Salta - GMT -03:00'), m('option[value="America/Argentina/San_Juan"]', 'America/Argentina/San_Juan - GMT -03:00'), m('option[value="America/Argentina/San_Luis"]', 'America/Argentina/San_Luis - GMT -03:00'), m('option[value="America/Argentina/Tucuman"]', 'America/Argentina/Tucuman - GMT -03:00'), m('option[value="America/Argentina/Ushuaia"]', 'America/Argentina/Ushuaia - GMT -03:00'), m('option[value="America/Aruba"]', 'America/Aruba - GMT -04:00'), m('option[value="America/Asuncion"]', 'America/Asuncion - GMT -04:00'), m('option[value="America/Atikokan"]', 'America/Atikokan - GMT -05:00'), m('option[value="America/Bahia"]', 'America/Bahia - GMT -03:00'), m('option[value="America/Bahia_Banderas"]', 'America/Bahia_Banderas - GMT -07:00'), m('option[value="America/Barbados"]', 'America/Barbados - GMT -04:00'), m('option[value="America/Belem"]', 'America/Belem - GMT -03:00'), m('option[value="America/Belize"]', 'America/Belize - GMT -06:00'), m('option[value="America/Blanc-Sablon"]', 'America/Blanc-Sablon - GMT -04:00'), m('option[value="America/Boa_Vista"]', 'America/Boa_Vista - GMT -04:00'), m('option[value="America/Bogota"]', 'America/Bogota - GMT -05:00'), m('option[value="America/Boise"]', 'America/Boise - GMT -07:00'), m('option[value="America/Cambridge_Bay"]', 'America/Cambridge_Bay - GMT -07:00'), m('option[value="America/Campo_Grande"]', 'America/Campo_Grande - GMT -04:00'), m('option[value="America/Cancun"]', 'America/Cancun - GMT -06:00'), m('option[value="America/Caracas"]', 'America/Caracas - GMT -04:00'), m('option[value="America/Cayenne"]', 'America/Cayenne - GMT -03:00'), m('option[value="America/Cayman"]', 'America/Cayman - GMT -05:00'), m('option[value="America/Chicago"]', 'America/Chicago - GMT -06:00'), m('option[value="America/Chihuahua"]', 'America/Chihuahua - GMT -06:00'), m('option[value="America/Costa_Rica"]', 'America/Costa_Rica - GMT -06:00'), m('option[value="America/Creston"]', 'America/Creston - GMT -07:00'), m('option[value="America/Cuiaba"]', 'America/Cuiaba - GMT -04:00'), m('option[value="America/Curacao"]', 'America/Curacao - GMT -04:00'), m('option[value="America/Danmarkshavn"]', 'America/Danmarkshavn - GMT -03:00'), m('option[value="America/Dawson"]', 'America/Dawson - GMT -09:00'), m('option[value="America/Dawson_Creek"]', 'America/Dawson_Creek - GMT -08:00'), m('option[value="America/Denver"]', 'America/Denver - GMT -07:00'), m('option[value="America/Detroit"]', 'America/Detroit - GMT -05:00'), m('option[value="America/Dominica"]', 'America/Dominica - GMT -04:00'), m('option[value="America/Edmonton"]', 'America/Edmonton - GMT -07:00'), m('option[value="America/Eirunepe"]', 'America/Eirunepe - GMT -05:00'), m('option[value="America/El_Salvador"]', 'America/El_Salvador - GMT -06:00'), m('option[value="America/Fortaleza"]', 'America/Fortaleza - GMT -03:00'), m('option[value="America/Glace_Bay"]', 'America/Glace_Bay - GMT -04:00'), m('option[value="America/Godthab"]', 'America/Godthab - GMT -03:00'), m('option[value="America/Goose_Bay"]', 'America/Goose_Bay - GMT -04:00'), m('option[value="America/Grand_Turk"]', 'America/Grand_Turk - GMT -05:00'), m('option[value="America/Grenada"]', 'America/Grenada - GMT -04:00'), m('option[value="America/Guadeloupe"]', 'America/Guadeloupe - GMT -04:00'), m('option[value="America/Guatemala"]', 'America/Guatemala - GMT -06:00'), m('option[value="America/Guayaquil"]', 'America/Guayaquil - GMT -05:00'), m('option[value="America/Guyana"]', 'America/Guyana - GMT -03:45'), m('option[value="America/Halifax"]', 'America/Halifax - GMT -04:00'), m('option[value="America/Havana"]', 'America/Havana - GMT -05:00'), m('option[value="America/Hermosillo"]', 'America/Hermosillo - GMT -07:00'), m('option[value="America/Indiana/Indianapolis"]', 'America/Indiana/Indianapolis - GMT -05:00'), m('option[value="America/Indiana/Knox"]', 'America/Indiana/Knox - GMT -06:00'), m('option[value="America/Indiana/Marengo"]', 'America/Indiana/Marengo - GMT -05:00'), m('option[value="America/Indiana/Petersburg"]', 'America/Indiana/Petersburg - GMT -06:00'), m('option[value="America/Indiana/Tell_City"]', 'America/Indiana/Tell_City - GMT -05:00'), m('option[value="America/Indiana/Vevay"]', 'America/Indiana/Vevay - GMT -05:00'), m('option[value="America/Indiana/Vincennes"]', 'America/Indiana/Vincennes - GMT -05:00'), m('option[value="America/Indiana/Winamac"]', 'America/Indiana/Winamac - GMT -05:00'), m('option[value="America/Inuvik"]', 'America/Inuvik - GMT -08:00'), m('option[value="America/Iqaluit"]', 'America/Iqaluit - GMT -05:00'), m('option[value="America/Jamaica"]', 'America/Jamaica - GMT -05:00'), m('option[value="America/Juneau"]', 'America/Juneau - GMT -08:00'), m('option[value="America/Kentucky/Louisville"]', 'America/Kentucky/Louisville - GMT -05:00'), m('option[value="America/Kentucky/Monticello"]', 'America/Kentucky/Monticello - GMT -06:00'), m('option[value="America/Kralendijk"]', 'America/Kralendijk - GMT -04:00'), m('option[value="America/La_Paz"]', 'America/La_Paz - GMT -04:00'), m('option[value="America/Lima"]', 'America/Lima - GMT -05:00'), m('option[value="America/Los_Angeles"]', 'America/Los_Angeles - GMT -08:00'), m('option[value="America/Lower_Princes"]', 'America/Lower_Princes - GMT -04:00'), m('option[value="America/Maceio"]', 'America/Maceio - GMT -03:00'), m('option[value="America/Managua"]', 'America/Managua - GMT -06:00'), m('option[value="America/Manaus"]', 'America/Manaus - GMT -04:00'), m('option[value="America/Marigot"]', 'America/Marigot - GMT -04:00'), m('option[value="America/Martinique"]', 'America/Martinique - GMT -04:00'), m('option[value="America/Matamoros"]', 'America/Matamoros - GMT -06:00'), m('option[value="America/Mazatlan"]', 'America/Mazatlan - GMT -07:00'), m('option[value="America/Menominee"]', 'America/Menominee - GMT -05:00'), m('option[value="America/Merida"]', 'America/Merida - GMT -06:00'), m('option[value="America/Metlakatla"]', 'America/Metlakatla - GMT -08:00'), m('option[value="America/Mexico_City"]', 'America/Mexico_City - GMT -06:00'), m('option[value="America/Miquelon"]', 'America/Miquelon - GMT -04:00'), m('option[value="America/Moncton"]', 'America/Moncton - GMT -04:00'), m('option[value="America/Monterrey"]', 'America/Monterrey - GMT -06:00'), m('option[value="America/Montevideo"]', 'America/Montevideo - GMT -03:00'), m('option[value="America/Montserrat"]', 'America/Montserrat - GMT -04:00'), m('option[value="America/Nassau"]', 'America/Nassau - GMT -05:00'), m('option[value="America/New_York"]', 'America/New_York - GMT -05:00'), m('option[value="America/Nipigon"]', 'America/Nipigon - GMT -05:00'), m('option[value="America/Nome"]', 'America/Nome - GMT -11:00'), m('option[value="America/Noronha"]', 'America/Noronha - GMT -02:00'), m('option[value="America/North_Dakota/Beulah"]', 'America/North_Dakota/Beulah - GMT -07:00'), m('option[value="America/North_Dakota/Center"]', 'America/North_Dakota/Center - GMT -07:00'), m('option[value="America/North_Dakota/New_Salem"]', 'America/North_Dakota/New_Salem - GMT -07:00'), m('option[value="America/Ojinaga"]', 'America/Ojinaga - GMT -06:00'), m('option[value="America/Panama"]', 'America/Panama - GMT -05:00'), m('option[value="America/Pangnirtung"]', 'America/Pangnirtung - GMT -04:00'), m('option[value="America/Paramaribo"]', 'America/Paramaribo - GMT -03:30'), m('option[value="America/Phoenix"]', 'America/Phoenix - GMT -07:00'), m('option[value="America/Port-au-Prince"]', 'America/Port-au-Prince - GMT -05:00'), m('option[value="America/Port_of_Spain"]', 'America/Port_of_Spain - GMT -04:00'), m('option[value="America/Porto_Velho"]', 'America/Porto_Velho - GMT -04:00'), m('option[value="America/Puerto_Rico"]', 'America/Puerto_Rico - GMT -04:00'), m('option[value="America/Rainy_River"]', 'America/Rainy_River - GMT -06:00'), m('option[value="America/Rankin_Inlet"]', 'America/Rankin_Inlet - GMT -06:00'), m('option[value="America/Recife"]', 'America/Recife - GMT -03:00'), m('option[value="America/Regina"]', 'America/Regina - GMT -06:00'), m('option[value="America/Resolute"]', 'America/Resolute - GMT -06:00'), m('option[value="America/Rio_Branco"]', 'America/Rio_Branco - GMT -05:00'), m('option[value="America/Santa_Isabel"]', 'America/Santa_Isabel - GMT -08:00'), m('option[value="America/Santarem"]', 'America/Santarem - GMT -04:00'), m('option[value="America/Santiago"]', 'America/Santiago - GMT -03:00'), m('option[value="America/Santo_Domingo"]', 'America/Santo_Domingo - GMT -04:30'), m('option[value="America/Sao_Paulo"]', 'America/Sao_Paulo - GMT -03:00'), m('option[value="America/Scoresbysund"]', 'America/Scoresbysund - GMT -02:00'), m('option[value="America/Sitka"]', 'America/Sitka - GMT -08:00'), m('option[value="America/St_Barthelemy"]', 'America/St_Barthelemy - GMT -04:00'), m('option[value="America/St_Johns"]', 'America/St_Johns - GMT -03:30'), m('option[value="America/St_Kitts"]', 'America/St_Kitts - GMT -04:00'), m('option[value="America/St_Lucia"]', 'America/St_Lucia - GMT -04:00'), m('option[value="America/St_Thomas"]', 'America/St_Thomas - GMT -04:00'), m('option[value="America/St_Vincent"]', 'America/St_Vincent - GMT -04:00'), m('option[value="America/Swift_Current"]', 'America/Swift_Current - GMT -07:00'), m('option[value="America/Tegucigalpa"]', 'America/Tegucigalpa - GMT -06:00'), m('option[value="America/Thule"]', 'America/Thule - GMT -04:00'), m('option[value="America/Thunder_Bay"]', 'America/Thunder_Bay - GMT -05:00'), m('option[value="America/Tijuana"]', 'America/Tijuana - GMT -08:00'), m('option[value="America/Toronto"]', 'America/Toronto - GMT -05:00'), m('option[value="America/Tortola"]', 'America/Tortola - GMT -04:00'), m('option[value="America/Vancouver"]', 'America/Vancouver - GMT -08:00'), m('option[value="America/Whitehorse"]', 'America/Whitehorse - GMT -08:00'), m('option[value="America/Winnipeg"]', 'America/Winnipeg - GMT -06:00'), m('option[value="America/Yakutat"]', 'America/Yakutat - GMT -09:00'), m('option[value="America/Yellowknife"]', 'America/Yellowknife - GMT -07:00'), m('option[value="Antarctica/Casey"]', 'Antarctica/Casey - GMT +08:00'), m('option[value="Antarctica/Davis"]', 'Antarctica/Davis - GMT +07:00'), m('option[value="Antarctica/DumontDUrville"]', 'Antarctica/DumontDUrville - GMT +10:00'), m('option[value="Antarctica/Macquarie"]', 'Antarctica/Macquarie - GMT +11:00'), m('option[value="Antarctica/Mawson"]', 'Antarctica/Mawson - GMT +06:00'), m('option[value="Antarctica/McMurdo"]', 'Antarctica/McMurdo - GMT +12:00'), m('option[value="Antarctica/Palmer"]', 'Antarctica/Palmer - GMT -03:00'), m('option[value="Antarctica/Rothera"]', 'Antarctica/Rothera - GMT +00:00'), m('option[value="Antarctica/Syowa"]', 'Antarctica/Syowa - GMT +03:00'), m('option[value="Antarctica/Troll"]', 'Antarctica/Troll - GMT +00:00'), m('option[value="Antarctica/Vostok"]', 'Antarctica/Vostok - GMT +06:00'), m('option[value="Arctic/Longyearbyen"]', 'Arctic/Longyearbyen - GMT +01:00'), m('option[value="Asia/Aden"]', 'Asia/Aden - GMT +03:00'), m('option[value="Asia/Almaty"]', 'Asia/Almaty - GMT +06:00'), m('option[value="Asia/Amman"]', 'Asia/Amman - GMT +02:00'), m('option[value="Asia/Anadyr"]', 'Asia/Anadyr - GMT +13:00'), m('option[value="Asia/Aqtau"]', 'Asia/Aqtau - GMT +05:00'), m('option[value="Asia/Aqtobe"]', 'Asia/Aqtobe - GMT +05:00'), m('option[value="Asia/Ashgabat"]', 'Asia/Ashgabat - GMT +05:00'), m('option[value="Asia/Baghdad"]', 'Asia/Baghdad - GMT +03:00'), m('option[value="Asia/Bahrain"]', 'Asia/Bahrain - GMT +04:00'), m('option[value="Asia/Baku"]', 'Asia/Baku - GMT +04:00'), m('option[value="Asia/Bangkok"]', 'Asia/Bangkok - GMT +07:00'), m('option[value="Asia/Beirut"]', 'Asia/Beirut - GMT +02:00'), m('option[value="Asia/Bishkek"]', 'Asia/Bishkek - GMT +06:00'), m('option[value="Asia/Brunei"]', 'Asia/Brunei - GMT +08:00'), m('option[value="Asia/Chita"]', 'Asia/Chita - GMT +09:00'), m('option[value="Asia/Choibalsan"]', 'Asia/Choibalsan - GMT +07:00'), m('option[value="Asia/Colombo"]', 'Asia/Colombo - GMT +05:30'), m('option[value="Asia/Damascus"]', 'Asia/Damascus - GMT +02:00'), m('option[value="Asia/Dhaka"]', 'Asia/Dhaka - GMT +06:00'), m('option[value="Asia/Dili"]', 'Asia/Dili - GMT +09:00'), m('option[value="Asia/Dubai"]', 'Asia/Dubai - GMT +04:00'), m('option[value="Asia/Dushanbe"]', 'Asia/Dushanbe - GMT +06:00'), m('option[value="Asia/Gaza"]', 'Asia/Gaza - GMT +02:00'), m('option[value="Asia/Hebron"]', 'Asia/Hebron - GMT +02:00'), m('option[value="Asia/Ho_Chi_Minh"]', 'Asia/Ho_Chi_Minh - GMT +07:00'), m('option[value="Asia/Hong_Kong"]', 'Asia/Hong_Kong - GMT +08:00'), m('option[value="Asia/Hovd"]', 'Asia/Hovd - GMT +06:00'), m('option[value="Asia/Irkutsk"]', 'Asia/Irkutsk - GMT +08:00'), m('option[value="Asia/Jakarta"]', 'Asia/Jakarta - GMT +07:00'), m('option[value="Asia/Jayapura"]', 'Asia/Jayapura - GMT +09:00'), m('option[value="Asia/Jerusalem"]', 'Asia/Jerusalem - GMT +02:00'), m('option[value="Asia/Kabul"]', 'Asia/Kabul - GMT +04:30'), m('option[value="Asia/Kamchatka"]', 'Asia/Kamchatka - GMT +12:00'), m('option[value="Asia/Karachi"]', 'Asia/Karachi - GMT +05:00'), m('option[value="Asia/Kathmandu"]', 'Asia/Kathmandu - GMT +05:30'), m('option[value="Asia/Khandyga"]', 'Asia/Khandyga - GMT +09:00'), m('option[value="Asia/Kolkata"]', 'Asia/Kolkata - GMT +05:30'), m('option[value="Asia/Krasnoyarsk"]', 'Asia/Krasnoyarsk - GMT +07:00'), m('option[value="Asia/Kuala_Lumpur"]', 'Asia/Kuala_Lumpur - GMT +07:30'), m('option[value="Asia/Kuching"]', 'Asia/Kuching - GMT +08:00'), m('option[value="Asia/Kuwait"]', 'Asia/Kuwait - GMT +03:00'), m('option[value="Asia/Macau"]', 'Asia/Macau - GMT +08:00'), m('option[value="Asia/Magadan"]', 'Asia/Magadan - GMT +11:00'), m('option[value="Asia/Makassar"]', 'Asia/Makassar - GMT +08:00'), m('option[value="Asia/Manila"]', 'Asia/Manila - GMT +08:00'), m('option[value="Asia/Muscat"]', 'Asia/Muscat - GMT +04:00'), m('option[value="Asia/Nicosia"]', 'Asia/Nicosia - GMT +02:00'), m('option[value="Asia/Novokuznetsk"]', 'Asia/Novokuznetsk - GMT +07:00'), m('option[value="Asia/Novosibirsk"]', 'Asia/Novosibirsk - GMT +07:00'), m('option[value="Asia/Omsk"]', 'Asia/Omsk - GMT +06:00'), m('option[value="Asia/Oral"]', 'Asia/Oral - GMT +05:00'), m('option[value="Asia/Phnom_Penh"]', 'Asia/Phnom_Penh - GMT +07:00'), m('option[value="Asia/Pontianak"]', 'Asia/Pontianak - GMT +08:00'), m('option[value="Asia/Pyongyang"]', 'Asia/Pyongyang - GMT +09:00'), m('option[value="Asia/Qatar"]', 'Asia/Qatar - GMT +04:00'), m('option[value="Asia/Qyzylorda"]', 'Asia/Qyzylorda - GMT +05:00'), m('option[value="Asia/Rangoon"]', 'Asia/Rangoon - GMT +06:30'), m('option[value="Asia/Riyadh"]', 'Asia/Riyadh - GMT +03:00'), m('option[value="Asia/Sakhalin"]', 'Asia/Sakhalin - GMT +11:00'), m('option[value="Asia/Samarkand"]', 'Asia/Samarkand - GMT +05:00'), m('option[value="Asia/Seoul"]', 'Asia/Seoul - GMT +09:00'), m('option[value="Asia/Shanghai"]', 'Asia/Shanghai - GMT +08:00'), m('option[value="Asia/Singapore"]', 'Asia/Singapore - GMT +07:30'), m('option[value="Asia/Srednekolymsk"]', 'Asia/Srednekolymsk - GMT +11:00'), m('option[value="Asia/Taipei"]', 'Asia/Taipei - GMT +08:00'), m('option[value="Asia/Tashkent"]', 'Asia/Tashkent - GMT +06:00'), m('option[value="Asia/Tbilisi"]', 'Asia/Tbilisi - GMT +04:00'), m('option[value="Asia/Tehran"]', 'Asia/Tehran - GMT +03:30'), m('option[value="Asia/Thimphu"]', 'Asia/Thimphu - GMT +05:30'), m('option[value="Asia/Tokyo"]', 'Asia/Tokyo - GMT +09:00'), m('option[value="Asia/Ulaanbaatar"]', 'Asia/Ulaanbaatar - GMT +07:00'), m('option[value="Asia/Urumqi"]', 'Asia/Urumqi - GMT +06:00'), m('option[value="Asia/Ust-Nera"]', 'Asia/Ust-Nera - GMT +09:00'), m('option[value="Asia/Vientiane"]', 'Asia/Vientiane - GMT +07:00'), m('option[value="Asia/Vladivostok"]', 'Asia/Vladivostok - GMT +10:00'), m('option[value="Asia/Yakutsk"]', 'Asia/Yakutsk - GMT +09:00'), m('option[value="Asia/Yekaterinburg"]', 'Asia/Yekaterinburg - GMT +05:00'), m('option[value="Asia/Yerevan"]', 'Asia/Yerevan - GMT +04:00'), m('option[value="Atlantic/Azores"]', 'Atlantic/Azores - GMT -01:00'), m('option[value="Atlantic/Bermuda"]', 'Atlantic/Bermuda - GMT -04:00'), m('option[value="Atlantic/Canary"]', 'Atlantic/Canary - GMT +00:00'), m('option[value="Atlantic/Cape_Verde"]', 'Atlantic/Cape_Verde - GMT -02:00'), m('option[value="Atlantic/Faroe"]', 'Atlantic/Faroe - GMT +00:00'), m('option[value="Atlantic/Madeira"]', 'Atlantic/Madeira - GMT +00:00'), m('option[value="Atlantic/Reykjavik"]', 'Atlantic/Reykjavik - GMT +00:00'), m('option[value="Atlantic/South_Georgia"]', 'Atlantic/South_Georgia - GMT -02:00'), m('option[value="Atlantic/St_Helena"]', 'Atlantic/St_Helena - GMT +00:00'), m('option[value="Atlantic/Stanley"]', 'Atlantic/Stanley - GMT -04:00'), m('option[value="Australia/Adelaide"]', 'Australia/Adelaide - GMT +09:30'), m('option[value="Australia/Brisbane"]', 'Australia/Brisbane - GMT +10:00'), m('option[value="Australia/Broken_Hill"]', 'Australia/Broken_Hill - GMT +09:30'), m('option[value="Australia/Currie"]', 'Australia/Currie - GMT +10:00'), m('option[value="Australia/Darwin"]', 'Australia/Darwin - GMT +09:30'), m('option[value="Australia/Eucla"]', 'Australia/Eucla - GMT +08:45'), m('option[value="Australia/Hobart"]', 'Australia/Hobart - GMT +11:00'), m('option[value="Australia/Lindeman"]', 'Australia/Lindeman - GMT +10:00'), m('option[value="Australia/Lord_Howe"]', 'Australia/Lord_Howe - GMT +10:00'), m('option[value="Australia/Melbourne"]', 'Australia/Melbourne - GMT +10:00'), m('option[value="Australia/Perth"]', 'Australia/Perth - GMT +08:00'), m('option[value="Australia/Sydney"]', 'Australia/Sydney - GMT +10:00'), m('option[value="Europe/Amsterdam"]', 'Europe/Amsterdam - GMT +01:00'), m('option[value="Europe/Andorra"]', 'Europe/Andorra - GMT +01:00'), m('option[value="Europe/Athens"]', 'Europe/Athens - GMT +02:00'), m('option[value="Europe/Belgrade"]', 'Europe/Belgrade - GMT +01:00'), m('option[value="Europe/Berlin"]', 'Europe/Berlin - GMT +01:00'), m('option[value="Europe/Bratislava"]', 'Europe/Bratislava - GMT +01:00'), m('option[value="Europe/Brussels"]', 'Europe/Brussels - GMT +01:00'), m('option[value="Europe/Bucharest"]', 'Europe/Bucharest - GMT +02:00'), m('option[value="Europe/Budapest"]', 'Europe/Budapest - GMT +01:00'), m('option[value="Europe/Busingen"]', 'Europe/Busingen - GMT +01:00'), m('option[value="Europe/Chisinau"]', 'Europe/Chisinau - GMT +03:00'), m('option[value="Europe/Copenhagen"]', 'Europe/Copenhagen - GMT +01:00'), m('option[value="Europe/Dublin"]', 'Europe/Dublin - GMT +01:00'), m('option[value="Europe/Gibraltar"]', 'Europe/Gibraltar - GMT +01:00'), m('option[value="Europe/Guernsey"]', 'Europe/Guernsey - GMT +01:00'), m('option[value="Europe/Helsinki"]', 'Europe/Helsinki - GMT +02:00'), m('option[value="Europe/Isle_of_Man"]', 'Europe/Isle_of_Man - GMT +01:00'), m('option[value="Europe/Istanbul"]', 'Europe/Istanbul - GMT +02:00'), m('option[value="Europe/Jersey"]', 'Europe/Jersey - GMT +01:00'), m('option[value="Europe/Kaliningrad"]', 'Europe/Kaliningrad - GMT +03:00'), m('option[value="Europe/Kiev"]', 'Europe/Kiev - GMT +03:00'), m('option[value="Europe/Lisbon"]', 'Europe/Lisbon - GMT +01:00'), m('option[value="Europe/Ljubljana"]', 'Europe/Ljubljana - GMT +01:00'), m('option[value="Europe/London"]', 'Europe/London - GMT +01:00'), m('option[value="Europe/Luxembourg"]', 'Europe/Luxembourg - GMT +01:00'), m('option[value="Europe/Madrid"]', 'Europe/Madrid - GMT +01:00'), m('option[value="Europe/Malta"]', 'Europe/Malta - GMT +01:00'), m('option[value="Europe/Mariehamn"]', 'Europe/Mariehamn - GMT +02:00'), m('option[value="Europe/Minsk"]', 'Europe/Minsk - GMT +03:00'), m('option[value="Europe/Monaco"]', 'Europe/Monaco - GMT +01:00'), m('option[value="Europe/Moscow"]', 'Europe/Moscow - GMT +03:00'), m('option[value="Europe/Oslo"]', 'Europe/Oslo - GMT +01:00'), m('option[value="Europe/Paris"]', 'Europe/Paris - GMT +01:00'), m('option[value="Europe/Podgorica"]', 'Europe/Podgorica - GMT +01:00'), m('option[value="Europe/Prague"]', 'Europe/Prague - GMT +01:00'), m('option[value="Europe/Riga"]', 'Europe/Riga - GMT +03:00'), m('option[value="Europe/Rome"]', 'Europe/Rome - GMT +01:00'), m('option[value="Europe/Samara"]', 'Europe/Samara - GMT +04:00'), m('option[value="Europe/San_Marino"]', 'Europe/San_Marino - GMT +01:00'), m('option[value="Europe/Sarajevo"]', 'Europe/Sarajevo - GMT +01:00'), m('option[value="Europe/Simferopol"]', 'Europe/Simferopol - GMT +03:00'), m('option[value="Europe/Skopje"]', 'Europe/Skopje - GMT +01:00'), m('option[value="Europe/Sofia"]', 'Europe/Sofia - GMT +02:00'), m('option[value="Europe/Stockholm"]', 'Europe/Stockholm - GMT +01:00'), m('option[value="Europe/Tallinn"]', 'Europe/Tallinn - GMT +03:00'), m('option[value="Europe/Tirane"]', 'Europe/Tirane - GMT +01:00'), m('option[value="Europe/Uzhgorod"]', 'Europe/Uzhgorod - GMT +03:00'), m('option[value="Europe/Vaduz"]', 'Europe/Vaduz - GMT +01:00'), m('option[value="Europe/Vatican"]', 'Europe/Vatican - GMT +01:00'), m('option[value="Europe/Vienna"]', 'Europe/Vienna - GMT +01:00'), m('option[value="Europe/Vilnius"]', 'Europe/Vilnius - GMT +03:00'), m('option[value="Europe/Volgograd"]', 'Europe/Volgograd - GMT +04:00'), m('option[value="Europe/Warsaw"]', 'Europe/Warsaw - GMT +01:00'), m('option[value="Europe/Zagreb"]', 'Europe/Zagreb - GMT +01:00'), m('option[value="Europe/Zaporozhye"]', 'Europe/Zaporozhye - GMT +03:00'), m('option[value="Europe/Zurich"]', 'Europe/Zurich - GMT +01:00'), m('option[value="Indian/Antananarivo"]', 'Indian/Antananarivo - GMT +03:00'), m('option[value="Indian/Chagos"]', 'Indian/Chagos - GMT +05:00'), m('option[value="Indian/Christmas"]', 'Indian/Christmas - GMT +07:00'), m('option[value="Indian/Cocos"]', 'Indian/Cocos - GMT +06:30'), m('option[value="Indian/Comoro"]', 'Indian/Comoro - GMT +03:00'), m('option[value="Indian/Kerguelen"]', 'Indian/Kerguelen - GMT +05:00'), m('option[value="Indian/Mahe"]', 'Indian/Mahe - GMT +04:00'), m('option[value="Indian/Maldives"]', 'Indian/Maldives - GMT +05:00'), m('option[value="Indian/Mauritius"]', 'Indian/Mauritius - GMT +04:00'), m('option[value="Indian/Mayotte"]', 'Indian/Mayotte - GMT +03:00'), m('option[value="Indian/Reunion"]', 'Indian/Reunion - GMT +04:00'), m('option[value="Pacific/Apia"]', 'Pacific/Apia - GMT -11:00'), m('option[value="Pacific/Auckland"]', 'Pacific/Auckland - GMT +12:00'), m('option[value="Pacific/Chatham"]', 'Pacific/Chatham - GMT +12:45'), m('option[value="Pacific/Chuuk"]', 'Pacific/Chuuk - GMT +10:00'), m('option[value="Pacific/Easter"]', 'Pacific/Easter - GMT -06:00'), m('option[value="Pacific/Efate"]', 'Pacific/Efate - GMT +11:00'), m('option[value="Pacific/Enderbury"]', 'Pacific/Enderbury - GMT -12:00'), m('option[value="Pacific/Fakaofo"]', 'Pacific/Fakaofo - GMT -11:00'), m('option[value="Pacific/Fiji"]', 'Pacific/Fiji - GMT +12:00'), m('option[value="Pacific/Funafuti"]', 'Pacific/Funafuti - GMT +12:00'), m('option[value="Pacific/Galapagos"]', 'Pacific/Galapagos - GMT -05:00'), m('option[value="Pacific/Gambier"]', 'Pacific/Gambier - GMT -09:00'), m('option[value="Pacific/Guadalcanal"]', 'Pacific/Guadalcanal - GMT +11:00'), m('option[value="Pacific/Guam"]', 'Pacific/Guam - GMT +10:00'), m('option[value="Pacific/Honolulu"]', 'Pacific/Honolulu - GMT -10:00'), m('option[value="Pacific/Johnston"]', 'Pacific/Johnston - GMT -10:00'), m('option[value="Pacific/Kiritimati"]', 'Pacific/Kiritimati - GMT -10:40'), m('option[value="Pacific/Kosrae"]', 'Pacific/Kosrae - GMT +12:00'), m('option[value="Pacific/Kwajalein"]', 'Pacific/Kwajalein - GMT -12:00'), m('option[value="Pacific/Majuro"]', 'Pacific/Majuro - GMT +12:00'), m('option[value="Pacific/Marquesas"]', 'Pacific/Marquesas - GMT -09:30'), m('option[value="Pacific/Midway"]', 'Pacific/Midway - GMT -11:00'), m('option[value="Pacific/Nauru"]', 'Pacific/Nauru - GMT +11:30'), m('option[value="Pacific/Niue"]', 'Pacific/Niue - GMT -11:30'), m('option[value="Pacific/Norfolk"]', 'Pacific/Norfolk - GMT +11:30'), m('option[value="Pacific/Noumea"]', 'Pacific/Noumea - GMT +11:00'), m('option[value="Pacific/Pago_Pago"]', 'Pacific/Pago_Pago - GMT -11:00'), m('option[value="Pacific/Palau"]', 'Pacific/Palau - GMT +09:00'), m('option[value="Pacific/Pitcairn"]', 'Pacific/Pitcairn - GMT -08:30'), m('option[value="Pacific/Pohnpei"]', 'Pacific/Pohnpei - GMT +11:00'), m('option[value="Pacific/Port_Moresby"]', 'Pacific/Port_Moresby - GMT +10:00'), m('option[value="Pacific/Rarotonga"]', 'Pacific/Rarotonga - GMT -10:30'), m('option[value="Pacific/Saipan"]', 'Pacific/Saipan - GMT +10:00'), m('option[value="Pacific/Tahiti"]', 'Pacific/Tahiti - GMT -10:00'), m('option[value="Pacific/Tarawa"]', 'Pacific/Tarawa - GMT +12:00'), m('option[value="Pacific/Tongatapu"]', 'Pacific/Tongatapu - GMT +13:00'), m('option[value="Pacific/Wake"]', 'Pacific/Wake - GMT +12:00'), m('option[value="Pacific/Wallis"]', 'Pacific/Wallis - GMT +12:00'), m('option[value="UTC"]', 'UTC - GMT +00:00')]), m('span.help-block', 'Set the system timezone.') ]) diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 125ac7aa..f72ed51c 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -786,4 +786,4 @@ $redis->pconnect('/tmp/redis.sock'); } // end while loop // --- WORKER MAIN LOOP // // close Redis connection -$redis->close(); +$redis->close(); \ No newline at end of file From d832e37356f0947faf4d83f13e6ec0fdfc6a2be3 Mon Sep 17 00:00:00 2001 From: Kevin Welsh Date: Thu, 8 Jan 2015 00:07:06 -0500 Subject: [PATCH 57/80] Bug fix for Queue Position --- assets/js/runeui.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/assets/js/runeui.js b/assets/js/runeui.js index 5059e11e..e511692a 100644 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -224,12 +224,10 @@ function volumeStepSet() { // highlight the current track in the queue function setQueuePos() { if (queueTracks.length !== 0 && GUI.currentqueuepos !== parseInt(GUI.json.song)) { - if (GUI.currentqueuepos) { - queueTracks[GUI.currentqueuepos].current = false; - GUI.currentqueuepos = parseInt(GUI.json.song); - queueTracks[GUI.currentqueuepos].current = true; - m.redraw(); - } + queueTracks[GUI.currentqueuepos].current = false; + GUI.currentqueuepos = parseInt(GUI.json.song); + queueTracks[GUI.currentqueuepos].current = true; + m.redraw(); } } From 048ff3c8ad10cdcabb3148253254e6e91f2754a9 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Fri, 9 Jan 2015 04:04:18 +0100 Subject: [PATCH 58/80] Activated playbackChannel --- assets/js/runeui._init.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/assets/js/runeui._init.js b/assets/js/runeui._init.js index 11747d15..114887e2 100644 --- a/assets/js/runeui._init.js +++ b/assets/js/runeui._init.js @@ -119,6 +119,12 @@ function renderMSG(text) { } } +// process the status update data +function renderUI(text){ + GUI.json = text[0]; + console.log(GUI.json); +} + // open the Playback UI refresh channel function playbackChannel(){ var pushstream = new PushStream({ @@ -128,6 +134,7 @@ function playbackChannel(){ reconnectOnChannelUnavailableInterval: 5000 }); pushstream.onmessage = renderUI; + /* pushstream.onstatuschange = function(status) { // console.log('[nginx pushtream module] status = ', status); if (status === 2) { @@ -141,6 +148,7 @@ function playbackChannel(){ } } }; + */ // pushstream.onerror = function() { // toggleLoader(); // console.log('[nginx pushtream module] error'); @@ -226,7 +234,7 @@ jQuery(document).ready(function ($) { 'use strict'; // first connection with MPD daemon // open UI rendering channel; - // playbackChannel(); + playbackChannel(); // PNotify init options PNotify.prototype.options.styling = 'fontawesome'; From f2946eb989b26c2db08a953a535f977bd340f725 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Fri, 9 Jan 2015 22:58:47 +0100 Subject: [PATCH 59/80] Top playback buttons --- app/templates/footer.php | 1 + app/templates/header.php | 4 + assets/css/runeui.css | 2 +- assets/js/runeui._helpers.js | 11 +- assets/js/runeui._init.js | 12 +- assets/js/runeui._playback_controls.js | 88 +++++++++++++ assets/js/runeui.audio.js | 166 +++++++++++++------------ assets/js/runeui.min.js | 2 +- assets/less/runeui-fonts.less | 11 -- 9 files changed, 197 insertions(+), 100 deletions(-) create mode 100644 assets/js/runeui._playback_controls.js diff --git a/app/templates/footer.php b/app/templates/footer.php index 2a9a5019..b75918c9 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -50,6 +50,7 @@ + diff --git a/app/templates/header.php b/app/templates/header.php index 726dba82..b8e6e432 100644 --- a/app/templates/header.php +++ b/app/templates/header.php @@ -85,12 +85,16 @@ + section !== 'config'): ?>
    + +
    + ",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) }}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;bback')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageYold=0,pageYdiff=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){isCustomScroll||(pageY=window.pageYOffset,pageYdiff=Math.abs(pageYold-pageY),pageYdiff>6*pageHeight&&(pageYold=pageY,console.log("REDRAW ",pageY),m.redraw()))},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=8,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file diff --git a/assets/less/runeui-fonts.less b/assets/less/runeui-fonts.less index 978a96f7..a07e93e5 100644 --- a/assets/less/runeui-fonts.less +++ b/assets/less/runeui-fonts.less @@ -9,17 +9,6 @@ font-style: normal; } -@font-face { - font-family: 'Lato'; - src: url('../fonts/lato/lato-bolditalic-webfont.eot'); - src: url('../fonts/lato/lato-bolditalic-webfont.eot?#iefix') format('embedded-opentype'), - url('../fonts/lato/lato-bolditalic-webfont.woff') format('woff'), - url('../fonts/lato/lato-bolditalic-webfont.ttf') format('truetype'), - url('../fonts/lato/lato-bolditalic-webfont.svg#latobold_italic') format('svg'); - font-weight: bold; - font-style: italic; -} - @font-face { font-family: 'Lato'; src: url('../fonts/lato/lato-italic-webfont.eot'); From 11c4ccfe1dbe446b8e5d29811ed67566273d4cb8 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sat, 10 Jan 2015 05:42:16 +0100 Subject: [PATCH 60/80] Loading layers (blocking and non-blocking) --- app/templates/config.php | 1 + app/templates/footer.php | 2 +- assets/js/runeui._data.js | 9 +++++---- assets/js/runeui._helpers.js | 19 ++++++++++++++----- assets/js/runeui._init.js | 2 ++ assets/js/runeui._mithril.js | 10 +++++----- assets/js/runeui.audio.js | 14 +++++++------- assets/js/runeui.navigation.js | 5 +++-- ...ontrols.js => runeui.playback_controls.js} | 0 9 files changed, 38 insertions(+), 24 deletions(-) rename assets/js/{runeui._playback_controls.js => runeui.playback_controls.js} (100%) diff --git a/app/templates/config.php b/app/templates/config.php index 4a9a62f2..964f095a 100644 --- a/app/templates/config.php +++ b/app/templates/config.php @@ -4,4 +4,5 @@
    connecting...
    +
    \ No newline at end of file diff --git a/app/templates/footer.php b/app/templates/footer.php index b75918c9..4591f72d 100644 --- a/app/templates/footer.php +++ b/app/templates/footer.php @@ -50,8 +50,8 @@ - + diff --git a/assets/js/runeui._data.js b/assets/js/runeui._data.js index 0345baf6..dc2e7d2f 100644 --- a/assets/js/runeui._data.js +++ b/assets/js/runeui._data.js @@ -7,9 +7,10 @@ data.getData = function (vm) { if (vm.id) { url += '/' + vm.id; } - helpers.toggleLoader('open'); + helpers.toggleLoader('open', ''); var loaderClose = function () { helpers.toggleLoader('close'); + // console.log('SUCCESS'); }; var loaderCloseFail = function () { console.log('FAIL'); @@ -24,9 +25,9 @@ data.getData = function (vm) { data.postData = function (url, data) { console.log(url); console.log(data); - helpers.toggleLoader('open'); + helpers.toggleLoader('open', 'blocking'); var loaderClose = function () { - helpers.toggleLoader('close'); + helpers.toggleLoader('close', 'blocking'); }; var loaderCloseFail = function () { console.log('FAIL'); @@ -39,7 +40,7 @@ data.postData = function (url, data) { return; }, unwrapError: function (response) { - return "oops"; + return 'oops'; }, // PHP errors are not wrapped in Proper JSON,. breaking Mitrhil deserialize: function (value) { return value; } diff --git a/assets/js/runeui._helpers.js b/assets/js/runeui._helpers.js index cddc60fa..a0f80a4f 100644 --- a/assets/js/runeui._helpers.js +++ b/assets/js/runeui._helpers.js @@ -3,20 +3,29 @@ window.helpers = window.helpers || {}; -// toggle blocking loading layer (spinning arrows) -helpers.toggleLoader = function (action) { +// toggle loading layers (spinning arrows and circle) +helpers.toggleLoader = function(action, type) { + console.log(type); + var div, style; + if (type === 'blocking') { + div = '#loader'; + style = 'hide'; + } else { + div = '#loader-spinner'; + style = 'hide'; + } if (action === 'close') { - $('#loader').addClass('hide'); + $(div).addClass('hide'); } else { if ($('#section-dev').length) { - $('#loader').addClass('hide'); + $(div).addClass('hide'); new PNotify({ title: 'Warning', text: 'The loading layer (spinning arrows) points to a socket error', icon: 'fa fa-exclamation-circle' }); } else { - $('#loader').removeClass('hide'); + $(div).removeClass('hide'); } } }; diff --git a/assets/js/runeui._init.js b/assets/js/runeui._init.js index c39fc72f..6f9cd5de 100644 --- a/assets/js/runeui._init.js +++ b/assets/js/runeui._init.js @@ -227,6 +227,8 @@ function nicsChannel(){ // INIT // ---------------------------------------------------------------------------------------------------- +helpers.toggleLoader('close', 'blocking'); + jQuery(document).ready(function ($) { 'use strict'; // check WebSocket support diff --git a/assets/js/runeui._mithril.js b/assets/js/runeui._mithril.js index 14442d1a..5ab17f29 100644 --- a/assets/js/runeui._mithril.js +++ b/assets/js/runeui._mithril.js @@ -111,7 +111,7 @@ mithril.getViewModel = function (url) { // property 'data' is defined here asnd the loading is set up this.data = data.getData(this); - console.log('* in vm init'); + // console.log('* in vm init'); navigation.vm.navigate(this.url.replace(urlPrefix, '')); // return m.request({ method: 'GET', url: vm.url }).then(function (response) { // vm.data = response; @@ -155,11 +155,11 @@ mithril.getController = function (vm) { var controller = function () { this.id = m.route.param("id"); vm.init(this.id); - helpers.toggleLoader('close'); - console.log('* in controller'); - - this.onunload = function () { + + // console.log('* in controller'); + this.onunload = function() { + // if (!confirm('Are you sure you want to leave this page?')) { e.preventDefault(); } }; }; return controller; diff --git a/assets/js/runeui.audio.js b/assets/js/runeui.audio.js index d0310fa8..a591b8f7 100644 --- a/assets/js/runeui.audio.js +++ b/assets/js/runeui.audio.js @@ -8,10 +8,10 @@ window.audio = new mithril.RuneModule('/audio'); audio.view = function (ctrl) { return [ m('h1', 'Audio Configuration'), - m('fieldset', [ - m('legend', 'Audio Output'), + m('fieldset.form-horizontal', [ + m('legend', 'Audio Output Interface'), m('.form-group', [ - mithril.createLabel('audio-output-interface', 'Audio output interface'), + mithril.createLabel('audio-output-interface', 'Output interface'), m('.col-sm-10', [ mithril.createSelect('audio-output-interface', audio.vm.data, 'ao', 'acards', 'name', 'extlabel', helpers.selectpicker), m('span.help-block', ['This is the current output interface.' @@ -25,7 +25,7 @@ audio.view = function (ctrl) { ]) ]) ]), - m('fieldset', [ + m('fieldset.form-horizontal', [ m('legend', 'Volume control'), m('.form-group', [ m('label.col-sm-2.control-label[for="mixer-type"]', 'Volume control'), @@ -65,10 +65,10 @@ audio.view = function (ctrl) { ]) ]) ]), - m('fieldset', [ - m('legend', 'Sound Signature'), + m('fieldset.form-horizontal', [ + m('legend', 'Sound Signature (optimization profiles)'), m('.form-group', [ - m('label.control-label.col-sm-2[for="orionprofile"]', 'Sound Signature (optimization profiles)'), + m('label.control-label.col-sm-2[for="orionprofile"]', 'Sound Signature'), m('.col-sm-10', [ m('select.selectpicker[data-style="btn-default btn-lg"]', mithril.createInput(audio.vm.data, "orionprofile", helpers.selectpicker), [ m('option[value="default"]', 'ArchLinux default'), diff --git a/assets/js/runeui.navigation.js b/assets/js/runeui.navigation.js index 505c96f7..d58486f2 100644 --- a/assets/js/runeui.navigation.js +++ b/assets/js/runeui.navigation.js @@ -20,6 +20,7 @@ window.navigation = { }; vm.navigate = function (url) { + for (i = 0; i < vm.pages.length - 1; i++) { if (vm.pages[i].url() === url) { vm.pages[i].selected(true); @@ -52,8 +53,8 @@ window.navigation = { ['MENU ', m('i.fa.fa-bars.dx')]), '\n', m('ul.dropdown-menu[aria-labelledby="menu-settings"][role="menu"]', [navigation.vm.pages.map(function (item, index) { return m('li', { className: item.selected() ? 'active' : '' }, - item.url() ? [m('a[href="' + item.url() + '"]', { config: m.route }, [m('i.fa.fa-' + item.icon()), ' ' + item.name()])] : [m('a[href="javascript:;"]', { onclick: function (e) { console.log(e); item.action(); } }, [m('i.fa.fa-' + item.icon()), ' ' + item.name()])]); - })])]; + item.url() ? [m('a[href="' + item.url() + '"]', { config: m.route }, [m('i.fa.fa-' + item.icon()), ' ' + item.name()])] : [m('a[href="javascript:;"]', { onclick: function (e) { item.action(); } }, [m('i.fa.fa-' + item.icon()), ' ' + item.name()])]); + })])]; } }; m.module(document.getElementById('main-menu'), navigation); \ No newline at end of file diff --git a/assets/js/runeui._playback_controls.js b/assets/js/runeui.playback_controls.js similarity index 100% rename from assets/js/runeui._playback_controls.js rename to assets/js/runeui.playback_controls.js From 5a1ef109b0e3f5cea6ca4a664ffa484ff8e2f167 Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sat, 10 Jan 2015 05:45:49 +0100 Subject: [PATCH 61/80] MPD section style --- assets/js/runeui.mpd.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/assets/js/runeui.mpd.js b/assets/js/runeui.mpd.js index 1cb2580d..b76c0b5b 100644 --- a/assets/js/runeui.mpd.js +++ b/assets/js/runeui.mpd.js @@ -132,13 +132,14 @@ mpd.view = function (ctrl) { mithril.createYesNo('auto-update', mpd.vm.data.conf, 'auto_update'), m('span.help-block', 'This setting enables automatic update of MPD"s database when files in music_directory are changed.') ]) - ]) - ]), - m('.form-group.form-actions', [ - m('.col-sm-offset-2.col-sm-10', [ - m('button.btn.btn-default.btn-lg[name="cancel"][value="cancel"][type="button"]', { onclick: function (e) { mpd.vm.cancel('conf'); } }, 'Cancel'), - m('button.btn.btn-primary.btn-lg[name="save"][value="save"][type="button"]', { onclick: function (e) { mpd.vm.save('conf'); } }, 'Save and apply') - ]) + ]), + m('.form-group.form-actions', [ + m('.col-sm-offset-2.col-sm-10', [ + m('button.btn.btn-default.btn-lg[name="cancel"][value="cancel"][type="button"]', { onclick: function (e) { mpd.vm.cancel('conf'); } }, 'Cancel'), ' ', + m('button.btn.btn-primary.btn-lg[name="save"][value="save"][type="button"]', { onclick: function (e) { mpd.vm.save('conf'); } }, 'Save and apply') + ]) + ]) ]) + ]; }; \ No newline at end of file From 652290db9023d6af6c23b4042d3fccf6f4b27092 Mon Sep 17 00:00:00 2001 From: Kevin Welsh Date: Sat, 10 Jan 2015 00:27:13 -0500 Subject: [PATCH 62/80] Progress on the Sources tab. testing tweaks to help ACX. --- .gitignore | 12 +- _TEST/index.html | 110 +++---- app/api/sources_ctl.php | 5 +- app/templates/config.php | 2 +- assets/img/logo.png | Bin 2096 -> 74506 bytes assets/js/runeui._data.js | 1 + assets/js/runeui._helpers.js | 10 +- assets/js/runeui._mithril.js | 4 +- assets/js/runeui._modal.js | 67 +++- assets/js/runeui.min.js | 2 +- assets/js/runeui.mpd.js | 14 +- assets/js/runeui.settings.js | 592 +++++++++++++++++++---------------- assets/js/runeui.sources.js | 107 ++++--- 13 files changed, 528 insertions(+), 398 deletions(-) diff --git a/.gitignore b/.gitignore index d3d6042e..0758dd7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,6 @@ -test/ -sync.ffs_db -node_modules -assets/img/logo.png -Scripts/ -_Test/ +test/ +sync.ffs_db +node_modules +_Test/ app/api/test.php -/.project +/.project \ No newline at end of file diff --git a/_TEST/index.html b/_TEST/index.html index 2ad6e38c..b5394da7 100644 --- a/_TEST/index.html +++ b/_TEST/index.html @@ -1,56 +1,56 @@ - - - - - - - - - - -
    -
    - - - - - + + + + + + + + + + +
    +
    + + + + + \ No newline at end of file diff --git a/app/api/sources_ctl.php b/app/api/sources_ctl.php index e70dbe01..383c1c1a 100644 --- a/app/api/sources_ctl.php +++ b/app/api/sources_ctl.php @@ -77,6 +77,7 @@ $id = $template->arg; // null when the id = 0 if ($id == '0') { + // THe user is doing a GET to setup the UI for a new source $template->nas_name = ''; $template->nas_ip = ''; $template->nas_dir = ''; @@ -89,9 +90,9 @@ if($source !== true) { foreach ($source as $mp) { if (wrk_checkStrSysfile('/proc/mounts', '/mnt/MPD/NAS/'.$mp['name'])) { - $mp['status'] = 1; + $mp['status'] = true; } else { - $mp['status'] = 0; + $mp['status'] = false; } $mounts[]=$mp; } diff --git a/app/templates/config.php b/app/templates/config.php index 4a9a62f2..4f84f30a 100644 --- a/app/templates/config.php +++ b/app/templates/config.php @@ -1,4 +1,4 @@ -
    +
    diff --git a/assets/img/logo.png b/assets/img/logo.png index ea63415fad4b573ccfda4d408cf093e01c0838e7..5823154e2b4aa8df26976caa82e046710af81275 100644 GIT binary patch literal 74506 zcmbq&1A8V-6K-tVwr$&Xp4c1PwzIKq+s?+e?Tzi^?E9Vb4^CfI)m?MXbXU(@UENg^ zsiYtY4}${(1Ox;xEhVP%ug?F+R8SEAq$k~7`o9XySwvb5>R<7JGL87BLpw-mI|Bj1 zqWs6e3)_C5|1RRWh-ub!x zNkh{k`zqa5PFEdkR8dw}Mpx$C`<(tURz)|TXtE#8#Th0hO+I4Kp%F9TK%&$%Yf$9G zd#cpnj}XZS6L=Bxq)((Qhs8nTWtLmUP(}kH4(fkJ5ZgrV)BBo!Im#yimfL;8)9L5s zYRlR0CHEuyl<&pw`J+tmw=xUN{DRb?83b#Eix-9bDs|^liE1&%?4vgG+;YrLO$yef zO~247{#nNbhZmlK^3b+C*7y3x637RHWuz+^dU9g<$74}bC=_1Kd8t48IVF;NwIY<{&w))Kn_>)1py#~VW=*R zhuOD3v_Va4L`T&T&d(NZ>Mcu4aA04 zwL9&zXJ`0g7qBo+Oa@0t7D@e~QBH~=#)9hCJqR4K6OG)2_pb=}>j9{qT@o=8q%m;> zll_8v2S4#?Tr!9@@C$r=(?s8AL{)|Dg8DT9^{YbWisr+JQxQ&}C`YzFf%ZuV{BE(e3uCKQ~CV+a$ZE-nz1^8=9EIp2MIJu77ER8jx1~eceNlEAC`w-ijUis=0sF zaZJghEQ6ex5e!${@xwVijXykW%QfBkIo-)lXuq*kb4Kk8Ip%8U6{;*zo!qZF_eR~# z)=)T(Ie*0N{lr)q<}!#ot`o(jZF#hx7RvB4CNb|c5Q?$ho9ucSwh96?oS0-d_R^`I zKe3$pGynS4Tc9#eMD=mEEGw)<-RrZt_xXhTlRf+PkE)uUvi!O89yIM`J_Jvl1^!Xq zfBM_!|KRM|iR8GxY=7&!l;&fT!071ciyu0>trcTc9hQz;-Sk&~o2Ts8j`gOM=WEiB zaVBgMKb5YNOQG|I;TEqiVEP&qwfwABy??$>%GO#$;(cf0`#)#-kN>|4bunuJ5KxD& zt+kq}NA_jUdMe)NZ=%e_ZIod>o9T1Uc1Avn>+FwWyxlZOG#GHhkdjWAy+X{KYJe2L zQ8}21Oh5bm#o8QspI{$5_ZnLr2*x;Sd#pM}4i=Hsd2{-6KQB(d_x<4VbG>T#7}EkV zuje3*(xT0q(cTkE}b-!4({?Qb@?)03tes0760ldSXzTW{RqmL@s+;+P_dXmpP2Q2@!! z(jKUD&5Eb9Su!u>W@6q`3ni;J0EB zu*w(Ywzs>l4_xiu>I<#%38^wp8;yT!(nQb)3*z>pJ3j^!K)WT$#EfK2Q%`>*G)d3! z73c!b>ka7pfx77pULC%qY;W{R;yTp)gYB=!^-({(zP;|;Ke=nZJJ^ER^rWy=4#9bW z-)>aYuFU}1Zp7=*{>Bwlg zc?9g5Gg+$wGXATDj}gy@P3w)~XJzyvv%nd+d&9F97Pr?HuQuviEk*4|xUM}P8Vr=z zo5Q^y9N|UrI(XZ`vw5gp`~g*h-L<}5;RI`-oR?2~CyVr3fZzVL+N!<2aK6ngLln-6 zoo&zid2QWoJiqF4I;_1-D+a871B+aoj@)g=jw?%S#!6l5szpWX%{WI* z^lY7ukD>J=a~NSn zDR!M#SuwQjkgeb6pt%uOA>!}OSfMJCf7L-syB;Q5D}`xhZTAuexeCwOO#HamPO}fb zdFOg(+B?&|hfWI!6o<-kTkDYbLKXkE^QT%*1JFsjo0HsLIr*biaAbNUd zG!`*9ZB%A@$@Ox^oLmNrZ{&;Xra8!KiJ26lM4N9{%6~E!{uY^AjT&YZ%GIjdpPqk4 zs5$IaRY_-@z-|ut;HVtjSSyFNyg1UG^f4XP6TBgw%yGxSgJ~a0zSzkoaBT&=oY>g6 zW*Za5(;7@9AI*28ecap`5?Iggbr>!3h&{Nrz#vGWWhpB@b6CY1NO8*DO^4NDcR-<% zuCU8d1FBrdsVn}ZqM59*z_-c;(=XPWkpkUK4^tS)Hk-{{Uj>f71U>6bee2x*=mm@K z8vd4xBfwZ!Zz#v14K=!d$I2meN`vxJL3^Nz07In{Kk8Bvvd(0!F1* zWFlfm5%Ncndw;t$`mp2o)*q_>AWFY*m6tN#LhGckp0_F4i|>q>YRys!@A5YF^54wd z+fAhL7s#}y(Z}V~>ekp=E~=aq;e(=@VAc5x&nOA1VH~cA z5<3h{@nU`0)cY9y%yDhe*tYG3=+n!I6eb9;7wBNw8m%phvy8XJNl4Kc`D_(mIsBc8 z1(#VUA0hqf4D*L^18&yttrhD@g{B(E1=0-+H8mQ-zHoU=_BR)G)e4La+-DF1a5Lwc zGyOXtxX(=YSF;UsyGw<{2&ct%)>UCf(`_j$vEr;wjkDVd_R;C4z$_NEz}fEu>^Ghg zn=xa9+$$SmwLbE=lt}ue^Xr*e;`K%|=sTDXTtR-T3daSdU*L?)e8D=wPwcE^na^gS|O z|Ha;u$PrZ$Mcymz{0vcjpY9^L$+^GyNqnH;}C*L|V%aMFol}u_j zr)n-al6Ir*En`Ss0x zkRp^k1L|gG9Ufd`sd;Tm*xl|7ycAo@cOLS5^{`@iO6RawLA6}43xPlxU3 zCJYuPHc#*&dse0A16~3(&O4#F@B_c2J!1hIZ`X~{edk^j_-#7JSR@sXT$f!wPuqf19O*)T%!8Q8oN92$GKpy!p7+F9qeMBvhA4d4O7shd_Uc9So2iO5 zrR%1z*{`1EJsIPhU(CM}YqxnM;+O%6Jf=nM#!sclh2Lda87?+c1#S+vV=x z(^(^2AmNS7aktY};X@A!26?V5jSZp~4jaeyigVw1Lua8lT4MMwS0*S|HgiOHao}vD zDQ?lK++m9)xNRK17vAq2OqcQ|-AVH6!|QQ{vFpRziEGLk%zdRmV|Jk|$sy|8c{F?o z+z-ahQ%ub3lISus_v7Lr;n<@Xwx%CyMT|NLKj46NB0lM|c4R5NXk==98B<~{} z;Q691TtPvre{sqX-@(r)FOUqaJ>0AK!cEVbFQ==bOV_s?%Yi9PV0t@MJOu!Ao@ zY?o;nF8$#!mN4R>ab7(@0f~*{{H--fdvK4EAMQIC1TRmO$bFhR=s!{g0UM?S(-`n5f-M}v5<{VYIYwfyYThTKwF;LK6N-=?HeXDto z1-?<~CU?cmr@Sp<23~I7(z@&%_SI{4MuYvyW9i)%Ym6n1&qCNVx(feetLKSk@i;qTG~>_@n>%Rh`v zM>!pVF7eZKsdunl;`R-r|AAB2P&KrVD(sTBXD_mS9Nr9Fm!ztv1 zLcR@K9|ju`-3qJy29w*%+v3#eVtFZU@Byp1TE zH_--qgqui&Hh8nkpU6DHX&-@D%Ua@0UL;$Pc>%jfx3VjvFI?!J-miN{+0q7kK6*bB z9BE%s6@Q|0u*BZg#K(xlCc)6^7Yeo%enfAkFBhDSRQQfmNGExs)sF${KRJtXmC|2t z9^_A_hbdOYy6nZe_)_lRu`lH4{M8?Bdo^%htsRzKFsF@sOnp4&|MD5; z)>4%mbhUl9P2u*5;PXQ(<~4f^(qc9T>nq9X)6_{|CorGiGLQVL_Axm|1BkBW-*uZV z%G^d3Jv$34znqKGep25K7E>8Hl#Gx)m`PgUv+_3Hwe%4XI-P=8S?Jz3r3X_WRF_j{Tv2czmF zY8F06R5Opp=oDQFfe={DX_e{@Y~S1`bJqrdZPLRP-9EkQad0Y44|9}5O}k(lxhk3` zl}~Fr-x$4#3jNBV(`SJ^!-hT)gnuq8+TKrP+Znw6H~fD1$o)=h8*8expSG4_fHZy)Vsp+oZb-u*De=e{rWukTp_3bM?B#!&}$!mnbzVTA9)AuH@&U3Yn>8>zq z(96^73;FYgy5DCDUpRmd`@ZAI>t-%Yj(9P7xM|SO`LhX!vGQ?T*2LQc|5RP{+>O|0 zxdEHk5-!Qs_ui(_R14Yn#Z@by#>Q{|?D^5hk)_qyFZqT%=c!LC)7i)55VBs^;%H*!VB`N=qP)Tdh zEGf-Ly1lp^P1*PB?=EC>{73QEvUk%DwARKRf7|s3bj#FF&y&V)T@Bqne?q@mub=UC z3eN-YBeTn}`tz?ek=NvdM6O1hTOM9wMKe8s*Zoohv1EjleU-%nklR-id_RMSk%QRy} z8r-wVo^9{b)tF?Ug*P5qQqQeleDH#61eoH>*sc}d5VPI+Jk8rNw`*B#gvE$oM$t6n zqwMFhN&dsn=3M#Lw*8&}mi!0xZzw{LUcb^uOqpN_jGi&$moK6gm95gBd8&1e`pM)96^G`+koF`$PKGub|FQOd( z(huTgM3i@;f`1}UTO=zu#P5{Mg^|QJVGa`dpZHlq$s{Cu-e`>88OP=rL77-U7KBMAP|qZ`#o`a0))2{z1^$F<+}1ORfp_JVj*=| zt4b3$2Pes!Tf9@YdCglZtCtn*?_H_8^|e^VKLzGj6RqV^*ADgKyD{_=FR5s`;>S4d$9DX3cM1bK?Gx5RPn6&dzS{StSML1T ze}I7p#Ks0nGdBAT*6^77j#;L(Z)lehghF}Y$KMFNuR!mK`@8E@pa-b#_kg?o?l4yVTN=V!Dt!ZBG>J?^ z&-J91PLiusoxHq6g&V;K1E@nmkZV7vM2_RO**${I*Q&SUi~Z=Yvkt;KABbm$+_SH~ zz}>l^&y0LxSLA2;lLYlWBu8+BHz&ijSAJ*QyHD^hUU&JhIHlQ}UvbZ`Ti|r5zE?GLm8_jzdoWwijM55fZ!-#D>+Roi znp}7j_C`AGdB1WV6ZJl1`F0k6)cs7`Zk48xec6{Oj-zI9$4#Sr2~6Ib!ox3iT?g;3 zlGcoxUidA%iMD^Uil+Fvc9uOZ9%-LvYq z-9X(>81or!(}hEw^eZNHTYkh8iaxp-??;z{>P}&;!2Xj`Vay_mx@}{F0Y`owZ`jzGK9fKkQop#LL}HRah|Vs4}^DSY@< zKJ6Za2=%no=_npy)`S$NVpz4B?SJCIyAMm>9b$8I7cg8Vz`+&b)6&+cq zeu7=FeeW4gxU*DM-p(Bbg!ab7J7jhBus^(S(_dvbi_Jw(vjroEyTBXSWcJ^J4-#yE z$X_L2@mSYRlAI|AI8-NNZcG8fqF#238*fqng6U_$GT+(?23T6Ed0yAY*x}Ta*Ilc$ zQ98q7w_Xt1*x(}~8_kY4&gLI?WoJ%GAGVJNxKmtTf0K^>Hhdi^cT^ILpk_uldp#sf zqCBj7DuxJ9jw2JOd$KtYe5ZjMBeQAMn<`)d+^^%!(bAU{mneooxFIp&0V-? z*)79pYq)69?!MI(6#laJQ^LVsTpuq`tNsccqH8XvECRwyNM|bl9UxIgZp@)8XD?xAV1|GY-AH_{N-~ zDE2RK1g3Yw7=)&G(}~0Og@g2z(f+U=?{PLi=u)w@sLjXb(z(vky}EFv9tHxy6g{c(Ztad0a_K ztBbP}^mzUy`qRZ{wIf^7t#3e(1L4)D*b&v&zm0?YqJ5K`3LAAx#F;mE`qTgALV<|uF+KUE+dd)L zPUGhJnJ(ykyeCeSemI(_udpWy%vk98`xQiYziKh9PJuvRpwCW_Ybb3I(&b}OH)I|1 zaj(oHlGWp(_zQP#kkLLzz*2wa?zzowyR^>^e{qsKKzoQY{tnU|nX2nkuTF)a$q=kfGb#S%KFZ%(v(B1YlvZ)N_9tR#t!S39JthFQ4%o{OG30 zd8MD{^s36zfV^kN(*?Kh(U?wHmG$*XRDV+0)sr@9XHy@#EzFSu^BdGCbbU6Oj-fb!u|4D}GFsD~Dbx&JSVZ z;9Hbr?feUJ8rJXWhl09fa|2eAdkuU%i-EMA!s@VG0H{u80tM&Yd-(+U>k_0KjJCJ? zC!hFwRp=bDtvBrJtE}sFV3GBp1G0wnmOP+`NV$RN@bv9C7&4?V{PeLWybXHl&eu3# z6Hy6eOE{tJCnRszGvKAO`}076?*VfC zsS)Zmy10KF`>Hglsp({+=j537zy!&ljEp9C4mF$4FKCzF8;m!sE*lUr4TE)EHBAeS z_wjl$T_xxQvD@n#6v53O4(spYOdR5j^Zn-{aT z-C8uh?!FIX-&3@zMoBZsIaKGi0BDmk_KgUFYvlu|&RM*KXZic@$)Rhnvaw-7*q9Pd zWW2oJmZ|mC`*TDB`YluUPG+bn)g`RYI+#T+5>q*BuHhsBuCrFy?(KaFS&$|=Ow=qg zVzZ&h*=YoHJ=L zWqRu;xyE*ATWTq5gmxf?aPfeH;sE(&!}-|^AQTGksT#nGp`4eH$s5IpRFR%nlAWq{ z8ToZTM#i8AJ<7}@?e3Q9^nQW(eAq($54TCJx=vyX?#3WOYqsl)Mn5D?oC1)h#jr4v#IVw`uE)wpx9j=@N&kh~8?qVSE#-KDHNEyk7Qh2^r zt282IE}6RE*Jl+0AMU87b;&`6s&`{fBvd&;_lB5jRIV1mMc89_R> zYtmVAV}>kf&~7X2LcVK=G`p^%Z&2%LWqXgIqC8pONX`P)IYF?wLUO=oh(H$yxkz!2(@E9;!0%QN11|$a*fdZK@ReyttU@-#q&k|O2*ij2q1;Sz-qF*q=7gHFg0cJ>RWW46 zF@(yM{>p>G{y9vu)D!4!ey4aPnzkv0V)vu?I6HKC!nmFmIOfI z0tyF8OH0^qsU+D+Vp)jFRCKKa4D&1Hx8%R@5yntS`4R{fPz{3RQYF!UlwAhG=8`Tk zUdm;m4{2#Q6ktpv>O5WxezMOJ1Z<*|%4{~UjvdsXgMH|2YJxHKM3OEJW4^RX8zAg% zFD7u3-TCkFBZ-n4ccMKT4>2YhZSBI>BV_#a-Mu~Wkl>~>TgL}4hu*MEF{V92!hWu~ zU!_#(d>(S5PwB7up}R%9+(EcZ4fN?@zgzGlkTm{0l6X=@q79y@t=R)L*^JU9h9?H7 z+5uu9U~fDf^XU6qWNla~b$*kYhKqCGa`T8~akt@op0hNYfsDvH;PYf4Qs9=4lF%C1%*%2+ z;PZM_bZGABVj}zgo`dy~hWJGJQn$6uNMb~BvRVpb0r?Grri3jcLcf-S@yZpnKQZ1I z)2HAM zOi{-8>qAz_d}Zm%7OxHwTOsT_g>XxjZCG#(1J5*0kH4~t=DQJw6oP|W|Gc1d)k2&6Dc?1VBL$2 zW4srxm8&I(LE?o&1Os4F$T3o8G-ZZXqvL~v4Ac`bPhPZ*OgO7_0Rx67<@cRVWEQ+8 zagiU@d{9OcRs)4{Q_eb<{U#@{ruqR8v?-M!nNrUWmP#&(2CyIVRyATiB8UuP>s-jv zL?W}~?M-oz&LEeJbM$6RRzMT^ABLb5emZ*Dj3L)Sc`fwbx4RU zx@2Z?WpY$LT8F9uodaOFwaN5ix}XMV#D5EYx8#&AD6Z0jD(y1jF5sis0ZOO|5Nv{0 z0L`=$g)2&)-a6(TRs{rMqgF=SpRN|}O|Iv|G3^toUWp<%bW?oG2N8pGXC|pdo-VP( zf?AliXTWSd`CPsc6)ZJ?74HqgS6CS?b4Zk5oe~>|zGhQM=dE_2cCmw5Kcg&GW^fotDMN1d9#_w>v?@Xch{fBMVh zJhw7AQ-RPqoh){CnXhyxr^c6o8Fu$%BLyZdA(KGw6Dxdv#-+om{V!TMav!TC&V8di zcs=cj*||51RIrDl%y*E!PQl#CuScMjuXK(QWqkv|cG&mJb zy~7A?9$WjE9NNWDVBD7R9v3=T89erY%gC>z+Ur@WdP2|A+X{LNY>QQZm!92wXg7BU zTg@02QaLx`ooR6*yBVaQbRB7FP1`*5O7^mv1|lE%+PQuQ6zEia)R{7Vct!GyE=gAxTWsLo&})&RIcA&G2SaRGXm zB>f^uz}<+pwzA6&3e%yCYvO7i1I(8V{PUk&eg7yDHEM;F2fE1BJd_x`qbN4FgQv1f zlhaaYkjvAjvZ+fZPU6X7q<^p-yiZkuR6kV8r%8F1XS}2gEVOY6- zCPKDOHSRVejBp})@Y8%ni%P0!vNW2A(R!sYJa)J8sjocK5Sby_>mbdDShcI=z!hdF z5YveCIVmR0+U@Zz03}oibRp1}bZDhfC*`Ex7c6=UcUka5-;%uhY} zx*{zFS``|SLXij$D?u}%U;`o%Ca zM@(vGm=)0oU?1mDPftkcHkcTi;HZ-xs|g4nzy6!gG@D$b6{DEawb;YLP?BtlPOd2G z1bfR3?p|8`o}ndv7<_EWjHpU2+{BdG>#q!!_Kq?` zMJLdS1;fdmu$#l-WYh%tGEm0ZR58rR1yn5_$SY?ts`f8B2hD2Ax2!}b7=%G}v$>C} z!KA(Kb2d9nkk`Ej9L>w(lzg)Oc4&xCCO<~>=lro+L~W-viF92 djM2wH^bIg|5i#n#> z$-=4WB*qO#NWCXPX2f(`A&@FKGaUzXuUOI#>9?7o z9Bzm#QeNgP1KzO;6t6QSyfVoVdeWwtUEvmxjZ!Q8bXm9x1WO*5JBHw7cFEf>Brkfn z$ov}9$(IpQxd|gHceTj4=~Jb8X~Z78abncQXu6mUCAJs2SHXcSLh~EsVnUBm$x*}} zbthV(b7Uo9nPeKi%wpzEV0*M?ShFqkpp3Ni6S!dXg}JHnJdp!NK%1E# zbAQiLz~iP|7-fGw&zJmx;wu|Sz0e}wVzC?*%_nhPOYW>la>}?iTN~8*YmC|V$4i!J zQ*A9ppL@5(tjMx)u!wW+DIJCsYxa>6^luIg<-J3d^s#5PH0mB}(e|1Q?hT)-R?FA; zAaq8lnP_+;1h)0u>4t>?1vjN3aolf0R8wTu%r`(Vi=jRUanuo*;EdzxcIq{cZ5@m7 z_H#}8DvpgsSCJ@p7r(PK<+37=nfiHgF>0m$wAgJ>|9#WmZ*?Kr0jP_fNV6`Dpzhi; zE;MK?Em+nb5hYvkj$D3ez5xtY{YIr~&=va24X16pL=O;s=ZTTX;ljnBlKp@LZq~ zX>4E3%6e0?Q+DYm)2kV2?cdeX+|+9djS-`*d`fPHRJT!cUr4H2LZl)^%+pkR-2kCf zGz1W=*b>Z!O8BE1n&^vS2c&+kGP%_S`OpqC11@S@FjgE?a2kxi)C$9_A1UzW)pybz zaDYS<=KBC?C`#YE@kfkQVJa^I(1Eo-1`H8Px>_UkxECd-{b>wk*-3z~Kk4+AwOAyh z#%E3ryyIq4bd#=)X`xIa4^I68(&qiwDiE?3CR+wUZna|~0J05-Gh}%gk$}B`n#g5O zV)8;7ob4n$uy>d}^Uk%uHvIMXx!h36QzOI106G(N^d$u+q%#@pGLJuutNA@N8mvU9 zJ3Ec(j(nE$BZQ&^ZC(Zl z5_2d|+)|h7KD()1w`5>U9a}Dnu_93_c!+R)-kPtK1X?d?mn6f*xt>k;V1;ksQvAZ7>D@uCEIDePDXtxmEeb3( z%U|&-LrFJqWt9Y9HKL#?mznn5&|kgaEpjXv=BpBlrS(l*B0m&k-ozlCGZbN10Iu$l z&Nuw4tNg3_P^*=}W$g_@GG!j9nd45&l37)ykhE=8o+aEN#OHA)u8cq}zO?v!*(Ubi zNy9>mHsb04Xbp^p1niSx0Cc6tG;uS*(LCxQ+0h%@LMb2<(^JlHOm1DDuP)88bcYa< zr_78ev=QfYKi(p{p>Y6|gyvPJ9;?hO2Bxu7f)6I;B+LZXXcs!aTxlR7dZ#Vd)$hTH02Gx@hu(gN98D+_}$pZGz-x-X?xzRj=| zZ%;3l#-STU4=EQpTybrD%hjGiS7TB7V_d#0War?c`5iX#1Smw(&Trd!0czI}XbU5) zy4G!3qe;Y+;n{~aDpYi;UO(30`Qr>h>Az6@0d+*$_6cE!y_W-I ze{i6o`NJ6*fZtY30sf%;SGUSGnS3T#x67W1uqbJ3m|2x8S@eo<%AN)+ zIjRDj&$(RcnJhK_PM3*LU9sM1+1yc^k4QdF99DnNgEFwL88+Y z{mMmvm=~)DLlGPLq4CL)7Jjo`dcYaT<+U z_7ZB6O1ZlAy0;b9l99$FvncEtII6^5BdQsrhcIQHVADcINZ9$#kKX{anYtVtb&!SH zUE}e&kOgl^|85MeIv&Km%3VX;KMIaRes4*(Q*cHZ{5K8jZ)`qS>CFQ=B0M!~{tN!X zRF`Pg&annTA_Dx;bB|6631ELC6U%DLlTC}&P^7rRA(bd(JUWEqnTh$)Q#@P~G0cKJ zBAyx(>Jd>N$-{Z!oiwEW@drOemQ;dMB`_gZK4xCp>h1#3Y&&tFC4(AFYlru;m46L~vns{{45N zn+sk+(<^qdfp6sS=idin+jVcMN;4%G_`zk&0hZ|qStYs}pLpp;?%Uyx0X4}svNiEWXe#}Z( z5>L*&_*}DGOO1H%@P#rv;=?3nkd+=55~4W3pgUd@gy(g zO9ugi5`6=&h;Zr!Mlah49kep>9~^^ylICTs&#Q}2Oi8{01OZFxUDjN1s?wDC-~NrA zj$t;V{k2#)#cl1cGRJIvq8KGg%x0ExGc6M`oWhHpNTYq^Fzs>EjcP9^zU;3;K8c<} zTQR1pL!+$<+%41JU)LTttjaZ8w8fLMG+u}lxO}UBSWJmn31yxn)#{jLrBWYnqFS)r zGX#KpK(`nq8x?fq!cK@rJLldM z_uI`3=cqkrIondEB%J^@q?bcoI^EM_Lm;{K9cm9sx8XW~X6;(5HREi+>ahCSwJEKQ zxIVb-5P{95v=MB>00DZkrS@z(MmF4eZP*&gDt4$@^ucIOSo#d2*tuMpk>HnMBE$i| zp%eBT0<>3>OjXcl?Lf4KfMq>0)o0NlKyfW9(F5U5iA+of-`3iv@6e9^1*1w~;$0p` zS*-k5W_sMBU`k=^U0QqFf+Uf_A@t^;z!UYR?zQz+d@!Q4)=IoKk|of0zSt*n%4MJl zMoEVrY-K=TqFhA-0S!X(z!+h6688Xak%4r1jEUk~Sqj+|KQGUhOE%NV>s)1ozcaz% zj0Rs#=JR3{(P7Xy4lcK<6NN^=$V1qR?qQfWa16O{jJa?O8i=0Vg;CZXjr~QQY$WW;3Ja@Z>eWdtn=Kl@btUQEeBgvnfs+0VE10 z*0GFX>)Zs;6V;dFaC1dQV@PG9(QPLgp;Otp&JOrdl7u$f;D}$ymi=Ma@;dtiksbT` z04IZ(ZfAMmfU_f>Y~=n;A{Kq{OygjmXyHqX{lQH+nYfKWHd+kXmkl2Bm9GsC!CAC0 z`mRQ+NQ?L5FmGk8^7LzH&WHRY_*@!HLWpE1sn0zv>kij)*|F9@?)|+{vrZ#24T&Bx z*2vJLJLHC8`NwpWWa79C?AgA3<{TJw;q%tBo5vZtmUQxYKB9$#0FV^vQKK^U@+_89 zXBsHSasCa;0TXoxF8MtrL;|cy`9~FJLnS<6)r}*BhuWRz8Sd~?v_Ns@+RNg(oML9J z#c}T0lN-bE2jkWp+S{eTdD}}fcN`8wx--eAYLE2#Q2prH6tkiDJIe_bJq`glt=YRz z+ao2iUzBrn?{5U?A6CwqVX8(RrsTDIFODZf@8J|_cc=kW(d>F=g}6vXJToyWBGQM0 zTa2Mr?^@(SW!9%GL9b#97li;753pj^9#C2I>J^DXYa@9zMz^>YXX?7pWa0>P;#<78 z1-)qiaE{ku0}uTQHQF(LXW4WSXm3Nfyy-$1*BZ*K1HPip@nhwBsCTFYLwS76L9s7g z6;)*qx~>u^p;4Bzy-)Tdgd+Xea-BoMTIm{6VZ(xu%rfp$5gg2mkSgD;DCCYtu2Gkb ztPxGsk&$KjAh1R{#sszY6(3_9tXLEa6Sl}5#q$j`!75N~K0GTQJ)P1J3hV!2>@8y} ziIqUjFiv2?oJ^7lGjnFb%*@Qp%#0IeW@ct)JV{QNnVDg8@7-O!KP#yLVaI=(1as`Ubmq?v{Okcse> z(ee0(3O5jx(Tla%Llb4I42s%HNikEnQ3<#8(f+XU4eX?NvZ>`9US{x!YKfifk}}&n zq(gopOe=^xZvQrjn_Ivt8XTy_m{wziVoVtS49gWi-_DhfS#cXtlNtD=dQ?VJ<=m(L zXdw}YU&=rKT^Cf%L6Y%1jWf96?PPFOubq2nTpuHuEZc#uw=jx_5(C_7d7?TkV$5i) zk#~MDCgfkRSE@lXUYX?Z#auN+WIIrI=GrYXBJf}60+3@?mk~2?M^8zK)HK206GoJK z%u{f(Ybd76J~g9HhRTRLDNF&tRQU$>DZYKA2%X-FXf zURbI>L2AUw9j_5>dQ87{h8HuGz!`V@rO)zK9;b_c*EiSz8wZPrA#!%R;tavm3OWtr zNf?k3mxonEc6apr>%HpDC2(cC{*9j!+!WH43|prIrdz`SD9zZub{gFn!DLwI#7r2Y zo8^x&!c+sl)!4f1z1BSx`CunY$~1n!m{k+Qn~`|El)B^`S~wz}4+^mmKuj3Zw^#fH zPw`xCW|}jJ`J}zN;AcpUlx;~0AJ)rqp(&ogs^C1cphic4!pkPZ#7+635sFTE;S3k* z-sfb6vI~~g?42-o{N-sGaN1;cs}j|&{o~H?g`>Z*k}VsrfD@_Bg-1;J^p<0qr7HTc zCB;6U`rX`ad9yp*nzZL%KKsO?g*pLS8d)LZWl zcDX~ruCN4aC_wKfRGSEjM4i>H`F!lgZ@O@jCBSjg0w2kwf4aQ>Axr8*Kt8fyQiw1NwXR=#3kXO zNVaM5cGK%|$5Rb$3i5ip_ggCbCkhX4u4~Z0>uN3WW*mJ9L@1-mSim|^>H?+A2M=LR zn##HtKXi}8bJk8pB@KFM4aLtvopJ6WdSG}IB~uA3l~d(M@lt+z%WbkgYl5WOc?9li?Ff$=StonD9V;ee^fGh(&fk3N+MkxjE zMdcWWAi<&aw;YP;F-X<5sKPjY<3j&R zf`1^VGt=N?1uWv(rHTBQZN^mdLyJ}&@k&dX{|8Epi=-cU)>qIpL6E&J!j`Rhly4s^ zSTP||D-~y5$2a?iB|oQUm)PZywv=Wna19XnH7@T_#vV;DiKMw{K{doS6&j@(H2xhR z1n0^n3iZ%&*v^iMSCW}n;B-QSohZfuU`IT2ojzg0EJ`q{y##|s8#x)1fLB3vUybmm z$SaV9LV@H-cF8H%n2RNXeV1w+aebF^En?z2+qjX@y;>m%6(UZ2(b;-D zGklPYTQ%Etl7XGew@bmO<6P^-B-aP59@?Lvjy4rAw&Wy(8 zl#F{H5C7oEwWbxQIjZ~KqsdJ4+ow~fphp0-+A0|`zn!bW+bmlkqS~Gl>ijQoyJg39 zh133pfu~IoMX;*{nd?AKKm4M;uPaweuyqH3=_#I=Rd90p5Q@FE_Ym640_Uj2SGWo< z2BjkjaYcVanZtt3MEOX;lNC&>-cS%b`q6li3U7pxKIGXV*mZi4w8diJYJyfe3>4n4 zJSs$8M@lR^M5`+Z(8ABnysfkTP{cO1Ax^Rx1d9c`)j$IHQz+`Vr^b_paj$gg zoW)f@{JOd|FYQ*?P2ba*dG}xQ3C$)e_vaiUn3W%fsepsC3L*7RUF}(nxofVHH ztz=aeiuOd3>oA1%`nWlL;NlMxt>RmVACSX_3maxtmf4m`{h*3!9m|NtJbMRznUWbU z%!h!+{jR~g36CuOR;sh{Xg~8?0&Azpi`$=)GH16dwBOyNg!y$*E6)WZIhcXjMrc-O?W5BaoZD0JGvn=3Tx+Gnmj)TVxwo44bCDYUg0?Wuc+n=47VMu zwBnX3L0T}Io9~vmDeZ^UM3b*dhPdkA`DmBo4(`nBV$OOu{sOz5wW;kH;u8CeR?93c z!IHr$&HA`qU&q_of>jGFEtAuD9?yVHC-|aCyNfqjiaVaCs}NQqlsf1a>gYb!?JgNz zB`2%a&Dq744d*=4K$8`>^y)5@X1I2?i7%kwKaU4R!4!)FHPIAaC0BIq;_b^^%dJls z46Xo(8JG$Hs2g6>Feq`+-$RfQw_>9#L^F}5hpKMxk6VxxWtT)iM? z8TqIwU`=Xwr~Q2}h_WvO{ZoS_ihsK-r^l;_5l)cHfk!35DQ;N3<{dDmc;DtsuABtnCfSFQ6I9E$f%Z663k)+{x%V~^U4(2PmUgul#*>yIfTc3tnBN<@(kX2wVHYk zb_(>ZJw4!tU0hb=lzL66oXiBAVftL6G8!PNxH2HsgvA(rfTe)40);Aqk!c$*>`mvW z&A#2lt4C(X?b4IH(EdV5y5hNZ2}Cjkl)G}vx{}HQVLm>pQlg?XuT(EQHzQ)~WzNb& zYlMz{R+Y2t#pJ=Y`BlRSL*&HxzZ)N4TfyWf` zM;%$_;4dkg_#_x!Ao#539(bnH0T_G+sfi<3Q~s*nj}>fV^|&sAz+}bvp~hn~0_F-l zY7d{t84Uz$&P}T{#SrwaWaByw1RLJXEEjy7%k9-o5THs>pKD`Ye`d;(%!oezk_Gl@ zWSXf=N7NDZ(RR=At-7@nQA5l?RVd`})Xtn6nsfsU&&e_q&y>qLWAO_qRuSdK;;xq| zkUP(xS$MaDnp{;R$llW}p)J#4JZx>tL+>ey0%W6*fi)=O>c&+NT z3RoHo%kU}vl|V6J(zx7fFmApY&Imd?={HCeoNlf*w5tx%0x8ObaWvo;qTk#3djw-U z3=J_RF}^NSk%A|y?1$+xdaUx;yxJNyoXR-*#1iOqEhe}xMWTI|&W{VFIY>wj!5)6o za;eIdn`dQu!=KfM&AW;DPB117=1w)KKo3R6KqCAAajH0vHi4gX@5MYR^!Nec#puf_ zT?RUa_Ar02V>SbrE%K!+&B5$e!#B|c_roGUQP$K9a=oNM3~z`sBJv_EA}zp92(AA5 zH@s3G8Xlv?xaw67{}Ln;b9&(^aZ)o{V#~s6o50ROC2=)~am?Rs!=LxF?)2S8gwMXt zodAJmNvCc&RN0r=UEo1IoVLJm>ZK<3V+#&M#qkOX<47b@Pd!(GLtk^mN1nQjTo(Y9le2{LRnX)}R9=^`w#~oY8uGoKp_a-%TVN zbf+@hTP|NKN(Gg=s?=@H^3xMNQ76&b@51meV;#K8ADS!(paw8g;Z%`>BHTkz1y2Tt z)0O zqnhvZTo%UZ5n7jud^6{Eg+r)1&WWh36vxjH1da9P^7VwYkXKN|*|BmRCb$`@>Qq+G zI2&X{L@&I^0j;TD-R6ZkhQk65*gFd=KiTyCtTOcs#{D7?4MHXvbQr7YE))unW967^ z*mzj0GpWQn&=^&Q`~F5}4DRw&LH<% zt%p+E8flT|g2=^1Ernn;W#)>s{mt^Zu{}9iBUU5St<6=5SjTV*z_EC`Ym3G0yQ)m> z4NUwH&B*sDrrFH;wSkNRWxc2=qtmtMw(;pHD@aWI1|ItTo%cI8>-de1sW)c@!>6|A+`{Z){`kY zV-A;Ao^W=$RUY}WxPWC>;<_Hk`||ZHDo6PHq2Pb=IIe8 z3kK-%NQtAPd^gMKi?d!oS0%3m&Wdv1`gm2x$SNL9%-6<3govl8cu0BsN7e7ZKpq~!;aF&&92 z2%9rrZd4jN5PvBY@Hx3O+oq$Dg&RF@Gt;quc>Tb9l+P1Nze2FW>2(R$W$87`l(g{= zz~sFW%|Q#9wBZL(plOR{rws;~y$-u#m`w(tCEr3cIgzp1xYe#G*{XEa8|U!iha;?s zdm1`7iZUc?sjQ!fS;f4`xo?o?Z6B1naiMUN+ZX>L-~I3Y;8_IcMO5BQdtdV2c0xuI=LwqP_*0bO4~HuFaLGH2MpWJLTOUCgM?7`( z+urAOy-TNN_8++CvE=*Y%9c$g!J4!25%-Bd7hH7qYm`e8m1j7@`WkG87^7JN)Lu

    ;U?4eT4U>gF1Yk8C;C3t>Oo00-}|Jt3u6q>VIcr`+85Xk0ko178p zp<1wH>9d}b`@#Lv2r-S={zXaaQMV>eO>F>PxWjf~gh1vzATo4Ue3LEBs^u_aAE{9w zUJ`NCPcEkz%b*meGF^Gx?A}eUxZ5T;t!2z1CUL8e&y8x<-g=4VepPDBt}chh;ba9z zFXJa$ms8uEDybHKS#F3hD`NSJc^3vr_@?swv>1u25+Z~gd~Y~d;Ou#O@7vFN(?XkL zInCgo+p4-3i<4dDzJT0~gQ?~OkaD!0t{D(JHrKJ2x;?6gGmPg>QASJXY|9Kt-Jb+y zIH^ixJRR$WpkM0@rw?U{l3b(SXHhxDNwM3Wa2KU~|MZ_Z&Q@yG1AiJcEQ+q9i@66m zP_}P3JRLJ$++|UX(O;zDXzeoAC+^9=r?Yos1i5mHD#viVfe1vBZ|Oz|pj!#T-^+-hvpdq!Z}n1oV*<8dbKjO-9_Rr!zh5vJf1N zde!(S8qR5BPYc7Du8*f3_LWS`6X_OJ+tW?Su?xu7=%%Mwy$n$s@do&<5 zxm0S&Cn|w>(7ehw1J$QkS3uv;LGn*Qi0k_5bc@Njc2F6{VQmfEQJFh=ba=`>Cp1nI z3~<$Py%fw0*B-N#+7=ty$k9o($NJmXn>U~7L~1PeN3rcWwm~>3p(t4i%ry*V8{eQd zbpKIyX+T?c(m^=^4sl}@NlR(J(}@va(jyq{n0CNo5sny_!|@f`!K5r|cNk0SUA6q7 zJ1W2cT%dtX>0SQkn}LMt{ss+A7g`h$1DvPLUMiq}>N=V=tBR*^E(G8KSrhY0Nn;NB z3iFUbSPq*LZmR@<(q9vL3iY@^ z9)G;tFL~FP0BOT@=zonQ%cv36j9^!IsgUvWw#^$4%6*eHh&Zp@4aTDj_`oJ?XN-%i zrS&50E)3%s0r&Fr@M6l;>!G5%`P<1g7miRPUE11&vM)1MlE}DZ7 zq(~UD;P2}6bit`tcb%aSbvo)BNU1rk*P2L@@9&mWr^Bw-vif(R@B@+;iYtQ#(=9t5 z@x7Qu_3AWhXEEWwML$0hAs^6;$=Af;5ztUAqLhyxvPa*Hs!fm)DjCdz;gkpEa%Saa zWH<}3ZbMy{V!jqxTdv%9G#@=G4y)aB%v|1Hi;5gn6u&txIsbz>;{K8;LC*L%)^Q?@ zGSgrX#SZTP#zUOv#JvJyQwEw=pG67IuUwBSLM%TIlNEz^9PP2QZYHmV=z{4vmu83} z+V&4=tx|NCF;%4r9D18726q;eU&R6_eDRxA-UfXrSdI)XOztQP z)p~MM-BFrv4~BvecK=4mfqNnw+e$rIvf6!RViF2K(+AkW_P zoO?JcxOGu?uf4SXWolES3G-{)=n?y*B^_m=%I$UhrPb2UKnq#LIr}+N&NA5?jI3pN zMeA0*g2FPDIl0jFqta3dHqT!suoEEAs;8sLpzO2;4x)N9x)=qD5P&)IoKh}z98+xB zj5DOw=#L#^-`5B7w&1v&=YsWnfmD)CGS^%LY3gx)BW}V^D*7B-O^;3e`PbqMHkrx&EGrS+`|!L3#JWiDFZxVYdo%x>j$4TRjswjGeV! zvMZ064KEVkA+&~LLRe(IP#^)j4%MQ@26Lh+LO2^iY329ftn9uWQo_$@j(`Qr6Um=h zok9GB63=&;L08T-7qgU{=I7OPe_X@%7*}NyhB?!9`T#h22Q080@@%ndSBmH%csCtn zr8R>-J&4I1VNWfjn=kqFWm|acKV2z{JQ|8bzU*#mM}2DK1tYiwhGsa0qH_lGHjX#nh3u5?3pmBeKUYEIEVb4W zUvCvoPLY++!Kv`H{(P##s2f4`Quc3h{pAvM*bqy7tAe9H5D}DI&dn0(Ghsh&T>XsG zDXUvF_MK(mNWEU&w(rzd>IhnTtG`}4=Hl*$OvOH?#w#juEw9(L*G7ZrLsiTUf&~@2 zUVVhHfz8r6Ho@zkPr86|WX%R@+i6h=?}DJXoI}HI0Qi1kyR2 znRfzp|4Z&7^Fg1tS4j=9Oba8sd+9Mj>r!Z!`D2krOutgJh*rD{wX;_*KwC#6?hoiC zmvVH$e$+*#R4Yt}g2LXO0>|5{@9Z90fTLXF9)%=OJUM>&mN<~=6Yv3_zH*bm3|g;Pv< zY}0SA)Dm#3>Se;9iW${%v8ZODBNJ0$=vMR;jTI*%r_N79ECp=HXYKv* z6de5v(vhA>2@YNiZ{#qZAAXM)$zYV}^+P#Xi6btZvJ3arWD3f%3KR!gB9^bmz;aWt zoUUB`Io(O>DrgLtZz&80Er}+pE9SSWe-`0iMd&3=$#{q-1a&-QC-C=9(=;E#kS~j+ zW{^uL6(aRl`*CJcrfS)rAJ1kRYRGniWo7#s7lcSO5ZFl?XAyEMIy>w|K$EY3I-5g< z@g7b}-1tXreT?yep6SkV4k5Uzd$in#i45{Z6p1-ml)-sHmue`TMJ2=qCV&6%Ox-9I z%IJkJxU0HcBw|Q^-w5YTgs~ z5l)Rhs;rh6*{__t2=fX1pKKY?8hSF;fk*p|6I|`YQ>5yc54+iPNft&8Sc1ql#i1BH zO?R1Ja==fH>s1H_yvf3Jk9hq}5VrV*Umr0t?APMbQ|}D6AS@uZ1toG(DhCPd0GEKu z20qSI_ER%i#KUOLu>?bR@FO=3L_Yh765}%F>FdJm+DcTOvKz{?ei;idFlacWDtWpv zyv!;s9Ze=8JZ=60D>N;FlDlO8A8?LyPy0-G?tbmleoSRpOg?dbeR~P5=bCusUbBWw zcsxg`vKBwU^{~J$hY3L$E-XA+H!wo3pZlt}(AOn1^R@VH`>hROtau2syrNaqhAb3* zM32CcJ#>S@=bh9PEW?+(XDp3o$sWupW zrdp{i=!*nPyeR`xh_YZ|6N3yGR*VBOF~$n~tp=~}31;zhv;F0*_s`X*D* zX%8ZI?hmwBia?CLVqEDM6hPScbh$8*DM4^^R5KBR&~l@Zs;8j-z|As{#{09OyeuO` z8T{G{AF2B%3W^2wH=@^|v;YKw1PiE=FHjeLM%9&@I>@>hBuBHm%9M|0j1|m=BS`@= zfYk@X5GB(0c?gR2tXU}~+d+VZi-WpW|%CVxNqGf z&9AMz!mW+hL4~vt4`E&EPJ~e(Dfze;xyh5eplx zjVS~&Tq7H%P8)@t05bhlIA+APxINCzh&@s&@^8{DMQ)=EK9bnO@KYiUqVYyc1v9R3 zx=L=qjrxdye}vFka?;UFF(eg^kqU(@D3MHgdOCIjNL}v?U-giko_~Y^b_Pu7O)ijh zWJ4c9odZ3o6HO;2tH&q^iEf;6g&7@0o7J)&HslXf$LJE`a|zD@McS4letp$!4UP^y zeNU_J?d>Aw(@e%0l8yJr?c!X{r9syepaJ^%)^FT%GlMsk)}&{0so|($#`OKRFA&=8 z=sWX0E3}1h`zjWfp@mTIV>SyqZ#S&`w&l|KJ09ryprS)ThY@us9VN_Vy48_@JO#ng3r4!xU)+c#o1 z_Hy%*Y*8nBH;{1XwCu?gQ;F9Z&g_4@ap01yH;Af_AGOz`XzQ!hBhvG*tM=Gjr z<{I-q+{1u9i>UO}(%kU~SDI<`_NJ7EG&udYg$zJ1~_*pG{^7CTEw81!X zR#r2}K>8TU?dEO;yYmg3PZQnsf`aZvMEj~cX(Ig1rS7VGYUj8BL-c9;?r6{kY5NqZ z#&YX25Bjke!IQW3#R;BWbw9^)DbbctkkI;~c5FT2vda7Ui1w;VrjQWTrTh0LmV?~Y zI7nniEvZc@#4a$VNLHk7;j;b1{(k9TmhL~8@%Fxd-6(_`|Dm%VoTs=dB;4dh7vZv; zKuJgbx9okxJ<~Ul%wB&6%|)`8?z^T-NwUhL)cqfr@$V)IYY*W;uHn2Xrk>4Z@-n+J zM!02)@Sd9oSo|^eGs_iK_P!90_rmT81`ltDR?PNR&QE&UW*?wIg-pRtyXWz@^At&& zeiwQMdDMpE_QC^8Lwk-11tCNz@YkZA7%P@S^gyT*zMI!G)_!#_^xJmrT}BQ_%?EhU z(oFPT3vNO|R5NbedP^x9W=G}`T9RkmOhO!`7d{ied7L{g)+IMwpBHLBLJz41NZPHZ z+t=Rt$OdS-3WA-wb){qRBM>~DHI>xeFLnL=Haj%^PpgHN1n_k(zUFaw;}XGI72$Nf zzHj|CeUiR;;vEGw$rOM5QFzu?6T%zT^L~iJ!Kz;+oN4*sU|SaY`KNJp`uX8P{enF1 zI#+rlHh0LY>_5wyYfbRXofY*kW}i5ss>tMeD9Z`$0E8BKclvm+lbxwX5p3&zU_h%A zJyai?a&A`NB0P#2|M`0Iy6#oC7p@m@WG)m`bSqxA72*etz;ffjwDo)j#jWd`;8^#* z0cSfis=sZ@TY*?p-Mnxl$z=7?>GX+|%Yv|srm|w}*i*<{rgyCvZll>5N;PbxnUs>j zT%~4HIKK#s0?eyMog36B>KSV%=jvvj^SY}9+?_CIV6xqoh_V_kE-R>YmX~E(?0M_i z5wB6(-E@E;C@|GwBLh${o%~H4znDr^{IPF;Aek1=lb&Mm#Y-@0NQ=Y6Zlw`w)?KaA z2O4g`d^)yCR&@h^5<=O%GRsPWsc$gY9zq#x*+j?rJ83!I;D=^$U$S|vF;24;1W|X} zGO1N~^W;hw@Ab3JY1jPO5?I7-RI{YQRR^jq4wb;~Ar&J{w?4iYd! zw))3Y-B}sQs$m9{QBe|Ok9FLGTOk=#V6hph0m^44*i9tcK!avCtw>iQTm{sIKYm}( zL4IF`8SAYAsmyqJ6BsUdPp%-y1;V3NBp-0wb|o2yR`Um)c6r>*l=_oNhuI-b=ZVxP zph4wqd$M7eh=1$ReOT<~Z!Fr(D3H=v5aaFE$`n5DmDave$|_IB)zt@aESXj^Om%td z`9xeYIw1rn$WURbWwf72$&eML+`<@#^j7+3s4teQ@oMECe3c8KN|iDHrT%rAcsXZk z*o7gGGK(K&BGJqZHmE7>Q(FCJ43Aq_f~H1qnK|DFH`soO2;E7u=JWr^i()6D-Y=I> zAtf+GM&|~AU<0(9iaRXqs8bMZPL$`V>#Q0MM2EoCCBv)@_8LN}o{}Js{8U(O>WEKE za0DAB>YUp6yVZ1ApMVb4GW&gU!FdMUCHZGO4&1|4!Zx8C-LPcbzZe)d_-$^Ue%I}^ zBiPFMo9?15E;^F7_2@Y-6{Rss)s-+JV|yjPPnTKmo-e z&9Fz_mNhbxRoMk~HfXBFowXOM2}i219650fD{P4%WSOOrmhQ~6?&#LdU}Cf;E%)cA zT~oB*rGd;Rt&3D6$l^sKZM*w*%OmR47`~a_Ime`xSD*ULeGtTKs8PS-_9(Sl<(Q3z zh6pmvMC?b0?UsXLix(uFu<%qyBQb*SsZN?!x{5ctDX$LV9ycp>=bJP~Mj1mS6+*4h zR4X@Gh}}D)E8vw8J0T$xAU5TCQM%LF>)ioZqT6z8!#}$@FYMelPtF=-MA%%+@MSvi z9${B=46(Z8z#~idy1k|Hvk-8C2I~9{Tjy=;sYdMDo%WWBZM|i;phCLLqg?ALJ2=+l z8yP!VHBq>!m=A$yAS+dJA@Q|TM~cBCzf5(alCjCi-bw|=)cM-Nt{L{0^P{bDEbfKj zZ+raUG54V_Ha9#h6g-iP=byQGZ5?8@NQgX~T=$O1FOJBkj{Lt7Ds@#=h8YN(_M{hA zp3#~tDzcAg*H7Rlr#WL#S5|jlW{hu;FA0+6*YDvTK!(QfDxn<3W|Xsg*CRJkLl^1p zPBwDV34(VA3R&@3+qWwVde_pXU?a^1n3};B>*ubABiy*v@c{oO@xl|%e4FD?6S#K= zh!=|E58E;xP(lB*D&iQl7ZZ!?AfRY+U~ueR=#%vSKioJuxva6$j);Kt6HbFSA&)om z4MfKqo%)6ER&<@bVOcd=iy$`rS>Zux-5}5~BCAI}(HkQw_o|e|dTaF7Oc!@f-ydx4Rq0?!X#`F|9fo{`|}ykz?Rb=ivc7h8^`Y4VH(vZuZq_QCY`)yiV=r- zuXLTlrNk4B(Fwb_-)?^!w-L<$HbZBAYR8)C^*#lSmaI^#@}iy;UahjiTj2W41xqF` z^xU#|8n4C+HITZs;i}wYSDIo&$yI8Y9tqoK_sjlOp<7cTD=$7cuc@8sutz6%?Ex9& zZ{GmvLAtui-i1j{Fd3BaR8hV{xuR>jQ@vgVxT(*wFCDq#3-{1wBhwh) zBl98GYElPIemNH~xP{4e<0oYS@CUc=gw8Os~p1r zql|}{;O4LVmoknjFiDkLL?ZKlbG;oA=GOhqP{SVWB^$Y|kkVl|nfz4y#- zZ~B2lwOX~A z_0HCukpV|860YCX1C9tnI%XVFvqze=80ysaXKPn`4|areJ{`!LYhFZbvG?#zxAMk` z#|!0Y2ehfm0(Bp*t%s8-Qne6MMi2X)RbPTz-VNN8A@OdSR(o{=D~dbJFwTDO4MeIO zf!;X@Q=)Hm9rPG)KBJ!=i@UuR4x#F_<>KE5Xxu8evyS^kiHF8APWwf{_SAAhLD<{Q zZ>4MVH*x!n1JIQ(a&Wu8DddcTm!@1?1z3ktx#)04x{-v@VYWB)Zf_T~KBs5U<=vDjONPPliM(DKV?y5 zNugg0beeTI=_(Vi$IJPsFhxciHTzOAnnlFt|M|JLM1-?mmwScZVrYt?bX(ia)BOSIb=Nbcr{AUP!_~pOCO5-n zG4pmES=@E4?&&6USK({PdggJx7Q1&UC=9qW$!Y0%OG(Q**=Kk4yVUyt)Ph(L_DmdPp6A`@a=Wc4{`CIy)+)QI+r|Et<5z^R>3G(iBRBEBrD==aX594f_O$a< z`IM7s9Z%jZsxxc@ldNuQ?|lgUHulSJW0-Y^(8{GJyVm=3obW@=Wz*dV{1)-HAf- z*m{rm7}Mj2+C0?Uit$2oYaaQ_v;u$i#6h7QDt7G@`<^w-jJKCeP!+G6t>}9CwY8bT zI%bb&-ftpGB0qnO6+Jc4eXT$BD9&n67~6_7SPFWd{|j~>z6y7-YN%Qyy+~-Xtd77YmH0d9`$Q<{wjttfBon^d;AM+j7DrH%G6I&v{>TVa=XP`V^~Z z0o{6a)fnO@r@Tl1u%6WJDZ1j{xIeL}xlM?}`*b1=PuS-BWAbH3-5|?`U@v;&l{hVW z@}8AE?UfZX|MDn#bX4~Ig!F%0f27Fb$2oZyPoCB-InxKmqP$Y%eODbcc^mQqzD_6} zXmNZJ#|1&()m39qvMB7woY*m;?eBX`^QWF%%lDlauJPl7D8BJ;aTJ><_Q%}labE<% z*#D*!1bxa#nt3PAwnz!gWUd(=Y{;7s8b7wsH5|~!t&EI!ApL5XQ1`-3^RDdVmN+VK z`s5Qo`W`hxo)w$q`d>A-pijIiJKx+2@9J(Z|Et>@S>CshFeivlWfTAR{kNLBr1#&# zy|~%$JN{3XoTzW1HxJXRn!9V_?6=n53I7qUk>wH2w$!Q?JWO)T;lgUqp7&&WMM|Ev z#I;?ZI{wWhyux}lmA>!i=45@LT9rR^;v5^ja;k{>1jS~KJ&@_GD z*ibAthdhVg>GIFv%eo%V>tx?AZAriM9I=cM4%%X^`8$5KXEJTQLvq-hW8G$5xzfh^ zT0q;ASDjk;RcCThWi3BcZPzHwA4N-rlyD=)CbfW>2%N;^;#=yJA z?izsUo^Iv!Ow8nGUl#oEZ(mUzV4|qcpQr9Gty}N68mEZMISZ|lrq$6jdUNG&39lbx z_c`~UHSWKEoqXwb2ND)4K2UyoZ*z8$*2vG6FlMz>ILS!I>kn`S)4Tuu(gLjD<--Vej$w+Yvi+0x>yIrov$!)ik25n9E~H_DB@^z)z^0GAh+#v20g1D^Lvb%k$r zJdFEm{6I=r)kjl98a2m!ULhs?jx7^AT=gJG^yVeKG_3HYcY;y9;;e9^_2K2N5HK?H zZme;`4_N)6l+>8E?J2Z8uhyNR-$K&GYt9M18K)oH91^vp z^4BRX$9_p;v9DA|MiswH%iZHs?1`&xNy*txNzY`Z^$fjl98LaOe<*LK1J;wbfX}*K z%KJgGJ+4!B-b_sb%j&U|xTS?_=T2=?Jv~ax--_y!FXEe11b~sRIQNtCZAH(z2B+@) z8~=J+rA8WH>wSh+RLb{3_juf8L`RD}`^EAo>C^uH_4{JN(Py(!z^1gj#2FWpc!lUww<-hs`q-ur;}{MSd?m>hD|P z>xdZd*~7Vs>GL_fwXUtHBhK{6<|{E~bog%3{CJh3oPE9`=(8xe^zhuZg z{plRR;LTO+Ecv@}5@i+dKOZLHf2u79SnY(G(AC)|fTDK-$C1m*tYYj1m8aEf6;E^L z+6nfj*OBvWz?Z|_aTLbI+)AYFW+zWqY*|;1t&Yw3R$@~|&n~|W7IcZ@-LyIJ-VL4k zr_nahRpP;Wg{Y&`9n1A=04wlj>H2|d3?{)~)85kEPj@5g;1?Hd>{A0c;DOuf!dL54 zAjjtNES9;gNh8^buHahGBl$}V+lpspt9~+T;-zOM?3qg(Gl96WMxl9^_@Is?GE7iI zTgqXBl0S!vt;WP*LokN$XS%cUOixYc(7KQG(>t^f;c~I6dx~#eGzlU{NsbNcy!PvZ zFA-d_XF&eDfz19>S_{U3HK|2O|!dfw~aR& z=v)r^)11E=P_A3@?l49k-iXRU(v=N-<3e>j)6RKgQ-PMsv09pB1zy^>KW5$L8t_nfUgZ)2A`l5!<41UI5Cbx!6|g zavjPSXVz^zBu$5QP4BM#Kb+tVs+MQ}>96jM^%+?HuDc=pZQPHys)K;mi`o9}4!k-! z@wa@>GbVe`=fU5xyG-`I&bN$8x1@UhGHu(KPNo?pd`jT&-zSG|72nrfZGUEck@~&? z8ZULHz6s`tk&+t*k(M^-C1;-l*0gh~WuGsyFYD5u9`H|pieDGc&@5Mk)D5^oeN2%; z%A0I0kxngF8c_MkBYY*gurp-&rkt}|BoSq1g51eXcXi_%sb@Zo$BEv5JNth%HCP^~ zdYW~@!&?x3aE4p+hb>s!OCufK^lW0tcqTnV|Abt?wB3czs7}~;4){`$<e>qbM8r@%)g_ms*zcmuBhq>^j%vpXI}6e7;ckDM)A_O zxzH*s`HWw3cRTHFxT{#v_383Hz{hQ}=z9A7VCl(u5a8SD$iHy_yx-{AZz2*D&)EI~o^-6kd+4G^TqtMpy;Z!A z(Xs!EWi*4BdL`f&kAJlF^l{EI$gc~;{M=Ewe07d+Osz70usAy#ly{ygo)AOUy?4Rx zs=)(ZtZey8*dO*-x7h&DZ`ogM8?=8Jy%L&y9f^B%C(g7RYk+i61Huv4aNf@rkQ_MY zdg%@{oFbgIw=$mGv`c!tvA#@Q(NnI*X4FadgxlfQuUxHt&!M@ps?fE&Rrd(Egb3I^ z=C-Q5BM7BjFEyu52tKF|7&GYMmTe%5R++xr{^)vIUA1_tyDFfdK*RaparN2Hr94IYMPE^^sprh5V3 z?$)+%UcUFqJE^zJr@BX*Yx<|#75mA-CxF&Jl>Fr54)a8k{As=;;ppVxudA7@E;S|L1aR z`f6um?EBCR`&%^jr{i}tUvAznS{(u_9hn)z?Ss!3)c5n94@aI!z|73e;#ROTz#HDl}pe>w_u8Fe# znq-#^VP--^{eO{mR!?zs;nqijy99T4861Mc-~@Mf8=OHyaJRwT-E{~W+})i724@Jt z5(s&7_^Q4-|G??$i)UB&zS#SsYuD3j{Z?|yf2SwpQbJ=zs*s_rJvpOjs|exuP1c4B z?5?IJJMsFSgsws#YDfX!LW)2%>PF0+^=t%vI+`lmL42VE=^>g*aA*Um0nqqZLqAcC zGzz0BaVm>w#A#qa*{H`UX^)HMlk$gZ82I0L)8?1h3+DM9Hy#yi#(us*KNbCE=As&V z3LX+0Y~MSPMCB3_*7L28JPw=S04Wo%Mz6E+qZ#KTNnIL6jFZ^$%8wP^;oI)+@EBGs zUqOWoZl{3=bYHGKJ1UyAFAQ&;A4R86z08sW)s}zeh1O@tduyHBq|KwIM2){NIVr}v zbR>8&6NBg_Y^|wd(1^rW08rkeLa^{{B6jQyT7wr-cVeAcXM&f5+2p*?d;*P$5Qt6f z%o39Ts;ZU<4}bEF7$6?)!uc6K(al2IXJm=(sPS%7cuU!n{7AUz4jGeBiX~g0iJAH2 z32|Ok&Gk#w=bphmv(=W$C%_c+Tf(rIz;$8unf}Zc+$TM=bh0xv7|TIXZcaQWPl@fg zbN>Kh@q8X(zx(R)*X0|tyjrD1K>Wtg7Q;qk#UyywbO}F2e1~hW0_ujdarJnb5Txi& zw3~EtjvsLL_bH*0u=9bbOV}0PKzyrQ`dZcWyQqL=Qw!<@L*SYIJ^Q>WVRwQ#bC*6@ zx`HefO+Hs>RnJN2z#z|m2t~g~LzufAr=1I&bDHYT$9ydqF~(1UCN{Y9@wolAQBP8K z?$BZUGyT5?Drkoy>z+o&M+V>Tg$AA`V9D4qQrUTVWd&=cnfs~|gs-8&^4Xm!-ew)i zYpl+}&iRvx3sIFqaVN^0LR3z1C^!_6Jo+Zf#*ODX11l^+`zuusRB{TeZW|u_OJ(bM zZRhDmrStNu7lxWXydOAqkNi~JcKTV4Y5OoMBgQ>7Ui6$j&>UE{Rnk|Z>NTrIfj4m3 z&{_gU*FhHqp1X+jVP%&cJC`xi6a||M3RZb(Ml~NbU~}iw2>1(G0>o zjK_DpMGsZ0u}y7}XVm50CH7ljVQn`o6N+t#&oigH?W(Mc_cnOz+MPEDtEoYM5bRYX zP5mYD_(`y1_umub9@)|F!Yzy*Ed=KN3ewpA2Q$Xn3 zc;qGtgMkhQMJB{0wJ#cpM??zA8;Vg!o%kQ0m&`oppOOu7jkd?sC(^~+sbz^~r{;QH zaX6MZ1X7{LaY9ov+Sl|M=8dT2U-Sj+To!aADX6NqK>|7nP69&h*2?@{btqt$_`pgY zyD73Yc-9^4T75dewJ@;)L{vQY$dZSp>9Dcsnik$C!bt0?Y5q37$Jm(?8AG&$7Lug8 zoXrN2w4u8%pz3e`2IB%Ae&~l3w$!m`NBm}W0EBnuyJA)=)2!-A0%$vb2LCP+aFu6) zvaYtag6Rkt@;N^Z)2Q0U;up=FB|AakxmZtH`5St@TIItW!0iu?q_7?SUF-t`>kIs8 zGk8FC0|t5eBgYtojlnjq@Ju+*6*!Te?3nOR^F~1nUe!aGG#5fvDvR3uZw|VufpRAn z6Ak9P;C@~OxwMew)lU17*-7QORninRhV*n;vZP&!UgsDq$`AVal<{tdLU`HZEEB%E z40!n5G4JwVfoib`nv@Z{>RR{9S1;mIvB;ex+-HB!a!%Wghfr0^qAq6{i=BVS8_6@m zhyC-#Hx=0Cij+-rqdSf=tY_D-Y}-$O8Jl`v0?2a<+v>_J+u#iBRMYQx{3|krd#9&b zwnEoO)Nlak9P{*uwcuUI3+;8D!w942HQX+@a!_-%8$B|(0=tIi4Jjvsp5-z z7Q2zSXZxM6YChoj(uK91k8;y3O_tBcAaKBs$x*~MW$cqa4UF%k-AbGJw1*3f4|!(D z%c)x~a#@wtXuJPFNo)?=TnWV9pwKVoOUGIk)+EMK*vevgJ7lu6N(=LsWgcp8ORN9Gpn$p^% z)(2dA+>q&wF}QxEX>0P~~g~KaR+|+&5UasN$I`%;LKMEJUXCqUYK>~2$L7!Ef}on5Mmm^yICY}r?s!TbvES!EH-yN^bXRH-fh5E+8Jz3WH{|pSZ#CqT_t{V4Wwi}Et9ft zsV?gpOa9C}uT&z!!~u+oGwgD8Ybr3o>)04FVfwLcquy8gD*cVWDU?dwS_y$(2~;&H zNpRor>lrp{n`zpNV9kDiD~kMgjj7s>{&MAWm7|>2&Q8czKygc>*au5D)+-|l3P+Mb zNA_Dj?fl|c?<8zzj327+azf%$xTw|SDWjAIS~)V}c>?yeeQC+^0;_tbuFgbIq<7OL zy-GJ1bI>`MbHT;Yfqz3r(TEFy(o85dA^nsTJFkGMwoAg z`j-Eaw#$uvLEieBQay!oVmZD-@*KW^>MBGxv3Gg29ABlK!N{`Eq{UA{;SG6*YTtlM z0SK<3pD4D9v9%L?9;qHv=*MgQhMOpdPfpsI5{>nq`ZqWrMUmc02DRP8SIXod9~!dh zw(APKY&QbVznY!yFwF5JbGl1xXY>vnWJe2XaaZ<(?RT~KRG@WP7Cd?O|$-ep#QGNn#d&S2JyJ=JNqKLylHPooLm zlu=Z$4w;-+Xx@vY&hjF+?L21-%y;i*DAAq%27Fl@qXFb3VQ(YxK|5fwqD>kn?<>kH zIeHw{3>gCsSUMc+9H>VWPfTBn@pHNdsTJ%`OhdwnsT=Tv+&OM`dD_7c@+&rtzO7LS zCOz}mn|rrKa$2nPQ1Q+NO3B@ai!!;ttt>TPZS6OLQ@*G_o>E_VcPZ`p=KNjA>5@fF zCpyREKhwZ#n?eEXM{?NpdzVpD;=0Y+VvcR=SW?@jFKPgC%nVid?_9eC$|I*Zn?YcXF=n#d zY^}GH*G{K$>WNmFo6lq^>4=FwT${!CC?6{^UH-*nDm(hlmmsfug&ZC^z3;}7R@mI7 zzdRYCV8wae@K=?By*+g}e^RfLp}S2fT~-{^5aYm9G!G`x-CRpg5SujH`Hpc0WV}z0{NIgqe&fq1(`6AN!jbXml z8Q;EE$$pn-E#h9Kfz9t{1p1Squa#e8?-Se3On&vvhuWLRcp=_Mnc?oZor`cG!N^ss zI%~6&U>?pS%`=5RnsOt)8_J<~2|Y{*be#r21&e1kOm<}Z0*)(n^|N?X#bqB&%Gya4 zvP)P~8zU)LD?*Z*GvPrRcfA$ITKoWC-jQTX*(O7H5I8%aobj}rq{k?>(Nw$(-fNy6 zz+izjkrOMI%q3p7YsaF!QP14Y_F3@*&GLn~YW;G`qo6$pFeW9zAX=Tc4(Yn}RevQ+ z_)Gd%fEEXJ9nI(zS=eIcgd%OE+on$YtNuEYY3AjyMjji`Z>aLRubn|cjVW!5J2a`? zT*Ur&%*8jq3p+miU$Gse09t%B1P+dEGn?TqrW z;HaA#&S)fxEXrgeV0b1R31A?qY{#X_tEx{qZMsUb+31-z6=k)zv{HoWvpdMgNy#KY z5s##c`Iw|WE)biAW6=0hu?KrEU7PtXj7eds?b#0On5Du7G)5YBI`SY@*eTKnZfPW~ z_`uYk0<_Ef5lYI~L$;F~vs zIRGU37)QcPuk5+Btl(#%8K0X1^v{kAYmsqxU~5{CBIKmajSRB`mk}SAC+YiL3(v|9 zWqA)zwGXbOKV5z)m=^wiXOWr2NU@pZ^y^4xThlfS`Enyr-*_ZI{!w{GztjlOiLyV*eo4cZU8OakT?u<%5k zpK@PY%i)#nG0wGZR^9@Pe8q)Npptk$b;iGlq3qM1juH&aSI)E^+(%obfJ3mx*awAI zHp*uE-DP|8O_f~oTw5_p-0(v?>J4zR6Q%J{g@W|6IyJs@Bb*|FrWMtGQ3$qF2HJ!L z$2(9!gbR!|xU*0wv z(%n>Y(T4kGIrBgyQt&`@$a09{4B(ab9WQH*C5zrY`oYk|4x z?s^?UN7ZxgRB8XPx`dsMG=BlUqsU}VrJ`=`d>|)0$fQ3qgCbzp>xv9C|+8;bJ zy)*};!+jUBFR<-|Zg0;77HZw%I`OGPniS$!F(H`kF~ELej;3&1&Y*LLhC>)q);xJt zs_tN$qBlnphk{RNz;YO|5!_MZqMI$=I4dX-;3nk!R_Z~#6IYl#O{4Xgi^~xK!E6yI zcAQIK;3xj_Nx0nrqYMUP9i1a}Pank$oMN?Co)1`6um5bPUIn zv0A94%gHX@xQ^0oabcnjaq$L5$Dh_U0=shhaS?Y1PiXS1}bjV2I&~*6wWnfTV&4F z*B>j^rPotf5PxW?KU5s{X{`ouWcrO#<tx_ zD+EzrVUq?`GfCm27l?j;w%Tt4FHuk8lo9eeA~0A|DL( z&XUV-hej`I@xMACfe+G6i05M0ejU6psL3&PKP_2Fm1h8mbJ@eZb4Mee3osFFRb3DT zV)J(wY@Xu|)1RGy5jgq<^Nhnb&zJ#LZ3rvD3QKMh2h`ip3Vvf^Hc!CHr*o&8M7Q1P z^T%93`n<7+`Q&`-@2h^5el`j1wop>VZw(GV%F$o@TAfpu^E}$Dtv?9rdS!1BW%Jj+ z!R|spw9DFh6CfZCwH$GkzXhj7qEyPvR@_q_iS~+_x7lJheJ^`0GtmfE(=UUElyX4& znuU)Y=4HjyKE-@JS;bVTGg58N#mkU3Go+pqLauJ!J{XVkuGEBf{G6akGe=a7R`mfb zbJ+`!T(djIc1}$pucp|sS7e?eFUo?W<_z@IqT-0$>`3Khrm$VZFH2(*|AZeh?h`U; zvqFPcZW3R|BV=r|>wSH34@R^!G z)HxK{j3hwG6u4ZpCrn-t!BjcMAKYNNr`S&@Y5o5 z7;xbyZA$U7)&ad2G#htLxUVF* z`P1KM4v7>OC>5$)3en%Dg#@NnRJ zB3w1}5U2=5I_RoM%6a^#C-|p*=f4D?rNN-ZGHjNkQ+tU6sN1fL7qsaM5p~1y($}iO zix_i5Q)i1^V9ruTs(}p_>9?5&jvu86HP~uz@rA#LYVV=nb?@rt7%k!d6a+L+G+j*e zri5+4dTcKDc=V}KUL(QLn2BUI>f!$6u4YS3Mu#aMTEnd87fgsv)TnKc;&@t1vcRBaT>5_ZkTIL?0AwLwsQQeN9o}@N4Emh?0=CP@1qIGxxj=- zMq-ekEcauUCvOgMbjGX4?R>nYNSF0DiWc6US5UZ!c&@qVhenP!%9%2}&>z(CJq~bQOmTzx zS4A&2Edh%$0t1G9v%ZXQ{ppC&rnHJc*5#g*`p*W;oEjX4fasb=;ocggfcdGVmP+n% z-JyG@Zp}7vV|0REN->whr0GbP^d5(F(1E=P@pXn1#{*b!ZajXApC~5zb9!##*}O6; zf<|e@yMTE?^aMY1DsJD8x^$HP-brht=<0FhJwPR~A#ZQS;V@U$GpKaBy1EGe!@yuE zX`&;pK_qGZBw(n%oKbM(gH>Zub<=v<)>}wIwDI9kF?>Hiv9I>J`*eqggSDxrGqE0P z)%QnIaulK_!kG)r&J{bU6}W@6!rQLK4(;{m@qHgD;`Ooj2jV<>keILJ36d{&Puuc& z);&Dr;IXq@@I-joEw4&TCZI>dUfipb5Nqorb2NejKHc5y+i{jJ^sLm?Ha2U|P&!HlpA_?J`pzqJY zdT=Wvay7DM%5T+})u4Z`j#*Q^+pkYLh+zIwhyCh2*Y2U8p9lf}P6hfc_WMQu9X%G% zxm$dY`g=N`IO(hX`IDCyH)^klNNRD3{Y+|c4Qyj{mG!Xyxw-mGk6AKy4lhvax2x)6 z89)W0|KZ5$b&B(%m?XYUsCP^AHhK9WQW!ML1ocRn7~-|pDz>4l6BUP;ZD zxh|dZv0SQRNOiioK`Tj_d{ZBm;+gvNFAA6qNZ~X@F?l%(Desx@Sm<m|gA zjKWk^a5FR*dE`&Ed{HLfjzTAak#6}g>`C4t)%IGYz)bixSA6t<^p z&!=7hOwvnjva|GY@c(IxjAN6+hfw$RyikmD=>rr+&qJh8^$;{-#W zRVQ%m{D@u9geY!D8Eh_$7l#6Rh6OfL9Se5;1a}7RKz(kCS!X%jkJ{Be$7#*7(PNgF zD&*czFl_Ixi+B&)e_@$*h`ML} zXY@6tS7v<06pi?+yuj&JXw^D8(}w9junk7;gS<9mT#ot6`_iDc#QbCe!GQrQ5nh&tF?sU(^ZvMkqVJ_5IsIUd)x5UT*KwMpjeM;PC7eWkQKe)WLr)qagYEh?|R3{YwF zp#Skr@cT$&-$NUQHSu)JU#$@JP96=|5wC|0C+vE})>Q@2seLcXYD2?S_xdYJS#GK) z5Ke?`U$punGx?k;GS!S* z_YX|>EulqNMLDR|tRzm>`v8i_K!$H9Io4Aveo_?Wn~; z$e=c!6>8fAiXEs6K)`&ZbmRIJ+2`!)FpjL1`^14|N_=oTD3Q*G0aO0e5MCXZ_5rtZ)AD>82%g!l0Wk1*;{w9OteP9Nx<>);km zbS!^%Tmo}s1w6~uV#oqxm=`NLH*H0YF*g_>9rCA^d~gRNpq&b$r$n}Udq7o+`ttTe z7KsuqL{&m{lE8%yf$OR8& z#nnMZDUGHbo^@&`bz5ydW)oV^oEcHxlF;%w6sU|a)xi`3rezL!2(eVu(mmnj+M23t zGpJC>5ea;>xs6{J|2<$=()@#?>hE-myiH(22LmieoL1{D4gy~6}WSqIlX*J8h~1NABk0dA)GduW$1=BNy0hJ z8&5S!Jfl(`=OSEKa;*Ylz2>iWiJCQqw)3EGKR8$2;sUoAyY?!7gOv>qAz8@`)Gq(u_?S zniZ#&(b>iKO1Od+eVW9m0ns3~PYx`Y+qhFG2RLT@CE3hBgitGzO%^;2r8*_B1Mg^r zdzENIjjOCc!ED$c59GzjIc<&MWJ#`@2e&ZEY7QIxA5KpoI_^-mP&=L8iByUil7++LU z`ZWb5Xf3>ZnkKlok>jsz@C|gQuhqXS7|9xIqmKZ6_o{Pa+91UGF?-g6zJSp@(acRE zTc_`O!14ogOv&iUmi1MN>I<%T-VgDW3Llt@+a6@&n$Ca81%BG}>t@V!LcBiYE7ykh z$uIl16pj+!M8E#TE{V$>5A#hIIvVF9jp~73D63W7RDyxGXU(C>rgxBJFZ4`!+xF{c z^Vt^B2I9le0auP!8S~jGgUq8{o?!jxuL9OoMYU^#Tfh3|;JS;D zFDUEZ;e5^g8g$6lH*#=OdDgj(o7nxT`?#*Jv4uI4o! zG!cUg`NMtL1TOD8I9$}pMRyMrJY}QO2-uPgd2sR3o%#`%4mE}3-M3N4lziU0po5vS zg&=8RRcnWU;@tS(=eTleJn{&|Hlmr+E5F@Z(8!*A^~?Mn1bfT4!g-Flo4h9pGZygN zS0tj3PF_7nQ0bgJc(0ZN*uUgm#LA%zwCCFFS?K0OEJuIpY^!>tDOoWei&!VLC8m;Q zOR8pdI*M=zeAjpWDjO$HA7K`F5}eXx3}LQb4{axvXO`<0%uR1X&zmhHEc@fm>Z(=t z;xfddJ=D?$BBlbam$6Q&OcY!pzD2(eT(Y?1lOEpNwV--J21HCdEXuSNb}()8mi6?B zXOpVyBa9pb_1}*ID(dP9#S{2BU`X+Qw9k65ppHCYC%)xL70a$GsOzg7QcXfK(|k=S zWd4)|DJIAk>Dv0v)I!A6To6B90Ws+UjTVj~2k%hf0tJSC{DL@bPL!2X{WN|oJxOIFy;d&SpIm~Pq#=N@~ZPQG)BT@q>Wy)8<0VWbtiI){N zec6t2Dzp9ycSc93U1S^t4Kea@gRiz%4OJctLR<x_aE{MPs$MK;$!b6^goHdBjO`?*O7;{R4+gKY5%K1ZOV`D=8B69 zLSN5s?VK!0d5$m2&}YUH{52@+)t!DJS_MwV5F)Q-(EF|159t@0LV)7)e>P?2^~!O+ zsP4tTtJ+6=A~Voap&wcLZey4hR(%>;5wu<_41UYl$(%yo5cuj~fjNS443KaYBrq)W zAvQ^Pno>^3fhk(yK6t8LlqCz<8*;;S5FOUUfl`V>!8f_JtULNdxJwdpsWs=y+-4-w zzH%Y%tYv@k=xY-UQ|prKN;_F)H8t6PP^X76WJ?h*GnGG44U0?s71qGmg#V4=SqY5_ z;b(((z$cl|8#9f6Qzk)n$a?}LafS2JDGsxQPMwW{j*{utkll3%^7hy5_yPy=-0`L_i z+LQ6{_R79t5D5xUuQ-*>=Sx5&aMnKLcsYWQ#M7t=WEL+F%IHbN7i>jG%9OE;ETYAJ zY^$aZ37(e{`Jd0_!Lg9zgHRfKxOkSQSsuSDV|`Qf&C2}EvR~_wDtRJleBKW^cqZKP zMYxhAb4GNOx?EQ0LX7$q8BRjCgivRB`Cd71E5K8i1c(ax^h33eFz=!~d2Fhn-3528 zy_I*G=zaMnbL%B`5d;@Ock!ekI$pHCG^rkhe7!)aXp_?zrX#M>+yy89Od&?CTuv~h zim>A3)5X0j^lm?_%93F~JZOCt$$$DH?V~LaJpr+llG@k8OFUg+k!_s;MT`jqaMg5J zptT^mY7y(5mHP`&Y|(&#!hhHATTd|ly&cojB6nLl-pU7mWWjqRqTXTk08X=E%iav- z55UkA(vdB#ycEv!aOW8R5|U$a`<1OaDg{g+tcwnhWXf`gvylT>?a<7qf9R+$)7txr zxsfStYQDeaQ5>6L601E)3;1R%6ix6$M?p_M!CQSu9yaW^w-^+=;O1**4OBcqfMrt| zL#g?E`nmCEqX^c=Dfnl)b$$Ce@mYeFs&ZE4*1%R>Kbwcvn63)v?f6LBYE*u@7%n35 z3#=}yPSL<%uAy?L6>7702J1u1?fqHrLYaY??81 zlqPwvo@7?FX2#tw9a|P^VwXWFzNw(&82R}bL5uO1^nAtAO3>@TQA09*m@gx?KH}DQ zVM1O@_Z0|}I8aEyZpfd>wgt?i?{s=QHLY2&R^~wBTx5Ae^fp}m z$|=f|dM84Mf=K}8VWWjyrn+5d+NNR5sux*K@pS2BDSWQE1uRE?&kv6ld-cbMNS)rk zk;p@-9L1w7F;*DcI>gP7YU{z@TVW)e!ZMMyhJ9ix1p7#HpY|-w6dRne!T?K^kSCaluFK8P;I{-qwx%NVmh2qCA+ z$OX;A7&E-q8XSPynS~Kum0UW(-{$pg+ChM^G3a<#N+Ncw`q-}G9=gRC$K3s1Bz7!Y zG?r!OCke-PN`jB_b^e%fwpCqxx;^AG#yH`LQxlSyr6iq~gsYHq3EE&<3j8-}>Z?5Q zi`H+#|3JIW$6lYyk$!zmD@(?bv|~6^TCtHMK1^Luo>bxV^=nM?rS zRvn8|7nNiTVxv@h z{D9C`T*y*K?~xH~QU9%VMdw$ngs+HP6mlUxwo{k0eDs>O5p?>15nOJzevA3sEceFyN z(gn3o06`d@_gJAa=a&>OIbGHi&1OiD;5-FU+^*JEzkw#%iZahkyE8#ucZxn{VM>-Y z@m=ZoouuRtBx4wz-Q1+lZq$=~5zo&m)k!YY{fSWWrIUFP0ye@rZjqWgYK(kb zGST@jbmias-$^Xf+e=J&M&j6NJvy1mGW9jsR&g^%n#>c>1t-Cjz+7#+VqkjG2t=j* zZpZid@4x=|^60WtzuesDJ!+P%p`YhY%F@O|*Qgbzo#PxlA}0@>z6JTeX-th{A8K6v z5#owKsffnO<<0SoyB+_=Qi|NCU|jFpAtZyz!Mxx(Uu#5Dh$3_YYWtSgwM$bb<5m{o z+zGG$Jj|Vz|Er(xQu!7txZ zjRRse_z8EMq!ErymAvw4Go;|=i{dbDgj>=|2WDm%^Oh9R`Mx}#+Pj?e6daZeC_wJ# z9RsrNPRE}~-#lDi_ecDB-n=xc_J1EyIJ}^l9_}=f(zBhkk{>T>Vr$+kORG6D!CheB zb1HjywGWbpI-wI#CYCOySEUr9+px;@GgFrG(~IZJ#q`5!#v81KDnIw#;9oYtRk#cN zxK?Pr^%0`6tw=1%a?W1;^3O^KZm+v8%|XFU<)-?K53j` zvST2ClI=J4YE}I5&#-a!(XbC z_Nh7GQJN0_#aLj~DvN+Ng$qwp5FEo_6Q;&r3gUgggRuHH_kCLe6`^J4wy#eRn|8%v zQ20T;>IB~HJ4i?q3D&%)9o?vON16b^@m%bC23wl-RSEL1(T42&kmiRGgmIXXcTZ3? ziCArXewutYfp&&?oI^;SL@fn17y`v)XZG0L~A3!t3rnlY2MS4?ea5Bcg zo3yp&D)8WQOzg@T)L%1Q5iO{=IH`_O?B6F>_-uvGzH_3fk5g7{9(=@lKOBes{6465 zBCB4n$UJ(qk0kw3W^LEwnb*)jGu^dH8IY|OPuc0sq zDz#DE5vWlqY1ntf!%GLHkiYavr& zlkYkn#xk6Uf!KtU?W-vA;5FZD))tO}ZxbfwsazLV;u5=^Y+^U9FXEK9oMAP3%{QM% zVmP#NURq5??g*OTrw5p%w|cm6xj(IuS@%@6^-a&}-R*i|tgR1oxX^ih0 z>-Q&*kQX=pDJ}RG`K5MM-T*IQOJz-a?X>qDufF1*XBm6pj+&nyVUlXI!{76mdK&N0 zTOwxjQGEr*C5?*pw)e|*YQOL6qNH0?erwzA(G=-qOnir$wqXD66~w9d8Fh=9Ex%=BEqw+`V}eF!FoAk%M|L-kd%{@@=eX> z5TzLxfw^PVuUQC7jq83HzsUOpx6e~vXBt}Z?mm3lTkBC+8%wggtjA$`lg9lOIe5$P z^v>RLy30YU))N?z9mA)>{8KC<63S#&TZ_kpsp2G5`auNIBjhq<3Y^R*g?;T_sZofePS9)3&+9_Wf@o`_{(A@99#chaAK# z{@My~Mr}1OukR;&hYXKL1-=T`F=sEh{vq}@*n zXXc?{9^MG1+k1EejK%Z6jtygyh)(WE#E6UAGxCR*k>jli&71fT`y!t+#PeOMoh1}~ z@>Z`UB-9a$Sj9&~SP`j$bgCn;bLrFAbxAaS5|ERB{qRgy&0U88=1$uG`1qo#e$y4} zG+bZ&DU`7p=A;eMonP7X#Rv0h1XjiHuzI)Z`LrT4CWzet)0#>?DK-)KEHFeq*wBQw zK7%|JBjTrIuakRc2v`&y;y~h#+-Lffgvf11BE|3a^js)D+2f|72}dMNm~E$MZOeWa zv2EG=PCw9_m{$Xg(yc+n zc^~^g;=JXc9kA=jy3u&gj9H0GLnY;5qvA5;j`2QB5J+}ylerPU#sRgrzr%F0?-s$T zg@>UJdv^HZA{QKr@`&>r#8o3IQkH+%ey9(qK-Y`5j#r$kFV(4YYWfiIp82c`O}U;|_2 zPtFw5rCvhbB2NfLU=j?7PBDl>qK=)PChWG|wQTfUNhiNywa?-u8eVu+IM3IZle92o z01;1mu2B*^#B03(m_|E184x>`$F&UgdsN@F&iM;}(fu)2$&=r!{fKbHKuX5wqef@E zM_3W2zT+n^K97xM3#z#SpLEj6JC=o??NlFp5_0V8I2Ufq!5#HP{k1jqmm@rvbqr{j z_nzug3}~(M@L=1mW6!^ZKNUR{5&l8r)m=ir2dfs9A1$K6%sTvk0h2LPgbs zW0*#%Tf|NigBIe*ZU)48Fc2j#hH^#VS61%WTVo$lo{d~!la$zy^Tgo3 z-U&%Gb_^$?W(CTCrU=x4F*9R)1PwUEe#11$nU&ZFnIQQh?>?fV2uX^cw@#h)tOAz) zz73Y@;YF^?nQyb=ZcVHzW!-3cdr9z}@e5+*no;H6^sD?{4Tx!|LQx7FYYq&wf8wi* zrb3RqcwozPF?7lqMi_pAwe%4`7gY6h+>Xq%EGl!yBiCFDHP949c*A8@lT;I4e@ORRx<3zi2!DMkNk5Mh0_R#7fX;~dnZBK4YeH$W(~zR zr!?6un*#zllsaBvd^%Cn2`ueCD?5ff)ENg0JX~be9lPHh8CN#4Tec` zyS)h_eNNB>_=(#$hdhylC`sdTBKbAi>!b}i5w*X59OrQsOOI>1(X3cbAwpPENFasa=h$M~USh@=67@Ks7$f$%bdzCHk}je# zf?d_3!D)AaRvv9c1Eox<8j0I*Q8Mt&%@!$deI@g{imGL^B=bWK3ipVHyTw!Q{Q)Um zKSJrB*4^ZoxqAoy!wl-l2?XLbus-TfuJAB6`! zU+%jl4E+at?=Ps|Z1q72NEkWg(^D*Z8zhoSQ~3G*bUAYIyh8~uG}hyT#K)?Siwi%hBdY)5ZG6H6VknQl zLqI?n1i8xT1{9iW&f-S!;a|@m-Vz~1ej}I}jcKB&CFl=t!!Xpy&z=9TkDCtd43Lpm zG(W{5WV9BdP-60pLh{m~H(uQq|K@@%6DW;YyFi(oQgG#jx3U6#K#IV{mRliLZ}4vY z*@dd)neJgniQ4E$`((!pwU?T9z!cjeTr|%xT$qxjAZ|BHelk-paCk8daE7}rR#XuE zjnwm@<$qGf_@f=~Hl|D)u~nlOyS((zm-hOp0rxnKO*dZF}&i0ki9E zC3-IlGyfrcHtc;{+5h1R{fOVobTJux8FxSzP4C? z{jdJl&Yg}!cWtgHTa^Uv+`%frRy zp~vCi-`Bg7+0QTKPo!NfckCRz3nye}5Y4}4%{z;2J08y&;389J6U+5B>qXUtqW^fs zpFjWi`n)Op`0*ciPbPMn7{EsQOz*!b;=IlO+(;i>7nr5HiFS}qD4(ujmVmq8E$6UB zewf_nE^LTT*ZW__ut}kBQiI|#QV27)lKj`()BhU(`}pkt1N%G>X7Ra!n{IOl%Jp~7 zX!aHwr+f-FPg>#$o%*x{w*2)^RpKh(%wx_` z_37%t*gXB9a)6-{7Yc*x&fUWE&%}%~@C$Sb+y+%uN*k z@b2tM;KB3^8l5MM9wlK_U{9*DgC-V2CXK^}KS)WL^S>!?`)$7FY(q}t>VdHCw)%{F z2b{6eC9s9Ut2NKJR*NFOalg5{yLZoUM|w9;?Z7=E4c5{X&e_i{dOEm+TWN1Fm%!nWx$;jKrS6q!rhVnnXqtWJ1&qn2p1!SC(uaC zKK9wL`z2KCNtQ@O=mq3#$|9azx~M+&WEvpdYC>cImcjG%tZY+B@e^~hoP1~Hc8Qi? ztC7T?^;@?ABx@Qq0zOjia6}2e;Z!>v;cI)ZrKvo${maT8rH-a)U8Ru6V!glG1D3cB z(;G{*SH{rDxz;*}Q6H+bowKPP3ym1=6WafcwDdhjE8_=#h=p<&80TPHn)8jr$HBjI zQQk({?=a%2R#QuQ3@Umt#u7q_4-7VlvBJg=<}|T{93EzHabhg4tr>r8YlI&91aLdz zeq4PsNwcQ*FH`#{7AFPHK9+Do>;`*%XWE}1OCs(H_RP!uSuKYiS%KloiKm>yx7i&x}&9cjpWnPCm;w}SK6|k;#f1%F|BUK{3fh9I z``|SouTi;73@)Oi>7_mz;<)Mw1X$P7yTN}+J%cL=8Fyw#7ozxA!pPv|npbfNrW9sa z2s1jo{OC{IAx@-gd6**q6StC=!R;3NQ7_wx>709ypl>f9QsM6HT^z4lFmNXTbK&w` zaqCK7AP7=k9H^ckPakG5R88)`)bKIhe))v-QpWufa@Z9~-*E$M5_c< ztHi#%wh1c2rpeE1vdn`0a=%f@lf8M2(Dq2u7RhSx@PhlZ@LdnbaX|uA?m6*$hOzH@pK%5aNQ*b0? zEBw@a&OIL9E}l=sq?vWiWe+V^p22)Ao**uvjK-&x98Mx;y#v2Edy~JN2aWr^2h8|IF~*6kow!YU1z^%{J)d`Rofw}(z*mqylQg79 ztJ1(BblGFL9C`qkImI9R`*IaN64DZ#YFm#Oem2CJ@s$iAm4KBA&#T1b0CgmBgcUZ4 z>x@f%=!~`dP+0IbWQYCoj8_z`>P?bJ2k!VDf*U&@(1A;%KD2cAW!ejRz3~vK_aUht z)W#Hk5<^v$Oe`_T^0TZKj&0 z$EPE7<=JNVX#+a4-h`jrhiYDF4b1r300Hh2 z>y$%!MWRu9qXwIZ-g_@U*Ipz7k{1te4^SN2-M=n0y%UJ{et5dC#B^|u zDjIQ43dnQeB56#P5{cC({EA<9Tb)19gl!Dv53#7`e^>cG+r&RwM&&BS@7MOFz(v+e z^H27+tDG^g9YtZs2aTHNhj$YFjcx(2iUU*;qxr{)Su|2btl=!VbYF$m%h>2+pwSn% z&Wt8k?P$NA%el@wcsp~X-;W-fL4$@o-AcaAJduc+0wm>ZMQzi2Sz-)$n1<6e(UD$Iz-AW6jKKo+*Ckc%(FX`&`$1FYUO< zs@O*F>8St?4de3_*jgJAD1&hYHG#!!g3w8w>gLiY? zGE!;o#;<1Ahh->XZ6?edpPZs+&y7U0b!Qdmz>M!^hNTbMU+#B8X)lI!LrN< z_DH6Hzz)JcH?S}6|3BZot_1kw23F$4wn)h*d;DZ}e1EF7Q+V`(M5F!m42V$ae&q}v z&%cGad)K|vW9RNo9S@NyDRqv@`?qa;_}AA6n7h0*J3+#u5D}v~%+I9JfUH~rR~EAl zxIWE(##f5~_`HekY}4O&t46SC6GXgX4UEIkrGC+LT~Fs2T>8N&LM9ryNS1xE0h;Zq7-Jl4V(vpVE)#Yd&B7j&wnrqwR+kw;P&bL=mR5tc${ z-gw9I zcuI}7u?^6_cras8s|a=x^xi{7=gdsDw@khSh)29 z(};|!`>p&L$VW2^C|M%R0@kTG`cSC@^bvkv&%!^r;tZ(y5SS@yp21_s<6DRa0IG^u zSv`MBZ&_}MGM>dx;=v?GYfFCW^Do)RtehhJaW4IO|MPQ;Z%tAa=Svmk=Mu{8T@fxn zNYz|ph`fz$y#ga!(zB8}zTJgkiHM@MEgy#s@#1DQD1Jk{!!>e+;IIyjp%$xEm3D62Z$1{rBbJDmi3WYB7vS+jn6r(tF=Hv z1NG1`n9{nXhA5Yc4u4g4lLPMjauh%<_{h~s`9zAw(MuQm0?`NM1`} z@ieS{0QuE<;(OLDyo=xc@Z0A6nLbfeuivYL8`g`oN<^6*exZ%aK#ugJjT>fT~c^3EtU;)bON?d&0eqvc_11TgvG9rDQ z)pTyx{RYuWcPS49eJtI!KGb8--g(k|xtj+0)qPTbSLW8*!mo>m7MuCs=WgyxD(tq( zT2~DAccZ!Ufo7@KdpMTqDFMCB)fN(cKI|V$Cs7uC(v(|lxrx2{KiXkzaMbBX;)Nc^c@kpI&!EO8+!oBxG9{?z>3a5Mh?D& zVj|4k#L%3EI{BkA@nX!th7hEeHUEVTFN(DG6$=YSgeI^pGgmPzjX zb=P2m^yWA_;g6Vx(h3H~-T5+Rxdll&K=G)~U_J|{q|jT>eo#YB)2|>FwI1W{6w;uy zW|!8kAOf_dkzV%DT;d9I+>+$?^5MKz9;Jssx{?VJ&X7;ZTsSj9ektOcN|(4^kNUOP zXyDAZPWjBupxHKjZk<__KE*?wpEKwK+(Z7#X-BzNShrb4=q;(3gx2RqT-4-yF8^^R z%rD?2bT1I5?FldwRNF-5{`>8bY^2};E@&cX!ZI|^CAT>jjp=d; zllZIhoSYi81zT#>8f3m`AxKLL;zxz7DmhZEJvt9~UHA*4?l}zS8h5?tTU!~b@&#r0 zD1ALV;MlBXv1q^~Jml7*J(b=~x&w=1Sf(QV)OzfY?1nGiP};ZS=( z=H$3nd*IGdayP-53-ah$WGI6gUUi-Q^;Fy``wYKJl1jJgIl)>LioKuQ_xvKL!R8vv zMukkTu@U6BZE&9>V|UDjhYe2e$R@FlJ8&Wcd?GAiH{Fkh*gMbC6Hi^5<3*O>*rH#) zb>@}rpykku<;R|F)vId;yp#QHHO;l7y=REW z!|OXUd^1vOf?WqEgrFVMHk{n$5X|fjgOAkW)@5ug(GDQygWYwPPLX_wUDfOQAyBOf zJ9J?eA&HN{6K^A!KqF-gyo@uon6A=ims$5YEVefQlAKIAY_KaA{A((>yxqjXvH{2_ zj1~R7g!Lb`GQKz457CX?$^L?BS1EKa(Dt>kPckTmgHmlAR`g{irln>~$pa`+wZE=~ zRft;BR6q54*^AN|n=vVB4dG|)=3rNZsqJ1*do6+9mvJB01?vgUTHg+HPbjn85DzIj+~%?=!7DlAED|3c@h?cPRXTc>iyg3TM+`F8e|9z`Y< zBEu79mXc=~m2ySQkl5LmInzQ3lXr>Df!~+N5?lSY#uVxZXJYXe^*gqQ9qElE`ms-( zcV6hR5-h%0zw)5vms*5w4!vQ(Q+O*MwC%Wvk*x^lPVTktUB|KpPul-{TY$C4kTDB> z{rcX!^+O|!7HO>D`W#p8(*axFEC0r48K(t{Q8;P+*tCUk%bBv}A(bu;XMKjQ{!r-z zEkvS!c8@Pd7jg!)oc6Nu)%3=jwm)Kd@>1vX6F2Igq^36IM7+Wp%o|FYmYr{&SZ8U+ zP8JP`RZ%QVr53*t(RR3q>d5~zy1klb!SloM1(y)bV<&>Uj*~u)y=hK>;mKGVgNgME zY)R zsx&oGXXB5J71=nPJ0Y(m(Ts2Uc1$>+l{|bmZfK^0dc-=$2JX;;ahdK#m%d*pkk3f( zU7(k@Lhbqh%|8p7RrzLiza4(iQ>t(7N_0?sjl65Nv0ct?YJ2YksvzX7eH`fvMOWY8 z#@j-0y1;ZW8I!-SS67d@j~@DDN}hOP`k(7h~G%Echt@0@Z4tzF{v2@H6ITHZCIHy9AO}B6Muj?>0Ga?p^ou z7K(p{qbq_uxUgp`a>f{}+l#SBPeQFS#`HB*h#SL&>{= zKC*Z~zPb#19=#`*iyd$vZ7%Ic!LQizt}_Vmd`|>-W9TQmoI@#a7a|P55NbXlQj50# zyo_{I2Qrbq(G|iI`#7HElqg6sSm(V&PYasYbRM^(xSRs*YZ6AFxu}*|5V+eY7(bzN zwuHY3yQovz*zS60;w*qK59H-%|TzqZ7h)eiDSw3AR9P~!W&MEZIb-1poiQ6{ZOUIi&OJ! zg(ZoMArZ%dKL^c24_oBF$n`mx*ctqbcD%s9pyDe~hE|WIs(z||Vy0_Z_PiPJjCQ~q zb>d$x=4qW%5+16{xWk^hi0^qLopS8C_6!t^Fw*S`(V>Ni&sS{FOD0F0DG?cPF8q$K zMvF#evn`fKLPr}!g)5y`8nH72$+2cq&^E1e!V*a|KlC>WV8_W6(~p~06{dT|o$Geh zuztZz!ZoqcqAh$BsPLb$xkb5#`{e!-LX zS+HW@ClRc3ODPp`La3X5kI-gZ1OZrA$=^YIIjxuWjmkpg*&M~|a}jPptWCsYfGM)X z4EPd8xkfs1z+h@(s;}-dEZmw9*{+sTnChchf0r-j%duRAbMLgw>m(D0?6 z$IDVXqk6@M3ZjfT>)HA_-j-7{v_{n+hxd$_TtMq5CV65Sbr*sJSN4k+cp`>dE-bT% z#Qe7mgm=|r9uF$~14RF}gDi)B1N$`4vX8J-dQm5rY&!7PR96qk1p+d-p($yUw?ANM zg8gYVo=;)$?&4tK+w6R1kKWJq{SF;|Qr;dN3Qm>~j z@%)c5nAH?p5+d&y=|y1rO{+3Il>V$WO!2~Emj1^<%ZTnKxSzhm+Zut;&ox&o2Ny_v zeS&Q`W-?|R7w5?r49uq9Hq%#~Nz(O!^&QrWlGVf&Fqap?V;WF~XYrN^*#ZCbwB@k#C@yzzx0Uv)8>h}xdhHnZNF0E)SHjayVvbdy=`cyys>HgJnM#x z&Shic(T9$5A&1V*o{id6*>|;(vh#_|gX16AZ*JVaPe1(*wBF6^)31l3H(r6tmU&h{ zow_GuAwBid&{t@kaJ&61mND$kW7>OWsL4K39!1O~EIlN5AC7Yk8luf94~kIGduU%} zIJeN@1r=BQzpN(;L+!8g{g?^~`CT$O6Oy6kQkb2(_EPbY1zodZP0@#aq5~UeX~^6c ze#08W_(B^v1OL1#?;^4hO*o$D`mjoRG+^;gU3E{Bf9L?F{JL9`V?;~4VWn-nKBxxO z1g1qsx85EY7iU}6FqZ>)sFS2BpB&P+Si}pDE{V~DM0o^sw*b3<9{gE;r=Y1IZ`w|s+h=|Fec zX#mv--JpWMZ0T?7$tNB!!)QR#UeRr??{uH-PWnAh4@^hz%v|D&pY0D;pYA!^#XRor z(F(moPd}*xMm_-!Fm@@dKIKr&EP|!&B~<{EVPlZMJ7{a`BBSAONisLvi|VuJi;*y$ ziIN9I9+zE`Of0ubZ}S|-hVjAZ4#o>^a=k?hAQ<{t=0h9Dbn~|~U>`7OyOU`s0~C)F z8SKTvurxCz&i)-ofv9s_5hWtf7Z!2#5@(^sU+4J&L%#G%85Zsjmx42?!5CawYpxd~ zKg<#-qCygz_!!-MJ7)r6@`O5g#Y%j15aOB7+lNq@F1+dUxXkqD&c{fEZV9lSPp5WH z6TeO7?TF)4tRJ(rusD^?sHr-^am|h!YCP5JZ(D>yD1NU#M_f36h;LbF$p{5m7lJgv zdb0#uQcwv5f=6p+j)W}@TTpR~Xmo-d9Dp3*c`3}C)Dm7M0ro`UMsOqef1}p@Ym5;- zU3z)9)D?AWJ*w*+NNnfEG~*C0YewSTTW(O~lE0Efd-G7QQM17`vr9Q+873Ic)P{Q?1k-kE6m z=-|4b$esk2XnVEQ>!4Px!lLEEAd>@K;P;l-K+P(K0q>t#dRPD?ZUWCC$Y}neH1HH( z_C(1)y_KE$^@+piYj>k0OFKe7GPUiZl@!g{t9kL1%?H%YbSv@8l{afvvfELT#s=o* z=H_Fcz(PJSamI46vuQF_U8Cs?11{1+vPH8hCBdEv10{NNAu9?LND{0mKFVVfAnU@A z#)hmfgK3VvGBj zZj0A@A9BOO8yEDtU0SC#rd?8f*t%1g{$?Pn;CjuvWN%J*I8%M@Ft3)g-lOwF$mCwY zU9aIVO}5Rx=7|0b7xQ~bAhx9{ z%X?em=m+90?K7pazlR-RUP-B@WT~PuDJfo%Og`RPyu=M$<9V84Sv81Ln3Bs~%-amM zP$H)|+XJPCn1^xf4lvjJl!pb-yMnPC&f7W@msm6CoYoA4huyuo1G0$Co%mK%pus$C-~Wm(-=h zUj!*EEu4To#6D@!D=}xORJ!jk8RzMcoEm&bZ(6 zT~h8pLws&5z6ZRBOe$v<8{P4!KBHel$NpI%f3KBxS9N#&uTKfODTXq!6{gIUj?e)TxPaFmaCq{5-YMpf>Y#ls z1$y>4%BO z^^J`}R!Uo4eI=+0-L5gYFFs{4@UG1jdY(`)&a{dAq}aqhAamxkMZrm`ug#&eKd=@*zR)3;t_Tt%uC2;hSyX_0z%GhTXyY$VYsT|?) zfi1SPCuwsJjoCZO?JFkHC;F?rmPo)muht(nD?>}8fMWlP$flw+w`nPu{o_mE4=yu# zMRcipR42i0IBiC61(fA zIdc|9)Tw&a{;oxe^CJvU^Jy2cS_!bWKE_f5H+NM|l(fd^C|%M8&?C%uaY~D)hW6AX zFN8xpHlU$BA+Zk4FFD1-FHS(BHTG#Lc>z(%A`=!2Ri~YU24^8sdZar-K(kXk8eD}-U z{BS}0x{a=9pSOLfligpvsZL$t_I`ZrBd3llAEp8}YUmcuDE2RbaX%b9oWT7t7}#l=^0) zMZj)y$Z(H&!+&0k|ooLifR5X#bV+Al-_@~gWn_~38~q=?{#LgfPm_L zkDIpwZ(TLkafWy+I=Mh@yDElw`~IF*4;WXR#&dMq(G8!6+DyP*oG*nK>s4Ab<{OWcan^Bz_|QxoZvAstBw~ zyymVoT&p6mD)E}T)^M$gz^cS+?pnjODgvt#ueoat*QyAtO1$Q-HC(GAuqyGIyVh{6 ziomMGYwlXZwJHLu60f;y4cDp&tV+D*t~Fe%BCsm)n!DC;t%|^^#B1(a!?h{`s}ird zYYo?`2&_uH=B_ndt0J%}@tV8VaIK2Ks>EyVTEn#}0;>|QxoZvAstBw~yymVoT&p6m zD)E2mt}Xv`_i*)D>Ei)i>CDmmsYX^nK$vmm!r7ZEopI6;@#d}vaNw4GTM`uCoOtqO zOQZUm`Ok^!uW~%HGTZu<4OK3h*h;o+`*6z4@b&APr!R2lVmkfOza!SKywhavo$8b3 z`iUsJD~ab4u0>yCAM#om?vJR;q4Wh%Db?Y>$TOVO@&J5jJ7+AExR}m_AxVQn2i4?u zUVa9;BEOU6vS*ue{P8-0bx(KywLtsyUUcf}xay}%j!sWyNm+&LBf^HLxOH^`E$-r9 z+9gpNPX*w{HZ59dIDKsD?Zq%^*ja>kkBjf_l-6~(VzA#AqsC7lvdoNqU(em0QSKDo%TLTL>PGhSMegwMz+*Cozv1buvAV)yQt_(<@Z zqaH`@HPvR+`Z@;bq&Xyh0r{m{X9c5kZs^)IXx45VIZ`yIE`$?GyB`(*a7b8dtJbb8 ziDW^1_)=7PoRYln{xHjaa?`RPQJ_HpbqU_Rrxs*d`t(kCAEjq@YeYr~6ytdhcRx-R z2H(g!Iv<)%#ojxTP@;1rqfNZyrb&jX$9m-Y9YTuhFRhaniW8K--K-&~+c6j|L=iMG z7z-atniWnLi8k>0Cf|tQ326ODGA$pw^zs_Szu?=Q=M?e#Nq6`k1mrrn3g?*h*%*0* zYK4-`z4}_B;r3ysVA{P!+izk5=kKT1T5HB1yYJay==&ip-Lq;r@!p1u%c+++X#Cj8Vzk)F?Gji%e(X9x)yyngj!Mr!>KHIi8CUcF?8noultEh!{x0=kmM7`=0 zcPklc<&QL}6i&M_5>mI*+BGjV?*+x6d0#^lQx!A{txXx)Y6C8A0fV6#Io%`e!l`{W zZjAWUrMM|pRjLBh#k1Ax?0cTIT6lkJ^4`vT8!)eTGjSp`hRJggNwUJwPv9;6& zoZM0_HJ7~V^LEpyO~jHXrJ*S6)?5s<8k?G@R+y&WcgiyENv?JmQA15!`~)Sd}dGj*;I=JMb`H)Lx*_l0w-YXpzVfB8W zW+5lPsJ$CA&c=1tI*#mgGpNv!LXA^18cUyO)U?0|$un;@#R*xy zyAmeg9V1Yh{4qd-WXnwW{^Qe#rwwK z1p7U{n)BP{kIr9?tf<~E7d`+(?Bjv_lcC<5tQ{|9zP#DQjz!pF6&t*e!&L<~4VN7qIzKWRK1S#{FUhL3u z<>}~z#$Qr#$X4fsLfFY9j1VWS?&A2mA!d|oNs2K1(d6i+(;|r-77pHb6W&V3yqi6H zT%i0BOR`w9Ct^>5xI&X3D}k(h`cPznO~(xL{D^GPmK{$$oYm`z&$g}8c()0<R;21o-J(YSoAu3?LppHsI)h#qiJKM*sRW^~Q4l~mS#(z07X zQ+8HbG(kk5hMGYYLT{`Q?QWRd9oA-G`jc=QZ5K_uh7sU(e%m>uv+-S8#~!v~d~D-m zA+RvzcwwIPc=*Lc*0;{8z3>Z_Q8TP>kw0Y)dPNJt&mGgSxVp~k9KV5An-Y)p+hVwz zW5Up&yZs7&>8!IcFGQ@O!suS#6&aWu+IfSoCN)gePlXN+?b*eC7%Ek3&kwTjwp_p9=G{2kQ6Rjex_6oRdr*_ zX8wj+$Thg{j)ExE+YCzQ?IhmukOK?t^PVcI*B%5M@P_PTywTjdcx~MLxyAdwskug9 z3?;Cr*fv&{SX~S5IBe(e9@ddK^kBtAbb;ze7TsTEQZh#-?-H=(I%*whuPlo6@$#zZ z!yy}4YVm?KF+$n$9aonST;+!>j^Db2@{MxI#%g5f$#MF*s(oOU3NSRSntkpJ#o z956H;>}a8rhA4UP;V$cu4|Zon?U}ESMF0J&`upV-5QdY}jzu3GBL3DH^vXq(3+Qu> G5B?9KJX&7> literal 2096 zcmV-02+#M4P)LH)rZ3KBNO7>$3_$f6OAA`wJX42Fn7K!u>9f+CBR z#Y&;J>@CxF+Rk{+^n3R9a$jc(LZ`?{zI5izoBQrP>vzu75ex?DQp@g>e(JvR5LHz1 zvmF<_oUG7>k;Ul7$j0kb#vP2juq((mSP!>nBvJpg1e%cLp|(k})DYsL#wi{~SH?|@ zdtihnhWoA!YY_3riU2(~uqDmz)x5zE)|d>Ez!=CF&$t;;5l+J2;}6iB{@$oCMq@EZ z55@$>a7IQwzuU6TPdPG%b@b5OJ}si=unl97$m&)aV-DjH!#-t!BE|v6Uko23p3$Ar zNxRQ1T))yhv9u(o6}cSr|29a1%Slo)D?<7*YNG?=OGc)4y^yhv@h;;>#u@GN8yVj! z@5}2l$dvA>)H*S`l7zD%9(oOX=56VTY!O=r9;O*XqF@r(lccYW24jQ>9HT&af5y0a zWq@vI(}bpVOO3kx>};q9OWt<7opwn@RqE%AzKk~*C&Mf&pC3`)A2Z$+VC!~CA(xY` z7{rpEUN?=)N)8oPgQ!$>rKaQvx{80L#8k+0GLvY$Jp1BF6V$ZEV-S%S`gtimB`%cD zH4y`p;&s1zDnjM2Wu}{^bM3gub$ljcj8dmRW!xL}25Au=6Dq6*gGhwz$Lo=dt8JEu z)mTAOMzfm4q!~n_qirG$$xOW1M^ht24tJ1oI_eD~GPzqb%E?I7Q&$yZCtiC&ebrG( zJH|68^g+!))|o16u`C&naM4)M*Grd}<;q#6GB!j?d)vYzyMf2&GPdHn&rlfKf%R0N z@v1_u?vLJKFXJceJ26r=gka&`ZHyD44_G_%xWI49_mRee#UKw@S%%RX%I?kR%s9&E zqdlh-`y%`;Q=?;Oho&?jEkV~oN1R*E@eQc8ND|{J#veA#W}$MeE%qY2--NYP$-sGw zwLYsiCJ+)q+a;=<$agZ1cmf;ffiFD87-}%$^O9}wTINV|8BfDdWq3bZ^V(N&Z!r$^ z8V(VX9HyX?g@V?Ok{`4b@GxT{qYL9tsvaEXYkNDZFtGrlq}tH2PMX%^9GW{FdksKA z%b)|ob6z%_e-vYc^8RkdTZ}|Rr08;xQUgV1!67Xf%veg*15nY~{aC~8g13paAJrZl zNn|_VU859_*^GmE(M`|5-)EKYi9+W?!6BKLolFaNos<^Adh&MEk@o83iLo3Ve7<2n zW$?uIh^82oe3e!P_3ZFH<8>vH0!S}2B1}i^aqmb(tR(~Bh$hK|6O3jY#`_ z-JNJ-480kwVO(NhHpcw#ib%1EM9!%HSl(lb0u?%R>w#*>u_vh+& z4k}|d7yA9jQ7ibb+wz#GK6d49sw!R*&Ms3}lZOn4Yx{I~_?nyTx!_Qe{P52HAk=sVet@x>iIGp4RpC zP-2`$`39K`GMuTYp;45SGzFo)0E}*zf!nu1O0dX9k@fA)scwBukJhZY!Q8B3ycf#v zq80JGl=H7gO;8)xPB4<)q|B~5Pb2wpQ8(oM5lQq8prTYNfIve?Xy|U?Yy$&e- zKqX!;Lw;V3DXkk6@I%vXAG$7?R_rl0wNHXU%|jX+Yk2k`C1t&@eo%g{k!42qCRkDd zl%0#cT4#8Lv54_8t_QHLRj2lV8n46uB8DlhO@WShbVg7Eo z$Ac8;*GNeg_Hf8zYOXL0D+n(jn+d8f4E5AmL{YdpvipP|HN@5+2W+lS#Q{ZLs$GE` zwC|Lkb{#LLp5A!9k=&-OqdQljM(h0%oXsDBKKzJ~=$d7zvgS|;&Dc^{Jx{5hj8huV z#i$>(;ymaN(DuSIigt+_gRILtOC#3ilTTW8r_mrDq!V2vAHS{S^qF?Ce(+4i6@x?~ zK5n09Z7rgzDqCX^hM$YHYr;$xB43|Eq@1zid`EqiQE!l__=W$I{l&DSfa_meo&HgX z`Oh&hl;Ie3T5RtzFcn)8o`1ILia{cgRcw$5Mwxkl^dpnNQXF7=6AVq_ITC1qf17P| zDeG`aC2cz5i=>d3qL&eg$KLb6;aAXQA`KoPo4M~e%|;26t}I!CPFbk;Dl}jx=rWRj a1Q-BzrX;*g)nEJo0000b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&GUI.currentqueuepos&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="

    ",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) +function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0,m.redraw())}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=parseInt($(window).height()/2),e=$(window).scrollTop(),f=0,g=0;"db"===a?(f=parseInt(b*listEntryHeight-d),g=f):"pl"===a&&0!==queueTracks.length&&(f=parseInt((b+2)*listEntryHeight-d),g=Math.abs(f-e),g=(f>e?"+":"-")+"="+g+"px"),isCustomScroll=!0,$.scrollTo(f>0?g:0,c,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function renderQueue(a){data=a[0],data.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(data),$("#playlist").height(queueTracks.length*listEntryHeight),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"
  • "}return g}function populateDB(a){var b=a.data||"",c=a.path||"",d=a.uplevel||0,e=a.keyword||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"",i="",j=0,k=[];if(""!==f){if("Spotify"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",b="tracks"===g?b.tracks:b.playlists,j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Spotify",i:j,querytype:g,inpath:h});document.getElementById("database-entries").innerHTML=i}if("Dirble"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Dirble",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}if("Jamendo"===f){for($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"Jamendo",i:j,querytype:g});document.getElementById("database-entries").innerHTML=i}}else{if(""===c&&""===e)return void renderLibraryHome();if($("#database-entries").removeClass("hide"),$("#db-level-up").removeClass("hide"),$("#home-blocks").addClass("hide"),c&&(GUI.currentpath=c),document.getElementById("database-entries").innerHTML="",""!==e){var l=b.length?b.length:"0",m=1===b.length?"":"s";$("#db-level-up").addClass("hide"),$("#db-search-results").removeClass("hide").html('back')}for(j=0;k=b[j];j+=1)i+=parseResponse({inputArr:k,respType:"db",i:j,inpath:c});"Webradio"===c&&(i+='
  • add newadd a webradio to your library
  • '),document.getElementById("database-entries").innerHTML=i}var n=$("span","#db-currentpath");if(n.html("album"===GUI.browsemode?"Albums"===c?c:"Albums/"+c:"artist"===GUI.browsemode?"Artists"===c?c:"Artists/"+c:"genre"===GUI.browsemode?"Genres"===c?c:"Genres/"+c:c),$("#db-homeSetup").addClass("hide"),d){var o=GUI.currentDBpos[GUI.currentDBpos[10]];$("#db-"+o).addClass("active"),customScroll("db",o,0)}else customScroll("db",0,0);loadingSpinner("db","hide")}function getDB(a){var b=a.cmd||"browse",c=a.path||"",d=a.browsemode||"file",e=a.uplevel||"",f=a.plugin||"",g=a.querytype||"",h=a.args||"";if(loadingSpinner("db"),GUI.browsemode=d,""!==f)"Spotify"===f?$.post("/db/?cmd=spotify",{plid:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e,args:h})},"json"):"Dirble"===f?$.post("/db/?cmd=dirble",{querytype:""===g?"categories":g,args:h},function(a){populateDB({data:a,path:c,plugin:f,querytype:g,uplevel:e})},"json"):"Jamendo"===f&&$.post("/db/?cmd=jamendo",{querytype:""===g?"radio":g,args:h},function(a){populateDB({data:a.results,path:c,plugin:f,querytype:g})},"json");else if("search"===b){var i=$("#db-search-keyword").val();$.post("/db/?querytype="+GUI.browsemode+"&cmd=search",{query:i},function(a){populateDB({data:a,path:c,uplevel:e,keyword:i})},"json")}else"browse"===b?$.post("/db/?cmd=browse",{path:c,browsemode:GUI.browsemode},function(a){populateDB({data:a,path:c,uplevel:e})},"json"):(loadingSpinner("db","hide"),$.post("/db/?cmd="+b,{path:c,querytype:g},function(){},"json"))}function onreleaseKnob(a){if("stop"!==GUI.state&&""!==GUI.state)if("radio"!==GUI.stream){window.clearInterval(GUI.currentKnob);var b=Math.floor(a*parseInt(GUI.json.time)/1e3);sendCmd("seek "+GUI.json.song+" "+b),$("#time").val(a),$("#countdown-display").countdown("destroy"),$("#countdown-display").countdown({since:-b,compact:!0,format:"MS"})}else $("#time").val(0).trigger("change")}function commandButton(a){var b,c=a.data("cmd");if("stop"===c)a.addClass("btn-primary"),$("#play").removeClass("btn-primary"),$("#section-index").length&&(refreshTimer(0,0,"stop"),window.clearInterval(GUI.currentKnob),$(".playlist").find("li").removeClass("active"),$("#total").html("00:00"));else{if("play"===c){var d=GUI.state;return"play"===d?(b="pause",$("#section-index").length&&$("#countdown-display").countdown("pause")):"pause"===d?(b="play",$("#section-index").length&&$("#countdown-display").countdown("resume")):"stop"===d&&(b="play",$("#section-index").length&&$("#countdown-display").countdown({since:0,compact:!0,format:"MS"})),window.clearInterval(GUI.currentKnob),void sendCmd(b)}if("previous"===c||"next"===c)$("#section-index").length&&($("#countdown-display").countdown("pause"),window.clearInterval(GUI.currentKnob));else if(a.hasClass("btn-volume")){var e,f=parseInt($("#volume").val());return null===GUI.volume&&(GUI.volume=f),"volumedn"===c&&parseInt(GUI.volume)>0?(e=parseInt(GUI.volume)-1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumeup"===c&&parseInt(GUI.volume)<100?(e=parseInt(GUI.volume)+1,GUI.volume=e,$("#volumemute").removeClass("btn-primary")):"volumemute"===c&&(0!==f?(GUI.volume=f,a.addClass("btn-primary"),e=0):(a.removeClass("btn-primary"),setvol(GUI.volume))),void(e>=0&&100>=e&&sendCmd("setvol "+e))}}a.hasClass("btn-toggle")?(b=c+(a.hasClass("btn-primary")?" 0":" 1"),a.toggleClass("btn-primary")):b=c,sendCmd(b)}function libraryHome(a){GUI.libraryhome=a[0],renderLibraryHome()}function listWLANs(a){var b="",c="",d="",e=a[0];$.each(e,function(a){b+='

    ',0!==e[a].connected&&(b+=''),1===e[a].storedprofile&&"on"===e[a].encryption?b+='':"on"===e[a].encryption?b+='':1!==e[a].storedprofile&&(b+=''),b+=""+e[a].ESSID+"

    ",1===e[a].storedprofile?d+=b:c+=b,b=""}),""===c&&(c='

    scanning for networks...

    '),document.getElementById("wifiNetworks").innerHTML=c,document.getElementById("wifiStored").innerHTML=d,$.ajax({url:"/command/?cmd=wifiscan"})}function nicsDetails(a){var b="",c=a[0];$.each(c,function(a){a===$("#nic-details").data("name")&&(b+="Name:"+a+"",b+="Type:wireless","off/any"===c[a].currentssid?b+='Status:no network connected':(b+='Status:connected',b+="Associated SSID:"+c[a].currentssid+""),b+="Assigned IP:"+(null!==c[a].ip?""+c[a].ip+"":"none")+"",b+="Speed:"+(null!==c[a].speed?c[a].speed:"unknown")+"")}),$("#nic-details tbody").html(b)}function playbackChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode,reconnectOnChannelUnavailableInterval:5e3});a.onmessage=renderUI,a.onstatuschange=function(a){2===a?($("#loader").addClass("hide"),sendCmd("renderui")):0===a&&toggleLoader()},a.addChannel("playback"),a.connect()}function queueChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderQueue,a.addChannel("queue"),a.connect()}function libraryChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=libraryHome,a.addChannel("library"),a.connect()}function notifyChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=renderMSG,a.addChannel("notify"),a.connect()}function wlansChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=listWLANs,a.addChannel("wlans"),a.connect(),$.ajax({url:"/command/?cmd=wifiscan"})}function nicsChannel(){var a=new PushStream({host:window.location.hostname,port:window.location.port,modes:GUI.mode});a.onmessage=nicsDetails,a.addChannel("nics"),a.connect()}function overlayTrigger(a){function b(){if(c.hasClass("open")){c.removeClass("open"),c.addClass("closed")}else if(c.hasClass("closed")&&(c.addClass("open"),"#overlay-social"===a)){var b="https://twitter.com/home?status=Listening+to+"+GUI.json.currentsong.replace(/\s+/g,"+")+"+by+"+GUI.json.currentartist.replace(/\s+/g,"+")+"+on+%40RuneAudio+http%3A%2F%2Fwww.runeaudio.com%2F+%23nowplaying",d="https://www.facebook.com/sharer.php?u=http%3A%2F%2Fwww.runeaudio.com%2F&display=popup",e="https://plus.google.com/share?url=http%3A%2F%2Fwww.runeaudio.com%2F";$("#urlTwitter").attr("href",b),$("#urlFacebook").attr("href",d),$("#urlGooglePlus").attr("href",e) }}var c=$(a),d=$(a+"-open"),e=$(a+"-close");transEndEventNames={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd",msTransition:"MSTransitionEnd",transition:"transitionend"},d.click(function(){b()}),e.click(function(){b()})}function getHiddenProp(){var a=["webkit","moz","ms","o"];if("hidden"in document)return"hidden";for(var b=0;b
    back')):(a("#pl-count").removeClass("hide"),a("#pl-filter-results").addClass("hide").html(""))}),a("#pl-filter-results").click(function(){a(this).addClass("hide"),a("#pl-count").removeClass("hide"),a(this).hasClass("back-to-queue")?(a(".playlist").addClass("hide"),getPlaylistCmd(),a("#pl-currentpath").addClass("hide"),a("#pl-manage").removeClass("hide")):(a("li","#playlist-entries").each(function(){var b=a(this);b.show()}),a("#pl-currentpath").removeClass("hide"),a("#pl-filter").val("")),customScroll("pl",parseInt(GUI.json.song),500)}),a("#pl-manage-list").click(function(){getPlaylists()}),a("#modal-pl-save-btn").click(function(){var b=a("#pl-save-name").val();sendCmd('save "'+b+'"')}),a("#pl-editor").on("click",".pl-action",function(b){b.preventDefault();var c=a(this).parent().attr("data-path");GUI.DBentry[0]=c}),a("#pl-rename-button").click(function(){var b=a("#pl-rename-oldname").text(),c=a("#pl-rename-name").val();sendCmd('rename "'+b+'" "'+c+'"'),getPlaylists()});var e=document.getElementById("playlist-entries");new Sortable(e,{ghostClass:"sortable-ghost",onUpdate:function(a){sortOrder(a.item.getAttribute("id"))}}),a("a","#open-panel-sx").click(function(){a("#open-panel-sx").hasClass("active")&&customScroll("pl",parseInt(GUI.json.song),500)}).on("shown.bs.tab",function(){customScroll("db",GUI.currentDBpos[GUI.currentDBpos[10]],0)}),a("#home-blocks").on("click",".home-block",function(b){if(a(this).hasClass("inactive"))a("#overlay-playsource-open").trigger("click");else if(a(this).is("#home-spotify-switch"))a("#overlay-playsource-open").trigger("click");else if(a(b.target).is("span.block-remove")){var c=a(this).attr("id");c=c.replace("home-bookmark-","");var d=a(this).find("h3").text();a.post("/db/?cmd=bookmark",{id:c,name:d})}else++GUI.currentDBpos[10],getDB({browsemode:a(this).data("browsemode"),path:a(this).data("path"),uplevel:0,plugin:a(this).data("plugin")})}),a("#db-homeSetup").click(function(){var b=a(this);b.hasClass("btn-primary")?(b.removeClass("btn-primary").addClass("btn-default"),a(".home-block-remove").remove()):(b.removeClass("btn-default").addClass("btn-primary"),a(".home-block.home-bookmark").append('
    ×
    '))});var f=a("#database-entries");f.on("click","li",function(b){var c="",d="",e=a(this);if(a(b.target).hasClass("db-action"))b.preventDefault(),c="spotify-track"===e.data("type")?e.data("plid")+"-"+e.data("path"):e.data("path"),GUI.DBentry[0]=c;else if(a("li.active","#database-entries").removeClass("active"),e.addClass("active"),e.hasClass("db-folder")){c=e.data("path"),e.hasClass("db-album")?""!==c?getDB({path:c,uplevel:0,browsemode:"album"}):(c=GUI.currentDBpath[GUI.currentDBpos[10]-1],getDB({path:c,uplevel:0,browsemode:"albumfilter"})):e.hasClass("db-artist")?getDB({path:c,uplevel:0,browsemode:"artist"}):e.hasClass("db-genre")?getDB({path:c,uplevel:0,browsemode:"genre"}):e.hasClass("db-spotify")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Spotify",args:e.data("path").toString(),querytype:"tracks"}),GUI.plugin="Spotify"):e.hasClass("db-dirble")?(c=GUI.currentpath+"/"+e.find("span").text(),getDB({path:c,plugin:"Dirble",querytype:"stations",args:e.data("path")}),GUI.plugin="Dirble"):e.hasClass("db-jamendo")||(d=e.data("browsemode"),getDB({path:c,uplevel:0,browsemode:d}));var f=e.attr("id");f=f.replace("db-",""),GUI.currentDBpos[GUI.currentDBpos[10]]=f,GUI.currentDBpath[GUI.currentDBpos[10]]=c,++GUI.currentDBpos[10]}else e.hasClass("db-webradio-add")&&a("#modal-webradio-add").modal()}),f.on("dblclick","li",function(b){var c=a(this);if(!a(b.target).hasClass("db-action")){a("li.active","#database-entries").removeClass("active"),c.addClass("active");var d=c.data("path");c.hasClass("db-spotify")?(d=c.attr("data-plid")+"-"+c.attr("data-path"),getDB({cmd:"spaddplay",path:d,querytype:"spotify-track"})):(d=c.hasClass("db-dirble")?d.split(" | ")[1]:d,getDB({cmd:"addplay",path:d}))}}),a("#db-level-up").click(function(){--GUI.currentDBpos[10];var a=GUI.currentpath;if(0===GUI.currentDBpos[10])a="";else if("file"===GUI.browsemode){var b=a.lastIndexOf("/");a=-1!==b?a.slice(0,b):""}else"album"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Albums":GUI.browsemode="artist"):"artist"===GUI.browsemode?(a=GUI.currentDBpath[GUI.currentDBpos[10]-1],""===a?a="Artists":GUI.browsemode="genre"):"genre"===GUI.browsemode?a="Genres":"albumfilter"===GUI.browsemode&&(GUI.browsemode="artist",a=GUI.currentDBpath[GUI.currentDBpos[10]-1]);getDB({browsemode:GUI.browsemode,path:a,plugin:GUI.plugin,uplevel:1}),GUI.plugin=""}),a("#db-search-results").click(function(){a(this).addClass("hide"),a("#db-level-up").removeClass("hide"),getDB({path:GUI.currentpath})}),a("a",".context-menu").click(function(){var b=a(this).data("cmd"),c=a(this).data("type"),d=GUI.DBentry[0];switch(GUI.DBentry[0]="",b){case"pl-add":sendCmd('load "'+d+'"');break;case"pl-replace":sendCmd("clear"),sendCmd('load "'+d+'"');break;case"pl-rename":a("#modal-pl-rename").modal(),a("#pl-rename-oldname").text(d);break;case"pl-rm":a.ajax({url:"/command/?cmd=rm%20%22"+d+"%22",success:function(a){getPlaylists(a)}});break;case"wradd":d=d.split(" | ")[1],getDB({cmd:"add",path:d});break;case"wraddplay":d=d.split(" | ")[1],getDB({cmd:"addplay",path:d});break;case"wraddreplaceplay":d=d.split(" | ")[1],getDB({cmd:"addreplaceplay",path:d});break;case"wredit":a("#modal-webradio-edit").modal(),a.post("/db/?cmd=readradio",{filename:d},function(b){var c=a("#webradio-edit-name");c.val(b.name),c.data("file-name",b.name),a("#webradio-edit-url").val(b.url)},"json");break;case"wrdelete":a("#modal-webradio-delete").modal(),a("#webradio-delete-name").text(d.replace("Webradio/",""));break;case"wrsave":var e=d.split(" | ");a.post("/db/?cmd=addradio",{"radio[label]":e[0],"radio[url]":e[1]});break;default:getDB({cmd:b,path:d,browsemode:GUI.browsemode,querytype:c})}}),a("#webradio-add-button").click(function(){var b=a("#webradio-add-name").val(),c=a("#webradio-add-url").val();""===b||""===c?renderMSG([{title:"Missing fields",text:"Please fill both fields to continue",icon:"fa fa-warning"}]):(a.post("/db/?cmd=addradio",{"radio[label]":b,"radio[url]":c},function(){},"json"),a("#modal-webradio-add").modal("hide"),a("#webradio-add-name").val(""),a("#webradio-add-url").val(""))}),a("#webradio-edit-button").click(function(){var b=a("#webradio-edit-name");a.post("/db/?cmd=editradio",{"radio[newlabel]":b.val(),"radio[label]":b.data("file-name"),"radio[url]":a("#webradio-edit-url").val()},function(){},"json")}),a("#webradio-delete-button").click(function(){var b=a("#webradio-delete-name").text();a.post("/db/?cmd=deleteradio",{"radio[label]":b},function(){},"json")}),a("#db-firstPage").click(function(){a.scrollTo(0,500)}),a("#db-prevPage").click(function(){var b="-="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-nextPage").click(function(){var b="+="+a(window).height()+"px";a.scrollTo(b,500)}),a("#db-lastPage").click(function(){a.scrollTo("100%",500)}),a("#pl-firstPage").click(function(){isCustomScroll=!0,a.scrollTo(0,500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})}),a("#pl-prevPage").click(function(){var b=a(window).scrollTop(),c=b-a(window).height()+160;a.scrollTo(c,500)}),a("#pl-nextPage").click(function(){var b=a(window).scrollTop(),c=b+a(window).height()-160;a.scrollTo(c,500)}),a("#pl-lastPage").click(function(){isCustomScroll=!0,a.scrollTo("100%",500,{onAfter:function(){m.redraw(),isCustomScroll=!1}})});var g=document.location.toString();g.match("#")&&a('#menu-bottom a[href="/#'+g.split("#")[1]+'"]').tab("show"),a("#menu-bottom a").on("shown",function(a){history.pushState?history.pushState(null,null,a.target.hash):window.location.hash=a.target.hash}).on("click",function(){a("#overlay-social").hasClass("open")&&a(".overlay-close").trigger("click")}),a(".ttip").length&&a(".ttip").tooltip(),FastClick.attach(document.body),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),overlayTrigger("#overlay-social"),overlayTrigger("#overlay-playsource"),a("#playsource-mpd").click(function(){a(this).hasClass("inactive")&&(a.ajax({url:"/command/?switchplayer=MPD"}),a("#overlay-playsource-close").trigger("click"))}),a("#playsource-spotify").click(function(){a(this).hasClass("inactive")&&("1"===GUI.libraryhome.Spotify?(a.ajax({url:"/command/?switchplayer=Spotify"}),a("#overlay-playsource-close").trigger("click")):new PNotify({title:"Spotify not enabled",text:"Enable and configure it under the Settings screen",icon:"fa fa-exclamation-circle"}))})}:function(a){"use strict";if(GUI.mode=checkWebSocket(),playbackChannel(),PNotify.prototype.options.styling="fontawesome",PNotify.prototype.options.stack.dir1="up",PNotify.prototype.options.stack.dir2="left",PNotify.prototype.options.stack.firstpos1=90,PNotify.prototype.options.stack.firstpos2=50,PNotify.prototype.options.stack.spacing1=10,PNotify.prototype.options.stack.spacing2=10,notifyChannel(),a(".btn-cmd").click(function(){var b=a(this);commandButton(b)}),a("#syscmd-poweroff").click(function(){a.post("/settings/",{syscmd:"poweroff"}),toggleLoader()}),a("#syscmd-reboot").click(function(){a.post("/settings/",{syscmd:"reboot"}),toggleLoader()}),a(".selectpicker").selectpicker(),a("#section-sources").length&&("nfs"===a("#mount-type").val()&&a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide"),a("#mount-type").change(function(){"cifs"===a(this).val()||"osx"===a(this).val()?a("#mount-cifs").removeClass("disabled").children(".disabler").addClass("hide"):a("#mount-cifs").addClass("disabled").children(".disabler").removeClass("hide")}),a("#nas-guest").change(function(){a(this).prop("checked")?a("#mount-auth").addClass("disabled").children(".disabler").removeClass("hide"):a("#mount-auth").removeClass("disabled").children(".disabler").addClass("hide")}),a("#nas-advanced").change(function(){a(this).prop("checked")?a("#mount-advanced-config").removeClass("hide"):a("#mount-advanced-config").addClass("hide")}),a("#show-mount-advanced-config").click(function(b){b.preventDefault(),a(this).hasClass("active")?(a("#mount-advanced-config").toggleClass("hide"),a(this).removeClass("active"),a(this).find("i").removeClass("fa fa-minus-circle").addClass("fa fa-plus-circle"),a(this).find("span").html("show advanced options")):(a("#mount-advanced-config").toggleClass("hide"),a(this).addClass("active"),a(this).find("i").removeClass("fa fa-plus-circle").addClass("fa fa-minus-circle"),a(this).find("span").html("hide advanced options"))}),a("#usb-mount-list a").click(function(){var b=a(this).data("mount");a("#usb-umount-name").html(b),a("#usb-umount").val(b)})),a("#section-settings").length&&(a("#airplay").change(function(){a(this).prop("checked")?(a("#airplayName").removeClass("hide"),a("#airplayBox").addClass("boxed-group")):(a("#airplayName").addClass("hide"),a("#airplayBox").removeClass("boxed-group"))}),a("#scrobbling-lastfm").change(function(){a(this).prop("checked")?(a("#lastfmAuth").removeClass("hide"),a("#lastfmBox").addClass("boxed-group")):(a("#lastfmAuth").addClass("hide"),a("#lastfmBox").removeClass("boxed-group"))}),a("#proxy").change(function(){a(this).prop("checked")?(a("#proxyAuth").removeClass("hide"),a("#proxyBox").addClass("boxed-group")):(a("#proxyAuth").addClass("hide"),a("#proxyBox").removeClass("boxed-group"))}),a("#dlna").change(function(){a(this).prop("checked")?(a("#dlnaName").removeClass("hide"),a("#dlnaBox").addClass("boxed-group")):(a("#dlnaName").addClass("hide"),a("#dlnaBox").removeClass("boxed-group"))}),a("#spotify").change(function(){a(this).prop("checked")?(a("#spotifyAuth").removeClass("hide"),a("#spotifyBox").addClass("boxed-group")):(a("#spotifyAuth").addClass("hide"),a("#spotifyBox").removeClass("boxed-group"))})),a("#section-network").length){var b=a("#network-manual-config");"0"===a("#dhcp").val()&&b.removeClass("hide"),a("#dhcp").change(function(){"0"===a(this).val()?b.removeClass("hide"):b.addClass("hide")});var c=a("#wifi-security-key");"open"!==a("#wifi-security").val()&&c.removeClass("hide"),a("#wifi-security").change(function(){"open"!==a(this).val()?c.removeClass("hide"):c.addClass("hide")}),a("#wifiNetworks").length&&(wlansChannel(),nicsChannel()),a("#wifiProfiles").change(function(){a(this).prop("checked")?a("#wifiProfilesBox").addClass("hide"):a("#wifiProfilesBox").removeClass("hide")})}if(a("#section-mpd").length&&(a("#audio-output-interface").change(function(){renderMSG([{title:"Switching audio output",text:"Please wait for the config update...",icon:"fa fa-cog fa-spin",delay:5e3}]);var b=a(this).val();a.ajax({type:"POST",url:"/mpd/",data:{ao:b}})}),a(".manual-edit-confirm").find(".btn-primary").click(function(){a("#mpdconf_editor").removeClass("hide"),a("#manual-edit-warning").addClass("hide")})),a("#section-debug").length){ZeroClipboard.config({swfPath:"/assets/js/vendor/ZeroClipboard.swf"});var d=new ZeroClipboard(document.getElementById("copy-to-clipboard"));d.on("ready",function(){d.on("aftercopy",function(){new PNotify({title:"Copied to clipboard",text:"The debug output was copied successfully in your clipboard.",icon:"fa fa-check"})})})}});var pageY=0,pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2),pageYold=0,pageYdiff=0;window.resize=function(){pageHeight=window.innerHeight-160,visibleEntries=Math.floor(pageHeight/listEntryHeight||2)},window.onscroll=function(){isCustomScroll||(pageY=window.pageYOffset,pageYdiff=Math.abs(pageYold-pageY),pageYdiff>6*pageHeight&&(pageYold=pageY,console.log("REDRAW ",pageY),m.redraw()))},m.module(document.getElementById("playlist"),{controller:function(){},view:function(){var a=Math.floor(pageY/listEntryHeight)||0,b=a+visibleEntries,c=8,d=Math.max(a-visibleEntries*c,0),e=Math.min(b+visibleEntries*c,Math.max(queueTracks.length-1,0)),f=d*listEntryHeight;return m("#queue-entries-container",[m("ul#playlist-entries",{style:"position:relative;top:"+f+"px"},[queueTracks?queueTracks.slice(d,e).map(function(a,b){var c=null,e=null;return a.webradio?(c=m("i.fa.fa-microphone"),e="URL: "+a.file):a.artist?e=a.artist+" - "+a.album:a.file?e="path: "+a.file.split("/").pop():console.log(a),m("li",{id:"pl-"+a.id,"data-queuepos":d+b,"class":a.current?"active":""},[m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'),m("span.sn",[a.title,m("span",a.timeFormatted)]),m("span.bl",e)])}):null])])}}); \ No newline at end of file diff --git a/assets/js/runeui.mpd.js b/assets/js/runeui.mpd.js index 1cb2580d..79ffe754 100644 --- a/assets/js/runeui.mpd.js +++ b/assets/js/runeui.mpd.js @@ -4,15 +4,19 @@ window.data = window.data || {}; window.mpd = new mithril.RuneModule('/mpd'); -mpd.vm.saveAudioOutput = function () { +mpd.vm.saveAudioOutput = function (e) { data.postData(mpd.vm.url, mpd.vm.ao); }; +mpd.vm.reset = function (e) { + m.module(document.getElementById('dialog'), modal.resetmpd); +}; + // 'MPD' view mpd.view = function (ctrl) { - return [m('h1', 'MPD Configuration'), '\n', m('p', ['\n If you mess up with this configuration you can ', m('a[href="javascript:;"]', { onclick: function (e) { m.module(document.getElementById('dialog'), modal.resetmpd); } }, 'reset to default'), '.\n']), '\n', - m('fieldset.form-horizontal', [ + return [m('h1', 'MPD Configuration'), '\n', m('p', ['\n If you mess up with this configuration you can ', m('a[href="javascript:;"]', { onclick: mpd.vm.reset }, 'reset to default'), '.\n']), '\n', + m('fieldset', [ m('legend', 'Audio Output'), m('.form-group', [ mithril.createLabel('ao', 'Audio output interface'), @@ -25,7 +29,7 @@ mpd.view = function (ctrl) { ]) ]) ]), - m('fieldset.form-horizontal', [ + m('fieldset', [ m('legend', 'Volume control'), m('.form-group', [ mithril.createLabel('mixer-type', 'Volume control'), @@ -36,7 +40,7 @@ mpd.view = function (ctrl) { ]) ]) ]), - m('fieldset.form-horizontal', [ + m('fieldset', [ m('legend', 'General music daemon options'), m('.form-group', [ m('label.col-sm-2.control-label[for="port"]', 'Port'), diff --git a/assets/js/runeui.settings.js b/assets/js/runeui.settings.js index 06d624eb..d3b8e1f6 100644 --- a/assets/js/runeui.settings.js +++ b/assets/js/runeui.settings.js @@ -3,7 +3,7 @@ window.mithril = window.mithril || {}; window.data = window.data || {}; window.settings = new mithril.RuneModule('/settings'); -settings.vm.validate = function(){ +settings.vm.validate = function () { console.log('Settings view'); return true; }; @@ -11,273 +11,325 @@ settings.vm.validate = function(){ // 'Settings' view settings.view = function (ctrl) { return [ - m('h1', 'Settings'), - m('fieldset.form-horizontal', [ - m('legend', 'Environment'), - m('.form-group[id="systemstatus"]', [ - m('label.control-label.col-sm-2', 'Check system status'), - m('.col-sm-10', [ - m('a.btn.btn-default.btn-lg[data-toggle="modal"][href="#modal-sysinfo"]', [m('i.fa.fa-info-circle.sx'), 'show status']), - m('span.help-block', 'See information regarding the system and its status.') - ]) - ]), - m('.form-group[id="environment"]', [ - m('label.control-label.col-sm-2[for="hostname"]', 'Player hostname'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][id="hostname"][placeholder="runeaudio"][type="text"]', mithril.createInput(settings.vm.data.environment, 'hostname')), - m('span.help-block', 'Set the player hostname. This will change the address used to reach the RuneUI.') - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="ntpserver"]', 'NTP server'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][id="ntpserver"][placeholder="pool.ntp.org"][type="text"]', mithril.createInput(settings.vm.data.environment, 'ntpserver')), - m('span.help-block', ['Set your reference time sync server ', m('i', '(NTP server)'), '.']) - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="timezone"]', 'Timezone'), - m('.col-sm-10', [ - // [TODO] re-enable this when the rendering performance issue is solved - // m('select[data-style="btn-default btn-lg"][id="timezone"]', { config: helpers.selectpicker }, [m('option[value="Africa/Abidjan"]', 'Africa/Abidjan - GMT +00:00'), m('option[value="Africa/Accra"]', 'Africa/Accra - GMT +00:00'), m('option[value="Africa/Addis_Ababa"]', 'Africa/Addis_Ababa - GMT +03:00'), m('option[value="Africa/Algiers"]', 'Africa/Algiers - GMT +00:00'), m('option[value="Africa/Asmara"]', 'Africa/Asmara - GMT +03:00'), m('option[value="Africa/Bamako"]', 'Africa/Bamako - GMT +00:00'), m('option[value="Africa/Bangui"]', 'Africa/Bangui - GMT +01:00'), m('option[value="Africa/Banjul"]', 'Africa/Banjul - GMT +00:00'), m('option[value="Africa/Bissau"]', 'Africa/Bissau - GMT -01:00'), m('option[value="Africa/Blantyre"]', 'Africa/Blantyre - GMT +02:00'), m('option[value="Africa/Brazzaville"]', 'Africa/Brazzaville - GMT +01:00'), m('option[value="Africa/Bujumbura"]', 'Africa/Bujumbura - GMT +02:00'), m('option[value="Africa/Cairo"]', 'Africa/Cairo - GMT +02:00'), m('option[value="Africa/Casablanca"]', 'Africa/Casablanca - GMT +00:00'), m('option[value="Africa/Ceuta"]', 'Africa/Ceuta - GMT +00:00'), m('option[value="Africa/Conakry"]', 'Africa/Conakry - GMT +00:00'), m('option[value="Africa/Dakar"]', 'Africa/Dakar - GMT +00:00'), m('option[value="Africa/Dar_es_Salaam"]', 'Africa/Dar_es_Salaam - GMT +03:00'), m('option[value="Africa/Djibouti"]', 'Africa/Djibouti - GMT +03:00'), m('option[value="Africa/Douala"]', 'Africa/Douala - GMT +01:00'), m('option[value="Africa/El_Aaiun"]', 'Africa/El_Aaiun - GMT -01:00'), m('option[value="Africa/Freetown"]', 'Africa/Freetown - GMT +00:00'), m('option[value="Africa/Gaborone"]', 'Africa/Gaborone - GMT +02:00'), m('option[value="Africa/Harare"]', 'Africa/Harare - GMT +02:00'), m('option[value="Africa/Johannesburg"]', 'Africa/Johannesburg - GMT +02:00'), m('option[value="Africa/Juba"]', 'Africa/Juba - GMT +02:00'), m('option[value="Africa/Kampala"]', 'Africa/Kampala - GMT +03:00'), m('option[value="Africa/Khartoum"]', 'Africa/Khartoum - GMT +02:00'), m('option[value="Africa/Kigali"]', 'Africa/Kigali - GMT +02:00'), m('option[value="Africa/Kinshasa"]', 'Africa/Kinshasa - GMT +01:00'), m('option[value="Africa/Lagos"]', 'Africa/Lagos - GMT +01:00'), m('option[value="Africa/Libreville"]', 'Africa/Libreville - GMT +01:00'), m('option[value="Africa/Lome"]', 'Africa/Lome - GMT +00:00'), m('option[value="Africa/Luanda"]', 'Africa/Luanda - GMT +01:00'), m('option[value="Africa/Lubumbashi"]', 'Africa/Lubumbashi - GMT +02:00'), m('option[value="Africa/Lusaka"]', 'Africa/Lusaka - GMT +02:00'), m('option[value="Africa/Malabo"]', 'Africa/Malabo - GMT +01:00'), m('option[value="Africa/Maputo"]', 'Africa/Maputo - GMT +02:00'), m('option[value="Africa/Maseru"]', 'Africa/Maseru - GMT +02:00'), m('option[value="Africa/Mbabane"]', 'Africa/Mbabane - GMT +02:00'), m('option[value="Africa/Mogadishu"]', 'Africa/Mogadishu - GMT +03:00'), m('option[value="Africa/Monrovia"]', 'Africa/Monrovia - GMT -00:44'), m('option[value="Africa/Nairobi"]', 'Africa/Nairobi - GMT +03:00'), m('option[value="Africa/Ndjamena"]', 'Africa/Ndjamena - GMT +01:00'), m('option[value="Africa/Niamey"]', 'Africa/Niamey - GMT +01:00'), m('option[value="Africa/Nouakchott"]', 'Africa/Nouakchott - GMT +00:00'), m('option[value="Africa/Ouagadougou"]', 'Africa/Ouagadougou - GMT +00:00'), m('option[value="Africa/Porto-Novo"]', 'Africa/Porto-Novo - GMT +01:00'), m('option[value="Africa/Sao_Tome"]', 'Africa/Sao_Tome - GMT +00:00'), m('option[value="Africa/Tripoli"]', 'Africa/Tripoli - GMT +02:00'), m('option[value="Africa/Tunis"]', 'Africa/Tunis - GMT +01:00'), m('option[value="Africa/Windhoek"]', 'Africa/Windhoek - GMT +02:00'), m('option[value="America/Adak"]', 'America/Adak - GMT -11:00'), m('option[value="America/Anchorage"]', 'America/Anchorage - GMT -10:00'), m('option[value="America/Anguilla"]', 'America/Anguilla - GMT -04:00'), m('option[value="America/Antigua"]', 'America/Antigua - GMT -04:00'), m('option[value="America/Araguaina"]', 'America/Araguaina - GMT -03:00'), m('option[value="America/Argentina/Buenos_Aires"]', 'America/Argentina/Buenos_Aires - GMT -03:00'), m('option[value="America/Argentina/Catamarca"]', 'America/Argentina/Catamarca - GMT -03:00'), m('option[value="America/Argentina/Cordoba"]', 'America/Argentina/Cordoba - GMT -03:00'), m('option[value="America/Argentina/Jujuy"]', 'America/Argentina/Jujuy - GMT -03:00'), m('option[value="America/Argentina/La_Rioja"]', 'America/Argentina/La_Rioja - GMT -03:00'), m('option[value="America/Argentina/Mendoza"]', 'America/Argentina/Mendoza - GMT -03:00'), m('option[value="America/Argentina/Rio_Gallegos"]', 'America/Argentina/Rio_Gallegos - GMT -03:00'), m('option[value="America/Argentina/Salta"]', 'America/Argentina/Salta - GMT -03:00'), m('option[value="America/Argentina/San_Juan"]', 'America/Argentina/San_Juan - GMT -03:00'), m('option[value="America/Argentina/San_Luis"]', 'America/Argentina/San_Luis - GMT -03:00'), m('option[value="America/Argentina/Tucuman"]', 'America/Argentina/Tucuman - GMT -03:00'), m('option[value="America/Argentina/Ushuaia"]', 'America/Argentina/Ushuaia - GMT -03:00'), m('option[value="America/Aruba"]', 'America/Aruba - GMT -04:00'), m('option[value="America/Asuncion"]', 'America/Asuncion - GMT -04:00'), m('option[value="America/Atikokan"]', 'America/Atikokan - GMT -05:00'), m('option[value="America/Bahia"]', 'America/Bahia - GMT -03:00'), m('option[value="America/Bahia_Banderas"]', 'America/Bahia_Banderas - GMT -07:00'), m('option[value="America/Barbados"]', 'America/Barbados - GMT -04:00'), m('option[value="America/Belem"]', 'America/Belem - GMT -03:00'), m('option[value="America/Belize"]', 'America/Belize - GMT -06:00'), m('option[value="America/Blanc-Sablon"]', 'America/Blanc-Sablon - GMT -04:00'), m('option[value="America/Boa_Vista"]', 'America/Boa_Vista - GMT -04:00'), m('option[value="America/Bogota"]', 'America/Bogota - GMT -05:00'), m('option[value="America/Boise"]', 'America/Boise - GMT -07:00'), m('option[value="America/Cambridge_Bay"]', 'America/Cambridge_Bay - GMT -07:00'), m('option[value="America/Campo_Grande"]', 'America/Campo_Grande - GMT -04:00'), m('option[value="America/Cancun"]', 'America/Cancun - GMT -06:00'), m('option[value="America/Caracas"]', 'America/Caracas - GMT -04:00'), m('option[value="America/Cayenne"]', 'America/Cayenne - GMT -03:00'), m('option[value="America/Cayman"]', 'America/Cayman - GMT -05:00'), m('option[value="America/Chicago"]', 'America/Chicago - GMT -06:00'), m('option[value="America/Chihuahua"]', 'America/Chihuahua - GMT -06:00'), m('option[value="America/Costa_Rica"]', 'America/Costa_Rica - GMT -06:00'), m('option[value="America/Creston"]', 'America/Creston - GMT -07:00'), m('option[value="America/Cuiaba"]', 'America/Cuiaba - GMT -04:00'), m('option[value="America/Curacao"]', 'America/Curacao - GMT -04:00'), m('option[value="America/Danmarkshavn"]', 'America/Danmarkshavn - GMT -03:00'), m('option[value="America/Dawson"]', 'America/Dawson - GMT -09:00'), m('option[value="America/Dawson_Creek"]', 'America/Dawson_Creek - GMT -08:00'), m('option[value="America/Denver"]', 'America/Denver - GMT -07:00'), m('option[value="America/Detroit"]', 'America/Detroit - GMT -05:00'), m('option[value="America/Dominica"]', 'America/Dominica - GMT -04:00'), m('option[value="America/Edmonton"]', 'America/Edmonton - GMT -07:00'), m('option[value="America/Eirunepe"]', 'America/Eirunepe - GMT -05:00'), m('option[value="America/El_Salvador"]', 'America/El_Salvador - GMT -06:00'), m('option[value="America/Fortaleza"]', 'America/Fortaleza - GMT -03:00'), m('option[value="America/Glace_Bay"]', 'America/Glace_Bay - GMT -04:00'), m('option[value="America/Godthab"]', 'America/Godthab - GMT -03:00'), m('option[value="America/Goose_Bay"]', 'America/Goose_Bay - GMT -04:00'), m('option[value="America/Grand_Turk"]', 'America/Grand_Turk - GMT -05:00'), m('option[value="America/Grenada"]', 'America/Grenada - GMT -04:00'), m('option[value="America/Guadeloupe"]', 'America/Guadeloupe - GMT -04:00'), m('option[value="America/Guatemala"]', 'America/Guatemala - GMT -06:00'), m('option[value="America/Guayaquil"]', 'America/Guayaquil - GMT -05:00'), m('option[value="America/Guyana"]', 'America/Guyana - GMT -03:45'), m('option[value="America/Halifax"]', 'America/Halifax - GMT -04:00'), m('option[value="America/Havana"]', 'America/Havana - GMT -05:00'), m('option[value="America/Hermosillo"]', 'America/Hermosillo - GMT -07:00'), m('option[value="America/Indiana/Indianapolis"]', 'America/Indiana/Indianapolis - GMT -05:00'), m('option[value="America/Indiana/Knox"]', 'America/Indiana/Knox - GMT -06:00'), m('option[value="America/Indiana/Marengo"]', 'America/Indiana/Marengo - GMT -05:00'), m('option[value="America/Indiana/Petersburg"]', 'America/Indiana/Petersburg - GMT -06:00'), m('option[value="America/Indiana/Tell_City"]', 'America/Indiana/Tell_City - GMT -05:00'), m('option[value="America/Indiana/Vevay"]', 'America/Indiana/Vevay - GMT -05:00'), m('option[value="America/Indiana/Vincennes"]', 'America/Indiana/Vincennes - GMT -05:00'), m('option[value="America/Indiana/Winamac"]', 'America/Indiana/Winamac - GMT -05:00'), m('option[value="America/Inuvik"]', 'America/Inuvik - GMT -08:00'), m('option[value="America/Iqaluit"]', 'America/Iqaluit - GMT -05:00'), m('option[value="America/Jamaica"]', 'America/Jamaica - GMT -05:00'), m('option[value="America/Juneau"]', 'America/Juneau - GMT -08:00'), m('option[value="America/Kentucky/Louisville"]', 'America/Kentucky/Louisville - GMT -05:00'), m('option[value="America/Kentucky/Monticello"]', 'America/Kentucky/Monticello - GMT -06:00'), m('option[value="America/Kralendijk"]', 'America/Kralendijk - GMT -04:00'), m('option[value="America/La_Paz"]', 'America/La_Paz - GMT -04:00'), m('option[value="America/Lima"]', 'America/Lima - GMT -05:00'), m('option[value="America/Los_Angeles"]', 'America/Los_Angeles - GMT -08:00'), m('option[value="America/Lower_Princes"]', 'America/Lower_Princes - GMT -04:00'), m('option[value="America/Maceio"]', 'America/Maceio - GMT -03:00'), m('option[value="America/Managua"]', 'America/Managua - GMT -06:00'), m('option[value="America/Manaus"]', 'America/Manaus - GMT -04:00'), m('option[value="America/Marigot"]', 'America/Marigot - GMT -04:00'), m('option[value="America/Martinique"]', 'America/Martinique - GMT -04:00'), m('option[value="America/Matamoros"]', 'America/Matamoros - GMT -06:00'), m('option[value="America/Mazatlan"]', 'America/Mazatlan - GMT -07:00'), m('option[value="America/Menominee"]', 'America/Menominee - GMT -05:00'), m('option[value="America/Merida"]', 'America/Merida - GMT -06:00'), m('option[value="America/Metlakatla"]', 'America/Metlakatla - GMT -08:00'), m('option[value="America/Mexico_City"]', 'America/Mexico_City - GMT -06:00'), m('option[value="America/Miquelon"]', 'America/Miquelon - GMT -04:00'), m('option[value="America/Moncton"]', 'America/Moncton - GMT -04:00'), m('option[value="America/Monterrey"]', 'America/Monterrey - GMT -06:00'), m('option[value="America/Montevideo"]', 'America/Montevideo - GMT -03:00'), m('option[value="America/Montserrat"]', 'America/Montserrat - GMT -04:00'), m('option[value="America/Nassau"]', 'America/Nassau - GMT -05:00'), m('option[value="America/New_York"]', 'America/New_York - GMT -05:00'), m('option[value="America/Nipigon"]', 'America/Nipigon - GMT -05:00'), m('option[value="America/Nome"]', 'America/Nome - GMT -11:00'), m('option[value="America/Noronha"]', 'America/Noronha - GMT -02:00'), m('option[value="America/North_Dakota/Beulah"]', 'America/North_Dakota/Beulah - GMT -07:00'), m('option[value="America/North_Dakota/Center"]', 'America/North_Dakota/Center - GMT -07:00'), m('option[value="America/North_Dakota/New_Salem"]', 'America/North_Dakota/New_Salem - GMT -07:00'), m('option[value="America/Ojinaga"]', 'America/Ojinaga - GMT -06:00'), m('option[value="America/Panama"]', 'America/Panama - GMT -05:00'), m('option[value="America/Pangnirtung"]', 'America/Pangnirtung - GMT -04:00'), m('option[value="America/Paramaribo"]', 'America/Paramaribo - GMT -03:30'), m('option[value="America/Phoenix"]', 'America/Phoenix - GMT -07:00'), m('option[value="America/Port-au-Prince"]', 'America/Port-au-Prince - GMT -05:00'), m('option[value="America/Port_of_Spain"]', 'America/Port_of_Spain - GMT -04:00'), m('option[value="America/Porto_Velho"]', 'America/Porto_Velho - GMT -04:00'), m('option[value="America/Puerto_Rico"]', 'America/Puerto_Rico - GMT -04:00'), m('option[value="America/Rainy_River"]', 'America/Rainy_River - GMT -06:00'), m('option[value="America/Rankin_Inlet"]', 'America/Rankin_Inlet - GMT -06:00'), m('option[value="America/Recife"]', 'America/Recife - GMT -03:00'), m('option[value="America/Regina"]', 'America/Regina - GMT -06:00'), m('option[value="America/Resolute"]', 'America/Resolute - GMT -06:00'), m('option[value="America/Rio_Branco"]', 'America/Rio_Branco - GMT -05:00'), m('option[value="America/Santa_Isabel"]', 'America/Santa_Isabel - GMT -08:00'), m('option[value="America/Santarem"]', 'America/Santarem - GMT -04:00'), m('option[value="America/Santiago"]', 'America/Santiago - GMT -03:00'), m('option[value="America/Santo_Domingo"]', 'America/Santo_Domingo - GMT -04:30'), m('option[value="America/Sao_Paulo"]', 'America/Sao_Paulo - GMT -03:00'), m('option[value="America/Scoresbysund"]', 'America/Scoresbysund - GMT -02:00'), m('option[value="America/Sitka"]', 'America/Sitka - GMT -08:00'), m('option[value="America/St_Barthelemy"]', 'America/St_Barthelemy - GMT -04:00'), m('option[value="America/St_Johns"]', 'America/St_Johns - GMT -03:30'), m('option[value="America/St_Kitts"]', 'America/St_Kitts - GMT -04:00'), m('option[value="America/St_Lucia"]', 'America/St_Lucia - GMT -04:00'), m('option[value="America/St_Thomas"]', 'America/St_Thomas - GMT -04:00'), m('option[value="America/St_Vincent"]', 'America/St_Vincent - GMT -04:00'), m('option[value="America/Swift_Current"]', 'America/Swift_Current - GMT -07:00'), m('option[value="America/Tegucigalpa"]', 'America/Tegucigalpa - GMT -06:00'), m('option[value="America/Thule"]', 'America/Thule - GMT -04:00'), m('option[value="America/Thunder_Bay"]', 'America/Thunder_Bay - GMT -05:00'), m('option[value="America/Tijuana"]', 'America/Tijuana - GMT -08:00'), m('option[value="America/Toronto"]', 'America/Toronto - GMT -05:00'), m('option[value="America/Tortola"]', 'America/Tortola - GMT -04:00'), m('option[value="America/Vancouver"]', 'America/Vancouver - GMT -08:00'), m('option[value="America/Whitehorse"]', 'America/Whitehorse - GMT -08:00'), m('option[value="America/Winnipeg"]', 'America/Winnipeg - GMT -06:00'), m('option[value="America/Yakutat"]', 'America/Yakutat - GMT -09:00'), m('option[value="America/Yellowknife"]', 'America/Yellowknife - GMT -07:00'), m('option[value="Antarctica/Casey"]', 'Antarctica/Casey - GMT +08:00'), m('option[value="Antarctica/Davis"]', 'Antarctica/Davis - GMT +07:00'), m('option[value="Antarctica/DumontDUrville"]', 'Antarctica/DumontDUrville - GMT +10:00'), m('option[value="Antarctica/Macquarie"]', 'Antarctica/Macquarie - GMT +11:00'), m('option[value="Antarctica/Mawson"]', 'Antarctica/Mawson - GMT +06:00'), m('option[value="Antarctica/McMurdo"]', 'Antarctica/McMurdo - GMT +12:00'), m('option[value="Antarctica/Palmer"]', 'Antarctica/Palmer - GMT -03:00'), m('option[value="Antarctica/Rothera"]', 'Antarctica/Rothera - GMT +00:00'), m('option[value="Antarctica/Syowa"]', 'Antarctica/Syowa - GMT +03:00'), m('option[value="Antarctica/Troll"]', 'Antarctica/Troll - GMT +00:00'), m('option[value="Antarctica/Vostok"]', 'Antarctica/Vostok - GMT +06:00'), m('option[value="Arctic/Longyearbyen"]', 'Arctic/Longyearbyen - GMT +01:00'), m('option[value="Asia/Aden"]', 'Asia/Aden - GMT +03:00'), m('option[value="Asia/Almaty"]', 'Asia/Almaty - GMT +06:00'), m('option[value="Asia/Amman"]', 'Asia/Amman - GMT +02:00'), m('option[value="Asia/Anadyr"]', 'Asia/Anadyr - GMT +13:00'), m('option[value="Asia/Aqtau"]', 'Asia/Aqtau - GMT +05:00'), m('option[value="Asia/Aqtobe"]', 'Asia/Aqtobe - GMT +05:00'), m('option[value="Asia/Ashgabat"]', 'Asia/Ashgabat - GMT +05:00'), m('option[value="Asia/Baghdad"]', 'Asia/Baghdad - GMT +03:00'), m('option[value="Asia/Bahrain"]', 'Asia/Bahrain - GMT +04:00'), m('option[value="Asia/Baku"]', 'Asia/Baku - GMT +04:00'), m('option[value="Asia/Bangkok"]', 'Asia/Bangkok - GMT +07:00'), m('option[value="Asia/Beirut"]', 'Asia/Beirut - GMT +02:00'), m('option[value="Asia/Bishkek"]', 'Asia/Bishkek - GMT +06:00'), m('option[value="Asia/Brunei"]', 'Asia/Brunei - GMT +08:00'), m('option[value="Asia/Chita"]', 'Asia/Chita - GMT +09:00'), m('option[value="Asia/Choibalsan"]', 'Asia/Choibalsan - GMT +07:00'), m('option[value="Asia/Colombo"]', 'Asia/Colombo - GMT +05:30'), m('option[value="Asia/Damascus"]', 'Asia/Damascus - GMT +02:00'), m('option[value="Asia/Dhaka"]', 'Asia/Dhaka - GMT +06:00'), m('option[value="Asia/Dili"]', 'Asia/Dili - GMT +09:00'), m('option[value="Asia/Dubai"]', 'Asia/Dubai - GMT +04:00'), m('option[value="Asia/Dushanbe"]', 'Asia/Dushanbe - GMT +06:00'), m('option[value="Asia/Gaza"]', 'Asia/Gaza - GMT +02:00'), m('option[value="Asia/Hebron"]', 'Asia/Hebron - GMT +02:00'), m('option[value="Asia/Ho_Chi_Minh"]', 'Asia/Ho_Chi_Minh - GMT +07:00'), m('option[value="Asia/Hong_Kong"]', 'Asia/Hong_Kong - GMT +08:00'), m('option[value="Asia/Hovd"]', 'Asia/Hovd - GMT +06:00'), m('option[value="Asia/Irkutsk"]', 'Asia/Irkutsk - GMT +08:00'), m('option[value="Asia/Jakarta"]', 'Asia/Jakarta - GMT +07:00'), m('option[value="Asia/Jayapura"]', 'Asia/Jayapura - GMT +09:00'), m('option[value="Asia/Jerusalem"]', 'Asia/Jerusalem - GMT +02:00'), m('option[value="Asia/Kabul"]', 'Asia/Kabul - GMT +04:30'), m('option[value="Asia/Kamchatka"]', 'Asia/Kamchatka - GMT +12:00'), m('option[value="Asia/Karachi"]', 'Asia/Karachi - GMT +05:00'), m('option[value="Asia/Kathmandu"]', 'Asia/Kathmandu - GMT +05:30'), m('option[value="Asia/Khandyga"]', 'Asia/Khandyga - GMT +09:00'), m('option[value="Asia/Kolkata"]', 'Asia/Kolkata - GMT +05:30'), m('option[value="Asia/Krasnoyarsk"]', 'Asia/Krasnoyarsk - GMT +07:00'), m('option[value="Asia/Kuala_Lumpur"]', 'Asia/Kuala_Lumpur - GMT +07:30'), m('option[value="Asia/Kuching"]', 'Asia/Kuching - GMT +08:00'), m('option[value="Asia/Kuwait"]', 'Asia/Kuwait - GMT +03:00'), m('option[value="Asia/Macau"]', 'Asia/Macau - GMT +08:00'), m('option[value="Asia/Magadan"]', 'Asia/Magadan - GMT +11:00'), m('option[value="Asia/Makassar"]', 'Asia/Makassar - GMT +08:00'), m('option[value="Asia/Manila"]', 'Asia/Manila - GMT +08:00'), m('option[value="Asia/Muscat"]', 'Asia/Muscat - GMT +04:00'), m('option[value="Asia/Nicosia"]', 'Asia/Nicosia - GMT +02:00'), m('option[value="Asia/Novokuznetsk"]', 'Asia/Novokuznetsk - GMT +07:00'), m('option[value="Asia/Novosibirsk"]', 'Asia/Novosibirsk - GMT +07:00'), m('option[value="Asia/Omsk"]', 'Asia/Omsk - GMT +06:00'), m('option[value="Asia/Oral"]', 'Asia/Oral - GMT +05:00'), m('option[value="Asia/Phnom_Penh"]', 'Asia/Phnom_Penh - GMT +07:00'), m('option[value="Asia/Pontianak"]', 'Asia/Pontianak - GMT +08:00'), m('option[value="Asia/Pyongyang"]', 'Asia/Pyongyang - GMT +09:00'), m('option[value="Asia/Qatar"]', 'Asia/Qatar - GMT +04:00'), m('option[value="Asia/Qyzylorda"]', 'Asia/Qyzylorda - GMT +05:00'), m('option[value="Asia/Rangoon"]', 'Asia/Rangoon - GMT +06:30'), m('option[value="Asia/Riyadh"]', 'Asia/Riyadh - GMT +03:00'), m('option[value="Asia/Sakhalin"]', 'Asia/Sakhalin - GMT +11:00'), m('option[value="Asia/Samarkand"]', 'Asia/Samarkand - GMT +05:00'), m('option[value="Asia/Seoul"]', 'Asia/Seoul - GMT +09:00'), m('option[value="Asia/Shanghai"]', 'Asia/Shanghai - GMT +08:00'), m('option[value="Asia/Singapore"]', 'Asia/Singapore - GMT +07:30'), m('option[value="Asia/Srednekolymsk"]', 'Asia/Srednekolymsk - GMT +11:00'), m('option[value="Asia/Taipei"]', 'Asia/Taipei - GMT +08:00'), m('option[value="Asia/Tashkent"]', 'Asia/Tashkent - GMT +06:00'), m('option[value="Asia/Tbilisi"]', 'Asia/Tbilisi - GMT +04:00'), m('option[value="Asia/Tehran"]', 'Asia/Tehran - GMT +03:30'), m('option[value="Asia/Thimphu"]', 'Asia/Thimphu - GMT +05:30'), m('option[value="Asia/Tokyo"]', 'Asia/Tokyo - GMT +09:00'), m('option[value="Asia/Ulaanbaatar"]', 'Asia/Ulaanbaatar - GMT +07:00'), m('option[value="Asia/Urumqi"]', 'Asia/Urumqi - GMT +06:00'), m('option[value="Asia/Ust-Nera"]', 'Asia/Ust-Nera - GMT +09:00'), m('option[value="Asia/Vientiane"]', 'Asia/Vientiane - GMT +07:00'), m('option[value="Asia/Vladivostok"]', 'Asia/Vladivostok - GMT +10:00'), m('option[value="Asia/Yakutsk"]', 'Asia/Yakutsk - GMT +09:00'), m('option[value="Asia/Yekaterinburg"]', 'Asia/Yekaterinburg - GMT +05:00'), m('option[value="Asia/Yerevan"]', 'Asia/Yerevan - GMT +04:00'), m('option[value="Atlantic/Azores"]', 'Atlantic/Azores - GMT -01:00'), m('option[value="Atlantic/Bermuda"]', 'Atlantic/Bermuda - GMT -04:00'), m('option[value="Atlantic/Canary"]', 'Atlantic/Canary - GMT +00:00'), m('option[value="Atlantic/Cape_Verde"]', 'Atlantic/Cape_Verde - GMT -02:00'), m('option[value="Atlantic/Faroe"]', 'Atlantic/Faroe - GMT +00:00'), m('option[value="Atlantic/Madeira"]', 'Atlantic/Madeira - GMT +00:00'), m('option[value="Atlantic/Reykjavik"]', 'Atlantic/Reykjavik - GMT +00:00'), m('option[value="Atlantic/South_Georgia"]', 'Atlantic/South_Georgia - GMT -02:00'), m('option[value="Atlantic/St_Helena"]', 'Atlantic/St_Helena - GMT +00:00'), m('option[value="Atlantic/Stanley"]', 'Atlantic/Stanley - GMT -04:00'), m('option[value="Australia/Adelaide"]', 'Australia/Adelaide - GMT +09:30'), m('option[value="Australia/Brisbane"]', 'Australia/Brisbane - GMT +10:00'), m('option[value="Australia/Broken_Hill"]', 'Australia/Broken_Hill - GMT +09:30'), m('option[value="Australia/Currie"]', 'Australia/Currie - GMT +10:00'), m('option[value="Australia/Darwin"]', 'Australia/Darwin - GMT +09:30'), m('option[value="Australia/Eucla"]', 'Australia/Eucla - GMT +08:45'), m('option[value="Australia/Hobart"]', 'Australia/Hobart - GMT +11:00'), m('option[value="Australia/Lindeman"]', 'Australia/Lindeman - GMT +10:00'), m('option[value="Australia/Lord_Howe"]', 'Australia/Lord_Howe - GMT +10:00'), m('option[value="Australia/Melbourne"]', 'Australia/Melbourne - GMT +10:00'), m('option[value="Australia/Perth"]', 'Australia/Perth - GMT +08:00'), m('option[value="Australia/Sydney"]', 'Australia/Sydney - GMT +10:00'), m('option[value="Europe/Amsterdam"]', 'Europe/Amsterdam - GMT +01:00'), m('option[value="Europe/Andorra"]', 'Europe/Andorra - GMT +01:00'), m('option[value="Europe/Athens"]', 'Europe/Athens - GMT +02:00'), m('option[value="Europe/Belgrade"]', 'Europe/Belgrade - GMT +01:00'), m('option[value="Europe/Berlin"]', 'Europe/Berlin - GMT +01:00'), m('option[value="Europe/Bratislava"]', 'Europe/Bratislava - GMT +01:00'), m('option[value="Europe/Brussels"]', 'Europe/Brussels - GMT +01:00'), m('option[value="Europe/Bucharest"]', 'Europe/Bucharest - GMT +02:00'), m('option[value="Europe/Budapest"]', 'Europe/Budapest - GMT +01:00'), m('option[value="Europe/Busingen"]', 'Europe/Busingen - GMT +01:00'), m('option[value="Europe/Chisinau"]', 'Europe/Chisinau - GMT +03:00'), m('option[value="Europe/Copenhagen"]', 'Europe/Copenhagen - GMT +01:00'), m('option[value="Europe/Dublin"]', 'Europe/Dublin - GMT +01:00'), m('option[value="Europe/Gibraltar"]', 'Europe/Gibraltar - GMT +01:00'), m('option[value="Europe/Guernsey"]', 'Europe/Guernsey - GMT +01:00'), m('option[value="Europe/Helsinki"]', 'Europe/Helsinki - GMT +02:00'), m('option[value="Europe/Isle_of_Man"]', 'Europe/Isle_of_Man - GMT +01:00'), m('option[value="Europe/Istanbul"]', 'Europe/Istanbul - GMT +02:00'), m('option[value="Europe/Jersey"]', 'Europe/Jersey - GMT +01:00'), m('option[value="Europe/Kaliningrad"]', 'Europe/Kaliningrad - GMT +03:00'), m('option[value="Europe/Kiev"]', 'Europe/Kiev - GMT +03:00'), m('option[value="Europe/Lisbon"]', 'Europe/Lisbon - GMT +01:00'), m('option[value="Europe/Ljubljana"]', 'Europe/Ljubljana - GMT +01:00'), m('option[value="Europe/London"]', 'Europe/London - GMT +01:00'), m('option[value="Europe/Luxembourg"]', 'Europe/Luxembourg - GMT +01:00'), m('option[value="Europe/Madrid"]', 'Europe/Madrid - GMT +01:00'), m('option[value="Europe/Malta"]', 'Europe/Malta - GMT +01:00'), m('option[value="Europe/Mariehamn"]', 'Europe/Mariehamn - GMT +02:00'), m('option[value="Europe/Minsk"]', 'Europe/Minsk - GMT +03:00'), m('option[value="Europe/Monaco"]', 'Europe/Monaco - GMT +01:00'), m('option[value="Europe/Moscow"]', 'Europe/Moscow - GMT +03:00'), m('option[value="Europe/Oslo"]', 'Europe/Oslo - GMT +01:00'), m('option[value="Europe/Paris"]', 'Europe/Paris - GMT +01:00'), m('option[value="Europe/Podgorica"]', 'Europe/Podgorica - GMT +01:00'), m('option[value="Europe/Prague"]', 'Europe/Prague - GMT +01:00'), m('option[value="Europe/Riga"]', 'Europe/Riga - GMT +03:00'), m('option[value="Europe/Rome"]', 'Europe/Rome - GMT +01:00'), m('option[value="Europe/Samara"]', 'Europe/Samara - GMT +04:00'), m('option[value="Europe/San_Marino"]', 'Europe/San_Marino - GMT +01:00'), m('option[value="Europe/Sarajevo"]', 'Europe/Sarajevo - GMT +01:00'), m('option[value="Europe/Simferopol"]', 'Europe/Simferopol - GMT +03:00'), m('option[value="Europe/Skopje"]', 'Europe/Skopje - GMT +01:00'), m('option[value="Europe/Sofia"]', 'Europe/Sofia - GMT +02:00'), m('option[value="Europe/Stockholm"]', 'Europe/Stockholm - GMT +01:00'), m('option[value="Europe/Tallinn"]', 'Europe/Tallinn - GMT +03:00'), m('option[value="Europe/Tirane"]', 'Europe/Tirane - GMT +01:00'), m('option[value="Europe/Uzhgorod"]', 'Europe/Uzhgorod - GMT +03:00'), m('option[value="Europe/Vaduz"]', 'Europe/Vaduz - GMT +01:00'), m('option[value="Europe/Vatican"]', 'Europe/Vatican - GMT +01:00'), m('option[value="Europe/Vienna"]', 'Europe/Vienna - GMT +01:00'), m('option[value="Europe/Vilnius"]', 'Europe/Vilnius - GMT +03:00'), m('option[value="Europe/Volgograd"]', 'Europe/Volgograd - GMT +04:00'), m('option[value="Europe/Warsaw"]', 'Europe/Warsaw - GMT +01:00'), m('option[value="Europe/Zagreb"]', 'Europe/Zagreb - GMT +01:00'), m('option[value="Europe/Zaporozhye"]', 'Europe/Zaporozhye - GMT +03:00'), m('option[value="Europe/Zurich"]', 'Europe/Zurich - GMT +01:00'), m('option[value="Indian/Antananarivo"]', 'Indian/Antananarivo - GMT +03:00'), m('option[value="Indian/Chagos"]', 'Indian/Chagos - GMT +05:00'), m('option[value="Indian/Christmas"]', 'Indian/Christmas - GMT +07:00'), m('option[value="Indian/Cocos"]', 'Indian/Cocos - GMT +06:30'), m('option[value="Indian/Comoro"]', 'Indian/Comoro - GMT +03:00'), m('option[value="Indian/Kerguelen"]', 'Indian/Kerguelen - GMT +05:00'), m('option[value="Indian/Mahe"]', 'Indian/Mahe - GMT +04:00'), m('option[value="Indian/Maldives"]', 'Indian/Maldives - GMT +05:00'), m('option[value="Indian/Mauritius"]', 'Indian/Mauritius - GMT +04:00'), m('option[value="Indian/Mayotte"]', 'Indian/Mayotte - GMT +03:00'), m('option[value="Indian/Reunion"]', 'Indian/Reunion - GMT +04:00'), m('option[value="Pacific/Apia"]', 'Pacific/Apia - GMT -11:00'), m('option[value="Pacific/Auckland"]', 'Pacific/Auckland - GMT +12:00'), m('option[value="Pacific/Chatham"]', 'Pacific/Chatham - GMT +12:45'), m('option[value="Pacific/Chuuk"]', 'Pacific/Chuuk - GMT +10:00'), m('option[value="Pacific/Easter"]', 'Pacific/Easter - GMT -06:00'), m('option[value="Pacific/Efate"]', 'Pacific/Efate - GMT +11:00'), m('option[value="Pacific/Enderbury"]', 'Pacific/Enderbury - GMT -12:00'), m('option[value="Pacific/Fakaofo"]', 'Pacific/Fakaofo - GMT -11:00'), m('option[value="Pacific/Fiji"]', 'Pacific/Fiji - GMT +12:00'), m('option[value="Pacific/Funafuti"]', 'Pacific/Funafuti - GMT +12:00'), m('option[value="Pacific/Galapagos"]', 'Pacific/Galapagos - GMT -05:00'), m('option[value="Pacific/Gambier"]', 'Pacific/Gambier - GMT -09:00'), m('option[value="Pacific/Guadalcanal"]', 'Pacific/Guadalcanal - GMT +11:00'), m('option[value="Pacific/Guam"]', 'Pacific/Guam - GMT +10:00'), m('option[value="Pacific/Honolulu"]', 'Pacific/Honolulu - GMT -10:00'), m('option[value="Pacific/Johnston"]', 'Pacific/Johnston - GMT -10:00'), m('option[value="Pacific/Kiritimati"]', 'Pacific/Kiritimati - GMT -10:40'), m('option[value="Pacific/Kosrae"]', 'Pacific/Kosrae - GMT +12:00'), m('option[value="Pacific/Kwajalein"]', 'Pacific/Kwajalein - GMT -12:00'), m('option[value="Pacific/Majuro"]', 'Pacific/Majuro - GMT +12:00'), m('option[value="Pacific/Marquesas"]', 'Pacific/Marquesas - GMT -09:30'), m('option[value="Pacific/Midway"]', 'Pacific/Midway - GMT -11:00'), m('option[value="Pacific/Nauru"]', 'Pacific/Nauru - GMT +11:30'), m('option[value="Pacific/Niue"]', 'Pacific/Niue - GMT -11:30'), m('option[value="Pacific/Norfolk"]', 'Pacific/Norfolk - GMT +11:30'), m('option[value="Pacific/Noumea"]', 'Pacific/Noumea - GMT +11:00'), m('option[value="Pacific/Pago_Pago"]', 'Pacific/Pago_Pago - GMT -11:00'), m('option[value="Pacific/Palau"]', 'Pacific/Palau - GMT +09:00'), m('option[value="Pacific/Pitcairn"]', 'Pacific/Pitcairn - GMT -08:30'), m('option[value="Pacific/Pohnpei"]', 'Pacific/Pohnpei - GMT +11:00'), m('option[value="Pacific/Port_Moresby"]', 'Pacific/Port_Moresby - GMT +10:00'), m('option[value="Pacific/Rarotonga"]', 'Pacific/Rarotonga - GMT -10:30'), m('option[value="Pacific/Saipan"]', 'Pacific/Saipan - GMT +10:00'), m('option[value="Pacific/Tahiti"]', 'Pacific/Tahiti - GMT -10:00'), m('option[value="Pacific/Tarawa"]', 'Pacific/Tarawa - GMT +12:00'), m('option[value="Pacific/Tongatapu"]', 'Pacific/Tongatapu - GMT +13:00'), m('option[value="Pacific/Wake"]', 'Pacific/Wake - GMT +12:00'), m('option[value="Pacific/Wallis"]', 'Pacific/Wallis - GMT +12:00'), m('option[value="UTC"]', 'UTC - GMT +00:00')]), - m('span.help-block', 'Set the system timezone.') - ]) - ]), - //m('.form-group.form-actions', [ - // m('.col-sm-offset-2.col-sm-10', [ - // m('button.btn.btn-primary.btn-lg[name="save"][type="submit"][value="save"]', 'Apply settings') - // ]) - //]), - m('.form-group.form-actions', [ - m('.col-sm-offset-2.col-sm-10', [ - m('button.btn.btn-default.btn-lg[type="button"]', { onclick: function (e) { settings.vm.cancel('environment'); } }, 'Cancel'), - m('button.btn.btn-primary.btn-lg[type="button"]', { onclick: function (e) { settings.vm.save('environment'); } }, 'Save and apply') - ]) - ]) - ]), - m('fieldset.form-horizontal', [ - m('legend', 'RuneOS kernel settings'), - m('.form-group', [ - m('label.control-label.col-sm-2[for="i2smodule"]', 'Linux Kernel'), - m('.col-sm-10', [ - m('select.selectpicker[data-style="btn-default btn-lg"][name="kernel"]', { style: { 'display': ' none' } }, [ - m('option[selected=""][value="linux-arch-rpi_3.12.26-1-ARCH"]', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), - m('option[value="linux-rune-rpi_3.12.19-2-ARCH"]', 'Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]'), - m('option[value="linux-rune-rpi_3.6.11-18-ARCH+"]', 'Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]'), - m('option[value="linux-rune-rpi_3.12.13-rt21_wosa"]', 'Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]') - ]), - m('.btn-group.bootstrap-select', [m('button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle="dropdown"][title="Linux kernel 3.12.26-1   ARCH [RuneAudio v0.3-beta]"][type="button"]', [m('span.filter-option.pull-left', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), ' ', m('span.caret')]), m('.dropdown-menu.open', [m('ul.dropdown-menu.inner.selectpicker[role="menu"]', [m('li.selected[rel="0"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="1"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="2"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="3"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])])])])]), - m('span.help-block', ['Switch Linux Kernel version (REBOOT REQUIRED). ', m('strong', 'Linux kernel 3.12.26-1'), ' is the default kernel in the current release, ', m('strong', 'Linux kernel 3.12.19-2'), ' is the kernel used in RuneAudio v0.3-alpha, ', m('strong', 'Linux kernel 3.6.11-18'), ' is the kernel used in RuneAudio v0.1-beta/v0.2-beta (it has no support for I²S), ', m('strong', 'Linux kernel 3.12.13-rt'), ' is an EXPERIMENTAL kernel (not suitable for all configurations), it is optimized for ', m('strong', 'Wolfson Audio Card'), ' support and it is the default option for that type of soundcard.']) - ]), - m('label.control-label.col-sm-2[for="i2smodule"]', 'I²S kernel modules'), - m('.col-sm-10', [ - m('select.selectpicker[data-style="btn-default btn-lg"][name="i2smodule"]', { style: { 'display': ' none' } }, [ - m('option[value="none"]', 'I²S disabled (default)'), - m('option[value="berrynos"]', 'G2Labs BerryNOS'), - m('option[value="berrynosmini"]', 'G2Labs BerryNOS mini'), - m('option[value="hifiberrydac"]', 'HiFiBerry DAC'), - m('option[value="hifiberrydacplus"]', 'HiFiBerry DAC+'), - m('option[value="hifiberrydigi"]', 'HiFiBerry Digi / Digi+'), - m('option[value="iqaudiopidac"]', 'IQaudIO Pi-DAC / Pi-DAC+'), - m('option[value="raspyplay3"]', 'RaspyPlay3'), - m('option[value="raspyplay4"]', 'RaspyPlay4'), - m('option[selected=""][value="transducer"]', 'Transducer') - ]), - m('.btn-group.bootstrap-select', [m('button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle="dropdown"][title="Transducer"][type="button"]', [m('span.filter-option.pull-left', 'Transducer'), ' ', m('span.caret')]), m('.dropdown-menu.open', [m('ul.dropdown-menu.inner.selectpicker[role="menu"]', [m('li[rel="0"]', [m('a[tabindex="0"]', [m('span.text', 'I²S disabled (default)'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="1"]', [m('a[tabindex="0"]', [m('span.text', 'G2Labs BerryNOS'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="2"]', [m('a[tabindex="0"]', [m('span.text', 'G2Labs BerryNOS mini'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="3"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry DAC'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="4"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry DAC+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="5"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry Digi / Digi+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="6"]', [m('a[tabindex="0"]', [m('span.text', 'IQaudIO Pi-DAC / Pi-DAC+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="7"]', [m('a[tabindex="0"]', [m('span.text', 'RaspyPlay3'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="8"]', [m('a[tabindex="0"]', [m('span.text', 'RaspyPlay4'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li.selected[rel="9"]', [m('a[tabindex="0"]', [m('span.text', 'Transducer'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])])])])]), - m('span.help-block', ['Enable I²S output selecting one of the available sets of modules, specific for each hardware. Once set, the output interface will appear in the ', m('a[href="/mpd/"]', 'MPD configuration select menu'), ', and modules will also auto-load from the next reboot.']) - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="orionprofile"]', 'Sound Signature (optimization profiles)'), - m('.col-sm-10', [ - m('select.selectpicker[data-style="btn-default btn-lg"][name="orionprofile"]', mithril.createInput(settings.vm.data, "orionprofile", helpers.selectpicker), [ - m('option[value="default"]', 'ArchLinux default'), - m('option[value="RuneAudio"]', 'RuneAudio'), - m('option[selected=""][value="ACX"]', 'ACX'), - m('option[value="Orion"]', 'Orion'), - m('option[value="OrionV2"]', 'OrionV2'), - m('option[value="OrionV3_berrynosmini"]', 'OrionV3 - (BerryNOS-mini)'), - m('option[value="OrionV3_iqaudio"]', 'OrionV3 - (IQaudioPi-DAC)'), - m('option[value="Um3ggh1U"]', 'Um3ggh1U') - ]), - m('span.help-block', ['These profiles include a set of performance tweaks that act on some system kernel parameters.\n It does not have anything to do with DSPs or other sound effects: the output is kept untouched (bit perfect).\n It happens that these parameters introduce an audible impact on the overall sound quality, acting on kernel latency parameters (and probably on the amount of overall \n ', m('a[href="http://www.thewelltemperedcomputer.com/KB/BitPerfectJitter.htm"][target="_blank"][title="Bit Perfect Jitter by Vincent Kars"]', 'jitter'), ').\n Sound results may vary depending on where music is listened, so choose according to your personal taste.\n (If you can"t hear any tangible differences... nevermind, just stick to the default settings.)']) - ]) - ]), - m('.form-group.form-actions', [ - m('.col-sm-offset-2.col-sm-10', [ - m('button.btn.btn-primary.btn-lg[type="submit"]', 'Apply settings') - ]) - ]), - m('fieldset.form-horizontal[id="features-management"]', [ - m('legend', 'Features management'), - m('p', 'Enable/disable optional modules that best suit your needs. Disabling unusued features will free system resources and might improve the overall performance.'), - m('[id="airplayBox"]', { className: settings.vm.data.features.airplay.enable ? 'boxed-group' : '' }, [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="airplay"]', 'AirPlay'), - m('.col-sm-10', [ - mithril.createYesNo('enable', settings.vm.data.features.airplay, 'enable'), - m('span.help-block', 'Toggle the capability of receiving wireless streaming of audio via AirPlay protocol') - ]) - ]), - m('[id="airplayName"]', { className: settings.vm.data.features.airplay.enable ? '' : 'hide' }, [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="airplay-name"]', 'AirPlay name'), - m('.col-sm-10', [ - m('input.form-control.input-lg[data-parsley-id="0928"][data-trigger="change"][id="airplay_name"][name="features[airplay][name]"][placeholder="runeaudio"][type="text"][value="RuneAudio"]'), - m('ul.parsley-errors-list[id="parsley-id-0928"]'), - m('span.help-block', 'AirPlay broadcast name') - ]) - ]) - ]) - ]), - m('[id="spotifyBox"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="spotify"]', 'Spotify'), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[data-parsley-id="3701"][data-parsley-multiple="featuresspotifyenable"][id="spotify"][name="features[spotify][enable]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary.') - ]), - m('ul.parsley-errors-list[id="parsley-id-multiple-featuresspotifyenable"]'), - m('span.help-block', ['Enable Spotify client [EXPERIMENTAL]. You must have a ', m('strong', [m('a[href="https://www.spotify.com/uk/premium/"][target="_blank"]', 'Spotify PREMIUM')]), ' account.']) - ]) - ]), - m('.hide[id="spotifyAuth"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="spotify-usr"]', 'Username'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="0174"][data-trigger="change"][id="spotify_user"][name="features[spotify][user]"][placeholder="user"][type="text"][value="user"]'), - m('ul.parsley-errors-list[id="parsley-id-0174"]'), - m('span.help-block', ['Insert your Spotify ', m('i', 'username')]) - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="spotify-pasw"]', 'Password'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="0985"][id="spotify_pass"][name="features[spotify][pass]"][placeholder="pass"][type="password"][value="pass"]'), - m('ul.parsley-errors-list[id="parsley-id-0985"]'), - m('span.help-block', ['Insert your Spotify ', m('i', 'password'), ' (case sensitive)']) - ]) - ]) - ]) - ]), - m('[id="dlnaBox"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="dlna"]', 'UPnP / DLNA'), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[data-parsley-id="1837"][data-parsley-multiple="featuresdlnaenable"][id="dlna"][name="features[dlna][enable]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary') - ]), - m('ul.parsley-errors-list[id="parsley-id-multiple-featuresdlnaenable"]'), - m('span.help-block', 'Toggle the capability of receiving wireless streaming of audio via UPnP / DLNA protocol') - ]) - ]), - m('.hide[id="dlnaName"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="dlna-name"]', 'UPnP / DLNA name'), - m('.col-sm-10', [ - m('input.form-control.input-lg[data-parsley-id="8193"][data-trigger="change"][id="dlna_name"][name="features[dlna][name]"][placeholder="runeaudio"][type="text"][value="RuneAudio"]'), - m('ul.parsley-errors-list[id="parsley-id-8193"]'), - m('span.help-block', 'UPnP / DLNA broadcast name') - ]) - ]) - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="udevil"]', 'USB Automount'), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[data-parsley-id="1024"][data-parsley-multiple="featuresudevil"][name="features[udevil]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary') - ]), - m('ul.parsley-errors-list[id="parsley-id-multiple-featuresudevil"]'), - m('span.help-block', 'Toggle automount for USB drives') - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="coverart"]', 'Display album cover'), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[checked="checked"][data-parsley-id="5818"][data-parsley-multiple="featurescoverart"][name="features[coverart]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary') - ]), - m('ul.parsley-errors-list[id="parsley-id-multiple-featurescoverart"]'), - m('span.help-block', 'Toggle the display of album art on the Playback main screen') - ]) - ]), - m('[id="lastfmBox"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="lastfm"]', [m('i.fa.fa.fa-lastfm-square'), ' Last.fm']), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[data-parsley-id="6913"][data-parsley-multiple="featureslastfmenable"][id="scrobbling-lastfm"][name="features[lastfm][enable]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary') - ]), - m('ul.parsley-errors-list[id="parsley-id-multiple-featureslastfmenable"]'), - m('span.help-block', 'Send to Last.fm informations about the music you are listening to (requires a Last.fm account)') - ]) - ]), - m('.hide[id="lastfmAuth"]', [ - m('.form-group', [ - m('label.control-label.col-sm-2[for="lastfm-usr"]', 'Username'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="9931"][data-trigger="change"][id="lastfm_user"][name="features[lastfm][user]"][placeholder="user"][type="text"][value="user"]'), - m('ul.parsley-errors-list[id="parsley-id-9931"]'), - m('span.help-block', ['Insert your Last.fm ', m('i', 'username')]) - ]) - ]), - m('.form-group', [ - m('label.control-label.col-sm-2[for="lastfm-pasw"]', 'Password'), - m('.col-sm-10', [ - m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="2505"][id="lastfm_pass"][name="features[lastfm][pass]"][placeholder="pass"][type="password"][value="pass"]'), - m('ul.parsley-errors-list[id="parsley-id-2505"]'), - m('span.help-block', ['Insert your Last.fm ', m('i', 'password'), ' (case sensitive)']) - ]) - ]) - ]) - ]), - m('.form-group.form-actions', [ - m('.col-sm-offset-2.col-sm-10', [ - m('button.btn.btn-primary.btn-lg[name="features[submit]"][type="button"]', { onclick: function(e){ settings.vm.save('features'); } }, 'apply settings') - ]) - ]) - ]), - m('fieldset.form-horizontal', [ - m('legend', 'Compatibility fixes'), - m('p', 'For people suffering problems with some receivers and DACs.'), - m('.form-group', [ - m('label.control-label.col-sm-2[for="cmediafix"]', 'CMedia fix'), - m('.col-sm-10', [ - m('label.switch-light.well[onclick=""]', [ - m('input[name="cmediafix[1]"][type="checkbox"][value="1"]'), - m('span', [m('span', 'OFF'), m('span', 'ON')]), - m('a.btn.btn-primary') - ]), - m('span.help-block', ['For those who have a CM6631 receiver and experiment issues (noise, crackling) between tracks with different sample rates and/or bit depth.', m('br'), ' \n A \'dirty\' fix that should avoid the problem, do NOT use if everything works normally.']) - ]) - ]), - m('.form-group.form-actions', [ - m('.col-sm-offset-2.col-sm-10', [ - m('button.btn.btn-primary.btn-lg[name="cmediafix[0]"][type="submit"][value="1"]', 'Apply fixes') - ]) - ]) - ]), - m('fieldset.form-horizontal', [ - m('legend', 'Backup / Restore configuration'), - m('p', 'Transfer settings between multiple RuneAudio installations, saving time during new/upgrade installations.'), - m('.form-group', [ - m('label.control-label.col-sm-2', 'Backup player config'), - m('.col-sm-10', [ - m('input.btn.btn-primary.btn-lg[id="syscmd-backup"][name="syscmd"][type="submit"][value="backup"]'), - m('span.help-block', 'NOTE: restore feature will come in 0.4 release.') - ]) - ]) - ]) - ])]; + m('h1', 'Settings'), + m('fieldset', [ + m('legend', 'Environment'), + m('.form-group[id="systemstatus"]', [ + m('label.control-label.col-sm-2', 'Check system status'), + m('.col-sm-10', [ + m('a.btn.btn-default.btn-lg[data-toggle="modal"][href="#modal-sysinfo"]', [m('i.fa.fa-info-circle.sx'), 'show status']), + m('span.help-block', 'See information regarding the system and its status.') + ]) + ]), + m('.form-group[id="environment"]', [ + m('label.control-label.col-sm-2[for="hostname"]', 'Player hostname'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][id="hostname"][placeholder="runeaudio"][type="text"]', mithril.createInput(settings.vm.data.environment, 'hostname')), + m('span.help-block', 'Set the player hostname. This will change the address used to reach the RuneUI.') + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="ntpserver"]', 'NTP server'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][id="ntpserver"][placeholder="pool.ntp.org"][type="text"]', mithril.createInput(settings.vm.data.environment, 'ntpserver')), + m('span.help-block', ['Set your reference time sync server ', m('i', '(NTP server)'), '.']) + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="timezone"]', 'Timezone'), + m('.col-sm-10', [ + // [TODO] re-enable this when the rendering performance issue is solved + // m('select[data-style="btn-default btn-lg"][id="timezone"]', { config: helpers.selectpicker }, [m('option[value="Africa/Abidjan"]', 'Africa/Abidjan - GMT +00:00'), m('option[value="Africa/Accra"]', 'Africa/Accra - GMT +00:00'), m('option[value="Africa/Addis_Ababa"]', 'Africa/Addis_Ababa - GMT +03:00'), m('option[value="Africa/Algiers"]', 'Africa/Algiers - GMT +00:00'), m('option[value="Africa/Asmara"]', 'Africa/Asmara - GMT +03:00'), m('option[value="Africa/Bamako"]', 'Africa/Bamako - GMT +00:00'), m('option[value="Africa/Bangui"]', 'Africa/Bangui - GMT +01:00'), m('option[value="Africa/Banjul"]', 'Africa/Banjul - GMT +00:00'), m('option[value="Africa/Bissau"]', 'Africa/Bissau - GMT -01:00'), m('option[value="Africa/Blantyre"]', 'Africa/Blantyre - GMT +02:00'), m('option[value="Africa/Brazzaville"]', 'Africa/Brazzaville - GMT +01:00'), m('option[value="Africa/Bujumbura"]', 'Africa/Bujumbura - GMT +02:00'), m('option[value="Africa/Cairo"]', 'Africa/Cairo - GMT +02:00'), m('option[value="Africa/Casablanca"]', 'Africa/Casablanca - GMT +00:00'), m('option[value="Africa/Ceuta"]', 'Africa/Ceuta - GMT +00:00'), m('option[value="Africa/Conakry"]', 'Africa/Conakry - GMT +00:00'), m('option[value="Africa/Dakar"]', 'Africa/Dakar - GMT +00:00'), m('option[value="Africa/Dar_es_Salaam"]', 'Africa/Dar_es_Salaam - GMT +03:00'), m('option[value="Africa/Djibouti"]', 'Africa/Djibouti - GMT +03:00'), m('option[value="Africa/Douala"]', 'Africa/Douala - GMT +01:00'), m('option[value="Africa/El_Aaiun"]', 'Africa/El_Aaiun - GMT -01:00'), m('option[value="Africa/Freetown"]', 'Africa/Freetown - GMT +00:00'), m('option[value="Africa/Gaborone"]', 'Africa/Gaborone - GMT +02:00'), m('option[value="Africa/Harare"]', 'Africa/Harare - GMT +02:00'), m('option[value="Africa/Johannesburg"]', 'Africa/Johannesburg - GMT +02:00'), m('option[value="Africa/Juba"]', 'Africa/Juba - GMT +02:00'), m('option[value="Africa/Kampala"]', 'Africa/Kampala - GMT +03:00'), m('option[value="Africa/Khartoum"]', 'Africa/Khartoum - GMT +02:00'), m('option[value="Africa/Kigali"]', 'Africa/Kigali - GMT +02:00'), m('option[value="Africa/Kinshasa"]', 'Africa/Kinshasa - GMT +01:00'), m('option[value="Africa/Lagos"]', 'Africa/Lagos - GMT +01:00'), m('option[value="Africa/Libreville"]', 'Africa/Libreville - GMT +01:00'), m('option[value="Africa/Lome"]', 'Africa/Lome - GMT +00:00'), m('option[value="Africa/Luanda"]', 'Africa/Luanda - GMT +01:00'), m('option[value="Africa/Lubumbashi"]', 'Africa/Lubumbashi - GMT +02:00'), m('option[value="Africa/Lusaka"]', 'Africa/Lusaka - GMT +02:00'), m('option[value="Africa/Malabo"]', 'Africa/Malabo - GMT +01:00'), m('option[value="Africa/Maputo"]', 'Africa/Maputo - GMT +02:00'), m('option[value="Africa/Maseru"]', 'Africa/Maseru - GMT +02:00'), m('option[value="Africa/Mbabane"]', 'Africa/Mbabane - GMT +02:00'), m('option[value="Africa/Mogadishu"]', 'Africa/Mogadishu - GMT +03:00'), m('option[value="Africa/Monrovia"]', 'Africa/Monrovia - GMT -00:44'), m('option[value="Africa/Nairobi"]', 'Africa/Nairobi - GMT +03:00'), m('option[value="Africa/Ndjamena"]', 'Africa/Ndjamena - GMT +01:00'), m('option[value="Africa/Niamey"]', 'Africa/Niamey - GMT +01:00'), m('option[value="Africa/Nouakchott"]', 'Africa/Nouakchott - GMT +00:00'), m('option[value="Africa/Ouagadougou"]', 'Africa/Ouagadougou - GMT +00:00'), m('option[value="Africa/Porto-Novo"]', 'Africa/Porto-Novo - GMT +01:00'), m('option[value="Africa/Sao_Tome"]', 'Africa/Sao_Tome - GMT +00:00'), m('option[value="Africa/Tripoli"]', 'Africa/Tripoli - GMT +02:00'), m('option[value="Africa/Tunis"]', 'Africa/Tunis - GMT +01:00'), m('option[value="Africa/Windhoek"]', 'Africa/Windhoek - GMT +02:00'), m('option[value="America/Adak"]', 'America/Adak - GMT -11:00'), m('option[value="America/Anchorage"]', 'America/Anchorage - GMT -10:00'), m('option[value="America/Anguilla"]', 'America/Anguilla - GMT -04:00'), m('option[value="America/Antigua"]', 'America/Antigua - GMT -04:00'), m('option[value="America/Araguaina"]', 'America/Araguaina - GMT -03:00'), m('option[value="America/Argentina/Buenos_Aires"]', 'America/Argentina/Buenos_Aires - GMT -03:00'), m('option[value="America/Argentina/Catamarca"]', 'America/Argentina/Catamarca - GMT -03:00'), m('option[value="America/Argentina/Cordoba"]', 'America/Argentina/Cordoba - GMT -03:00'), m('option[value="America/Argentina/Jujuy"]', 'America/Argentina/Jujuy - GMT -03:00'), m('option[value="America/Argentina/La_Rioja"]', 'America/Argentina/La_Rioja - GMT -03:00'), m('option[value="America/Argentina/Mendoza"]', 'America/Argentina/Mendoza - GMT -03:00'), m('option[value="America/Argentina/Rio_Gallegos"]', 'America/Argentina/Rio_Gallegos - GMT -03:00'), m('option[value="America/Argentina/Salta"]', 'America/Argentina/Salta - GMT -03:00'), m('option[value="America/Argentina/San_Juan"]', 'America/Argentina/San_Juan - GMT -03:00'), m('option[value="America/Argentina/San_Luis"]', 'America/Argentina/San_Luis - GMT -03:00'), m('option[value="America/Argentina/Tucuman"]', 'America/Argentina/Tucuman - GMT -03:00'), m('option[value="America/Argentina/Ushuaia"]', 'America/Argentina/Ushuaia - GMT -03:00'), m('option[value="America/Aruba"]', 'America/Aruba - GMT -04:00'), m('option[value="America/Asuncion"]', 'America/Asuncion - GMT -04:00'), m('option[value="America/Atikokan"]', 'America/Atikokan - GMT -05:00'), m('option[value="America/Bahia"]', 'America/Bahia - GMT -03:00'), m('option[value="America/Bahia_Banderas"]', 'America/Bahia_Banderas - GMT -07:00'), m('option[value="America/Barbados"]', 'America/Barbados - GMT -04:00'), m('option[value="America/Belem"]', 'America/Belem - GMT -03:00'), m('option[value="America/Belize"]', 'America/Belize - GMT -06:00'), m('option[value="America/Blanc-Sablon"]', 'America/Blanc-Sablon - GMT -04:00'), m('option[value="America/Boa_Vista"]', 'America/Boa_Vista - GMT -04:00'), m('option[value="America/Bogota"]', 'America/Bogota - GMT -05:00'), m('option[value="America/Boise"]', 'America/Boise - GMT -07:00'), m('option[value="America/Cambridge_Bay"]', 'America/Cambridge_Bay - GMT -07:00'), m('option[value="America/Campo_Grande"]', 'America/Campo_Grande - GMT -04:00'), m('option[value="America/Cancun"]', 'America/Cancun - GMT -06:00'), m('option[value="America/Caracas"]', 'America/Caracas - GMT -04:00'), m('option[value="America/Cayenne"]', 'America/Cayenne - GMT -03:00'), m('option[value="America/Cayman"]', 'America/Cayman - GMT -05:00'), m('option[value="America/Chicago"]', 'America/Chicago - GMT -06:00'), m('option[value="America/Chihuahua"]', 'America/Chihuahua - GMT -06:00'), m('option[value="America/Costa_Rica"]', 'America/Costa_Rica - GMT -06:00'), m('option[value="America/Creston"]', 'America/Creston - GMT -07:00'), m('option[value="America/Cuiaba"]', 'America/Cuiaba - GMT -04:00'), m('option[value="America/Curacao"]', 'America/Curacao - GMT -04:00'), m('option[value="America/Danmarkshavn"]', 'America/Danmarkshavn - GMT -03:00'), m('option[value="America/Dawson"]', 'America/Dawson - GMT -09:00'), m('option[value="America/Dawson_Creek"]', 'America/Dawson_Creek - GMT -08:00'), m('option[value="America/Denver"]', 'America/Denver - GMT -07:00'), m('option[value="America/Detroit"]', 'America/Detroit - GMT -05:00'), m('option[value="America/Dominica"]', 'America/Dominica - GMT -04:00'), m('option[value="America/Edmonton"]', 'America/Edmonton - GMT -07:00'), m('option[value="America/Eirunepe"]', 'America/Eirunepe - GMT -05:00'), m('option[value="America/El_Salvador"]', 'America/El_Salvador - GMT -06:00'), m('option[value="America/Fortaleza"]', 'America/Fortaleza - GMT -03:00'), m('option[value="America/Glace_Bay"]', 'America/Glace_Bay - GMT -04:00'), m('option[value="America/Godthab"]', 'America/Godthab - GMT -03:00'), m('option[value="America/Goose_Bay"]', 'America/Goose_Bay - GMT -04:00'), m('option[value="America/Grand_Turk"]', 'America/Grand_Turk - GMT -05:00'), m('option[value="America/Grenada"]', 'America/Grenada - GMT -04:00'), m('option[value="America/Guadeloupe"]', 'America/Guadeloupe - GMT -04:00'), m('option[value="America/Guatemala"]', 'America/Guatemala - GMT -06:00'), m('option[value="America/Guayaquil"]', 'America/Guayaquil - GMT -05:00'), m('option[value="America/Guyana"]', 'America/Guyana - GMT -03:45'), m('option[value="America/Halifax"]', 'America/Halifax - GMT -04:00'), m('option[value="America/Havana"]', 'America/Havana - GMT -05:00'), m('option[value="America/Hermosillo"]', 'America/Hermosillo - GMT -07:00'), m('option[value="America/Indiana/Indianapolis"]', 'America/Indiana/Indianapolis - GMT -05:00'), m('option[value="America/Indiana/Knox"]', 'America/Indiana/Knox - GMT -06:00'), m('option[value="America/Indiana/Marengo"]', 'America/Indiana/Marengo - GMT -05:00'), m('option[value="America/Indiana/Petersburg"]', 'America/Indiana/Petersburg - GMT -06:00'), m('option[value="America/Indiana/Tell_City"]', 'America/Indiana/Tell_City - GMT -05:00'), m('option[value="America/Indiana/Vevay"]', 'America/Indiana/Vevay - GMT -05:00'), m('option[value="America/Indiana/Vincennes"]', 'America/Indiana/Vincennes - GMT -05:00'), m('option[value="America/Indiana/Winamac"]', 'America/Indiana/Winamac - GMT -05:00'), m('option[value="America/Inuvik"]', 'America/Inuvik - GMT -08:00'), m('option[value="America/Iqaluit"]', 'America/Iqaluit - GMT -05:00'), m('option[value="America/Jamaica"]', 'America/Jamaica - GMT -05:00'), m('option[value="America/Juneau"]', 'America/Juneau - GMT -08:00'), m('option[value="America/Kentucky/Louisville"]', 'America/Kentucky/Louisville - GMT -05:00'), m('option[value="America/Kentucky/Monticello"]', 'America/Kentucky/Monticello - GMT -06:00'), m('option[value="America/Kralendijk"]', 'America/Kralendijk - GMT -04:00'), m('option[value="America/La_Paz"]', 'America/La_Paz - GMT -04:00'), m('option[value="America/Lima"]', 'America/Lima - GMT -05:00'), m('option[value="America/Los_Angeles"]', 'America/Los_Angeles - GMT -08:00'), m('option[value="America/Lower_Princes"]', 'America/Lower_Princes - GMT -04:00'), m('option[value="America/Maceio"]', 'America/Maceio - GMT -03:00'), m('option[value="America/Managua"]', 'America/Managua - GMT -06:00'), m('option[value="America/Manaus"]', 'America/Manaus - GMT -04:00'), m('option[value="America/Marigot"]', 'America/Marigot - GMT -04:00'), m('option[value="America/Martinique"]', 'America/Martinique - GMT -04:00'), m('option[value="America/Matamoros"]', 'America/Matamoros - GMT -06:00'), m('option[value="America/Mazatlan"]', 'America/Mazatlan - GMT -07:00'), m('option[value="America/Menominee"]', 'America/Menominee - GMT -05:00'), m('option[value="America/Merida"]', 'America/Merida - GMT -06:00'), m('option[value="America/Metlakatla"]', 'America/Metlakatla - GMT -08:00'), m('option[value="America/Mexico_City"]', 'America/Mexico_City - GMT -06:00'), m('option[value="America/Miquelon"]', 'America/Miquelon - GMT -04:00'), m('option[value="America/Moncton"]', 'America/Moncton - GMT -04:00'), m('option[value="America/Monterrey"]', 'America/Monterrey - GMT -06:00'), m('option[value="America/Montevideo"]', 'America/Montevideo - GMT -03:00'), m('option[value="America/Montserrat"]', 'America/Montserrat - GMT -04:00'), m('option[value="America/Nassau"]', 'America/Nassau - GMT -05:00'), m('option[value="America/New_York"]', 'America/New_York - GMT -05:00'), m('option[value="America/Nipigon"]', 'America/Nipigon - GMT -05:00'), m('option[value="America/Nome"]', 'America/Nome - GMT -11:00'), m('option[value="America/Noronha"]', 'America/Noronha - GMT -02:00'), m('option[value="America/North_Dakota/Beulah"]', 'America/North_Dakota/Beulah - GMT -07:00'), m('option[value="America/North_Dakota/Center"]', 'America/North_Dakota/Center - GMT -07:00'), m('option[value="America/North_Dakota/New_Salem"]', 'America/North_Dakota/New_Salem - GMT -07:00'), m('option[value="America/Ojinaga"]', 'America/Ojinaga - GMT -06:00'), m('option[value="America/Panama"]', 'America/Panama - GMT -05:00'), m('option[value="America/Pangnirtung"]', 'America/Pangnirtung - GMT -04:00'), m('option[value="America/Paramaribo"]', 'America/Paramaribo - GMT -03:30'), m('option[value="America/Phoenix"]', 'America/Phoenix - GMT -07:00'), m('option[value="America/Port-au-Prince"]', 'America/Port-au-Prince - GMT -05:00'), m('option[value="America/Port_of_Spain"]', 'America/Port_of_Spain - GMT -04:00'), m('option[value="America/Porto_Velho"]', 'America/Porto_Velho - GMT -04:00'), m('option[value="America/Puerto_Rico"]', 'America/Puerto_Rico - GMT -04:00'), m('option[value="America/Rainy_River"]', 'America/Rainy_River - GMT -06:00'), m('option[value="America/Rankin_Inlet"]', 'America/Rankin_Inlet - GMT -06:00'), m('option[value="America/Recife"]', 'America/Recife - GMT -03:00'), m('option[value="America/Regina"]', 'America/Regina - GMT -06:00'), m('option[value="America/Resolute"]', 'America/Resolute - GMT -06:00'), m('option[value="America/Rio_Branco"]', 'America/Rio_Branco - GMT -05:00'), m('option[value="America/Santa_Isabel"]', 'America/Santa_Isabel - GMT -08:00'), m('option[value="America/Santarem"]', 'America/Santarem - GMT -04:00'), m('option[value="America/Santiago"]', 'America/Santiago - GMT -03:00'), m('option[value="America/Santo_Domingo"]', 'America/Santo_Domingo - GMT -04:30'), m('option[value="America/Sao_Paulo"]', 'America/Sao_Paulo - GMT -03:00'), m('option[value="America/Scoresbysund"]', 'America/Scoresbysund - GMT -02:00'), m('option[value="America/Sitka"]', 'America/Sitka - GMT -08:00'), m('option[value="America/St_Barthelemy"]', 'America/St_Barthelemy - GMT -04:00'), m('option[value="America/St_Johns"]', 'America/St_Johns - GMT -03:30'), m('option[value="America/St_Kitts"]', 'America/St_Kitts - GMT -04:00'), m('option[value="America/St_Lucia"]', 'America/St_Lucia - GMT -04:00'), m('option[value="America/St_Thomas"]', 'America/St_Thomas - GMT -04:00'), m('option[value="America/St_Vincent"]', 'America/St_Vincent - GMT -04:00'), m('option[value="America/Swift_Current"]', 'America/Swift_Current - GMT -07:00'), m('option[value="America/Tegucigalpa"]', 'America/Tegucigalpa - GMT -06:00'), m('option[value="America/Thule"]', 'America/Thule - GMT -04:00'), m('option[value="America/Thunder_Bay"]', 'America/Thunder_Bay - GMT -05:00'), m('option[value="America/Tijuana"]', 'America/Tijuana - GMT -08:00'), m('option[value="America/Toronto"]', 'America/Toronto - GMT -05:00'), m('option[value="America/Tortola"]', 'America/Tortola - GMT -04:00'), m('option[value="America/Vancouver"]', 'America/Vancouver - GMT -08:00'), m('option[value="America/Whitehorse"]', 'America/Whitehorse - GMT -08:00'), m('option[value="America/Winnipeg"]', 'America/Winnipeg - GMT -06:00'), m('option[value="America/Yakutat"]', 'America/Yakutat - GMT -09:00'), m('option[value="America/Yellowknife"]', 'America/Yellowknife - GMT -07:00'), m('option[value="Antarctica/Casey"]', 'Antarctica/Casey - GMT +08:00'), m('option[value="Antarctica/Davis"]', 'Antarctica/Davis - GMT +07:00'), m('option[value="Antarctica/DumontDUrville"]', 'Antarctica/DumontDUrville - GMT +10:00'), m('option[value="Antarctica/Macquarie"]', 'Antarctica/Macquarie - GMT +11:00'), m('option[value="Antarctica/Mawson"]', 'Antarctica/Mawson - GMT +06:00'), m('option[value="Antarctica/McMurdo"]', 'Antarctica/McMurdo - GMT +12:00'), m('option[value="Antarctica/Palmer"]', 'Antarctica/Palmer - GMT -03:00'), m('option[value="Antarctica/Rothera"]', 'Antarctica/Rothera - GMT +00:00'), m('option[value="Antarctica/Syowa"]', 'Antarctica/Syowa - GMT +03:00'), m('option[value="Antarctica/Troll"]', 'Antarctica/Troll - GMT +00:00'), m('option[value="Antarctica/Vostok"]', 'Antarctica/Vostok - GMT +06:00'), m('option[value="Arctic/Longyearbyen"]', 'Arctic/Longyearbyen - GMT +01:00'), m('option[value="Asia/Aden"]', 'Asia/Aden - GMT +03:00'), m('option[value="Asia/Almaty"]', 'Asia/Almaty - GMT +06:00'), m('option[value="Asia/Amman"]', 'Asia/Amman - GMT +02:00'), m('option[value="Asia/Anadyr"]', 'Asia/Anadyr - GMT +13:00'), m('option[value="Asia/Aqtau"]', 'Asia/Aqtau - GMT +05:00'), m('option[value="Asia/Aqtobe"]', 'Asia/Aqtobe - GMT +05:00'), m('option[value="Asia/Ashgabat"]', 'Asia/Ashgabat - GMT +05:00'), m('option[value="Asia/Baghdad"]', 'Asia/Baghdad - GMT +03:00'), m('option[value="Asia/Bahrain"]', 'Asia/Bahrain - GMT +04:00'), m('option[value="Asia/Baku"]', 'Asia/Baku - GMT +04:00'), m('option[value="Asia/Bangkok"]', 'Asia/Bangkok - GMT +07:00'), m('option[value="Asia/Beirut"]', 'Asia/Beirut - GMT +02:00'), m('option[value="Asia/Bishkek"]', 'Asia/Bishkek - GMT +06:00'), m('option[value="Asia/Brunei"]', 'Asia/Brunei - GMT +08:00'), m('option[value="Asia/Chita"]', 'Asia/Chita - GMT +09:00'), m('option[value="Asia/Choibalsan"]', 'Asia/Choibalsan - GMT +07:00'), m('option[value="Asia/Colombo"]', 'Asia/Colombo - GMT +05:30'), m('option[value="Asia/Damascus"]', 'Asia/Damascus - GMT +02:00'), m('option[value="Asia/Dhaka"]', 'Asia/Dhaka - GMT +06:00'), m('option[value="Asia/Dili"]', 'Asia/Dili - GMT +09:00'), m('option[value="Asia/Dubai"]', 'Asia/Dubai - GMT +04:00'), m('option[value="Asia/Dushanbe"]', 'Asia/Dushanbe - GMT +06:00'), m('option[value="Asia/Gaza"]', 'Asia/Gaza - GMT +02:00'), m('option[value="Asia/Hebron"]', 'Asia/Hebron - GMT +02:00'), m('option[value="Asia/Ho_Chi_Minh"]', 'Asia/Ho_Chi_Minh - GMT +07:00'), m('option[value="Asia/Hong_Kong"]', 'Asia/Hong_Kong - GMT +08:00'), m('option[value="Asia/Hovd"]', 'Asia/Hovd - GMT +06:00'), m('option[value="Asia/Irkutsk"]', 'Asia/Irkutsk - GMT +08:00'), m('option[value="Asia/Jakarta"]', 'Asia/Jakarta - GMT +07:00'), m('option[value="Asia/Jayapura"]', 'Asia/Jayapura - GMT +09:00'), m('option[value="Asia/Jerusalem"]', 'Asia/Jerusalem - GMT +02:00'), m('option[value="Asia/Kabul"]', 'Asia/Kabul - GMT +04:30'), m('option[value="Asia/Kamchatka"]', 'Asia/Kamchatka - GMT +12:00'), m('option[value="Asia/Karachi"]', 'Asia/Karachi - GMT +05:00'), m('option[value="Asia/Kathmandu"]', 'Asia/Kathmandu - GMT +05:30'), m('option[value="Asia/Khandyga"]', 'Asia/Khandyga - GMT +09:00'), m('option[value="Asia/Kolkata"]', 'Asia/Kolkata - GMT +05:30'), m('option[value="Asia/Krasnoyarsk"]', 'Asia/Krasnoyarsk - GMT +07:00'), m('option[value="Asia/Kuala_Lumpur"]', 'Asia/Kuala_Lumpur - GMT +07:30'), m('option[value="Asia/Kuching"]', 'Asia/Kuching - GMT +08:00'), m('option[value="Asia/Kuwait"]', 'Asia/Kuwait - GMT +03:00'), m('option[value="Asia/Macau"]', 'Asia/Macau - GMT +08:00'), m('option[value="Asia/Magadan"]', 'Asia/Magadan - GMT +11:00'), m('option[value="Asia/Makassar"]', 'Asia/Makassar - GMT +08:00'), m('option[value="Asia/Manila"]', 'Asia/Manila - GMT +08:00'), m('option[value="Asia/Muscat"]', 'Asia/Muscat - GMT +04:00'), m('option[value="Asia/Nicosia"]', 'Asia/Nicosia - GMT +02:00'), m('option[value="Asia/Novokuznetsk"]', 'Asia/Novokuznetsk - GMT +07:00'), m('option[value="Asia/Novosibirsk"]', 'Asia/Novosibirsk - GMT +07:00'), m('option[value="Asia/Omsk"]', 'Asia/Omsk - GMT +06:00'), m('option[value="Asia/Oral"]', 'Asia/Oral - GMT +05:00'), m('option[value="Asia/Phnom_Penh"]', 'Asia/Phnom_Penh - GMT +07:00'), m('option[value="Asia/Pontianak"]', 'Asia/Pontianak - GMT +08:00'), m('option[value="Asia/Pyongyang"]', 'Asia/Pyongyang - GMT +09:00'), m('option[value="Asia/Qatar"]', 'Asia/Qatar - GMT +04:00'), m('option[value="Asia/Qyzylorda"]', 'Asia/Qyzylorda - GMT +05:00'), m('option[value="Asia/Rangoon"]', 'Asia/Rangoon - GMT +06:30'), m('option[value="Asia/Riyadh"]', 'Asia/Riyadh - GMT +03:00'), m('option[value="Asia/Sakhalin"]', 'Asia/Sakhalin - GMT +11:00'), m('option[value="Asia/Samarkand"]', 'Asia/Samarkand - GMT +05:00'), m('option[value="Asia/Seoul"]', 'Asia/Seoul - GMT +09:00'), m('option[value="Asia/Shanghai"]', 'Asia/Shanghai - GMT +08:00'), m('option[value="Asia/Singapore"]', 'Asia/Singapore - GMT +07:30'), m('option[value="Asia/Srednekolymsk"]', 'Asia/Srednekolymsk - GMT +11:00'), m('option[value="Asia/Taipei"]', 'Asia/Taipei - GMT +08:00'), m('option[value="Asia/Tashkent"]', 'Asia/Tashkent - GMT +06:00'), m('option[value="Asia/Tbilisi"]', 'Asia/Tbilisi - GMT +04:00'), m('option[value="Asia/Tehran"]', 'Asia/Tehran - GMT +03:30'), m('option[value="Asia/Thimphu"]', 'Asia/Thimphu - GMT +05:30'), m('option[value="Asia/Tokyo"]', 'Asia/Tokyo - GMT +09:00'), m('option[value="Asia/Ulaanbaatar"]', 'Asia/Ulaanbaatar - GMT +07:00'), m('option[value="Asia/Urumqi"]', 'Asia/Urumqi - GMT +06:00'), m('option[value="Asia/Ust-Nera"]', 'Asia/Ust-Nera - GMT +09:00'), m('option[value="Asia/Vientiane"]', 'Asia/Vientiane - GMT +07:00'), m('option[value="Asia/Vladivostok"]', 'Asia/Vladivostok - GMT +10:00'), m('option[value="Asia/Yakutsk"]', 'Asia/Yakutsk - GMT +09:00'), m('option[value="Asia/Yekaterinburg"]', 'Asia/Yekaterinburg - GMT +05:00'), m('option[value="Asia/Yerevan"]', 'Asia/Yerevan - GMT +04:00'), m('option[value="Atlantic/Azores"]', 'Atlantic/Azores - GMT -01:00'), m('option[value="Atlantic/Bermuda"]', 'Atlantic/Bermuda - GMT -04:00'), m('option[value="Atlantic/Canary"]', 'Atlantic/Canary - GMT +00:00'), m('option[value="Atlantic/Cape_Verde"]', 'Atlantic/Cape_Verde - GMT -02:00'), m('option[value="Atlantic/Faroe"]', 'Atlantic/Faroe - GMT +00:00'), m('option[value="Atlantic/Madeira"]', 'Atlantic/Madeira - GMT +00:00'), m('option[value="Atlantic/Reykjavik"]', 'Atlantic/Reykjavik - GMT +00:00'), m('option[value="Atlantic/South_Georgia"]', 'Atlantic/South_Georgia - GMT -02:00'), m('option[value="Atlantic/St_Helena"]', 'Atlantic/St_Helena - GMT +00:00'), m('option[value="Atlantic/Stanley"]', 'Atlantic/Stanley - GMT -04:00'), m('option[value="Australia/Adelaide"]', 'Australia/Adelaide - GMT +09:30'), m('option[value="Australia/Brisbane"]', 'Australia/Brisbane - GMT +10:00'), m('option[value="Australia/Broken_Hill"]', 'Australia/Broken_Hill - GMT +09:30'), m('option[value="Australia/Currie"]', 'Australia/Currie - GMT +10:00'), m('option[value="Australia/Darwin"]', 'Australia/Darwin - GMT +09:30'), m('option[value="Australia/Eucla"]', 'Australia/Eucla - GMT +08:45'), m('option[value="Australia/Hobart"]', 'Australia/Hobart - GMT +11:00'), m('option[value="Australia/Lindeman"]', 'Australia/Lindeman - GMT +10:00'), m('option[value="Australia/Lord_Howe"]', 'Australia/Lord_Howe - GMT +10:00'), m('option[value="Australia/Melbourne"]', 'Australia/Melbourne - GMT +10:00'), m('option[value="Australia/Perth"]', 'Australia/Perth - GMT +08:00'), m('option[value="Australia/Sydney"]', 'Australia/Sydney - GMT +10:00'), m('option[value="Europe/Amsterdam"]', 'Europe/Amsterdam - GMT +01:00'), m('option[value="Europe/Andorra"]', 'Europe/Andorra - GMT +01:00'), m('option[value="Europe/Athens"]', 'Europe/Athens - GMT +02:00'), m('option[value="Europe/Belgrade"]', 'Europe/Belgrade - GMT +01:00'), m('option[value="Europe/Berlin"]', 'Europe/Berlin - GMT +01:00'), m('option[value="Europe/Bratislava"]', 'Europe/Bratislava - GMT +01:00'), m('option[value="Europe/Brussels"]', 'Europe/Brussels - GMT +01:00'), m('option[value="Europe/Bucharest"]', 'Europe/Bucharest - GMT +02:00'), m('option[value="Europe/Budapest"]', 'Europe/Budapest - GMT +01:00'), m('option[value="Europe/Busingen"]', 'Europe/Busingen - GMT +01:00'), m('option[value="Europe/Chisinau"]', 'Europe/Chisinau - GMT +03:00'), m('option[value="Europe/Copenhagen"]', 'Europe/Copenhagen - GMT +01:00'), m('option[value="Europe/Dublin"]', 'Europe/Dublin - GMT +01:00'), m('option[value="Europe/Gibraltar"]', 'Europe/Gibraltar - GMT +01:00'), m('option[value="Europe/Guernsey"]', 'Europe/Guernsey - GMT +01:00'), m('option[value="Europe/Helsinki"]', 'Europe/Helsinki - GMT +02:00'), m('option[value="Europe/Isle_of_Man"]', 'Europe/Isle_of_Man - GMT +01:00'), m('option[value="Europe/Istanbul"]', 'Europe/Istanbul - GMT +02:00'), m('option[value="Europe/Jersey"]', 'Europe/Jersey - GMT +01:00'), m('option[value="Europe/Kaliningrad"]', 'Europe/Kaliningrad - GMT +03:00'), m('option[value="Europe/Kiev"]', 'Europe/Kiev - GMT +03:00'), m('option[value="Europe/Lisbon"]', 'Europe/Lisbon - GMT +01:00'), m('option[value="Europe/Ljubljana"]', 'Europe/Ljubljana - GMT +01:00'), m('option[value="Europe/London"]', 'Europe/London - GMT +01:00'), m('option[value="Europe/Luxembourg"]', 'Europe/Luxembourg - GMT +01:00'), m('option[value="Europe/Madrid"]', 'Europe/Madrid - GMT +01:00'), m('option[value="Europe/Malta"]', 'Europe/Malta - GMT +01:00'), m('option[value="Europe/Mariehamn"]', 'Europe/Mariehamn - GMT +02:00'), m('option[value="Europe/Minsk"]', 'Europe/Minsk - GMT +03:00'), m('option[value="Europe/Monaco"]', 'Europe/Monaco - GMT +01:00'), m('option[value="Europe/Moscow"]', 'Europe/Moscow - GMT +03:00'), m('option[value="Europe/Oslo"]', 'Europe/Oslo - GMT +01:00'), m('option[value="Europe/Paris"]', 'Europe/Paris - GMT +01:00'), m('option[value="Europe/Podgorica"]', 'Europe/Podgorica - GMT +01:00'), m('option[value="Europe/Prague"]', 'Europe/Prague - GMT +01:00'), m('option[value="Europe/Riga"]', 'Europe/Riga - GMT +03:00'), m('option[value="Europe/Rome"]', 'Europe/Rome - GMT +01:00'), m('option[value="Europe/Samara"]', 'Europe/Samara - GMT +04:00'), m('option[value="Europe/San_Marino"]', 'Europe/San_Marino - GMT +01:00'), m('option[value="Europe/Sarajevo"]', 'Europe/Sarajevo - GMT +01:00'), m('option[value="Europe/Simferopol"]', 'Europe/Simferopol - GMT +03:00'), m('option[value="Europe/Skopje"]', 'Europe/Skopje - GMT +01:00'), m('option[value="Europe/Sofia"]', 'Europe/Sofia - GMT +02:00'), m('option[value="Europe/Stockholm"]', 'Europe/Stockholm - GMT +01:00'), m('option[value="Europe/Tallinn"]', 'Europe/Tallinn - GMT +03:00'), m('option[value="Europe/Tirane"]', 'Europe/Tirane - GMT +01:00'), m('option[value="Europe/Uzhgorod"]', 'Europe/Uzhgorod - GMT +03:00'), m('option[value="Europe/Vaduz"]', 'Europe/Vaduz - GMT +01:00'), m('option[value="Europe/Vatican"]', 'Europe/Vatican - GMT +01:00'), m('option[value="Europe/Vienna"]', 'Europe/Vienna - GMT +01:00'), m('option[value="Europe/Vilnius"]', 'Europe/Vilnius - GMT +03:00'), m('option[value="Europe/Volgograd"]', 'Europe/Volgograd - GMT +04:00'), m('option[value="Europe/Warsaw"]', 'Europe/Warsaw - GMT +01:00'), m('option[value="Europe/Zagreb"]', 'Europe/Zagreb - GMT +01:00'), m('option[value="Europe/Zaporozhye"]', 'Europe/Zaporozhye - GMT +03:00'), m('option[value="Europe/Zurich"]', 'Europe/Zurich - GMT +01:00'), m('option[value="Indian/Antananarivo"]', 'Indian/Antananarivo - GMT +03:00'), m('option[value="Indian/Chagos"]', 'Indian/Chagos - GMT +05:00'), m('option[value="Indian/Christmas"]', 'Indian/Christmas - GMT +07:00'), m('option[value="Indian/Cocos"]', 'Indian/Cocos - GMT +06:30'), m('option[value="Indian/Comoro"]', 'Indian/Comoro - GMT +03:00'), m('option[value="Indian/Kerguelen"]', 'Indian/Kerguelen - GMT +05:00'), m('option[value="Indian/Mahe"]', 'Indian/Mahe - GMT +04:00'), m('option[value="Indian/Maldives"]', 'Indian/Maldives - GMT +05:00'), m('option[value="Indian/Mauritius"]', 'Indian/Mauritius - GMT +04:00'), m('option[value="Indian/Mayotte"]', 'Indian/Mayotte - GMT +03:00'), m('option[value="Indian/Reunion"]', 'Indian/Reunion - GMT +04:00'), m('option[value="Pacific/Apia"]', 'Pacific/Apia - GMT -11:00'), m('option[value="Pacific/Auckland"]', 'Pacific/Auckland - GMT +12:00'), m('option[value="Pacific/Chatham"]', 'Pacific/Chatham - GMT +12:45'), m('option[value="Pacific/Chuuk"]', 'Pacific/Chuuk - GMT +10:00'), m('option[value="Pacific/Easter"]', 'Pacific/Easter - GMT -06:00'), m('option[value="Pacific/Efate"]', 'Pacific/Efate - GMT +11:00'), m('option[value="Pacific/Enderbury"]', 'Pacific/Enderbury - GMT -12:00'), m('option[value="Pacific/Fakaofo"]', 'Pacific/Fakaofo - GMT -11:00'), m('option[value="Pacific/Fiji"]', 'Pacific/Fiji - GMT +12:00'), m('option[value="Pacific/Funafuti"]', 'Pacific/Funafuti - GMT +12:00'), m('option[value="Pacific/Galapagos"]', 'Pacific/Galapagos - GMT -05:00'), m('option[value="Pacific/Gambier"]', 'Pacific/Gambier - GMT -09:00'), m('option[value="Pacific/Guadalcanal"]', 'Pacific/Guadalcanal - GMT +11:00'), m('option[value="Pacific/Guam"]', 'Pacific/Guam - GMT +10:00'), m('option[value="Pacific/Honolulu"]', 'Pacific/Honolulu - GMT -10:00'), m('option[value="Pacific/Johnston"]', 'Pacific/Johnston - GMT -10:00'), m('option[value="Pacific/Kiritimati"]', 'Pacific/Kiritimati - GMT -10:40'), m('option[value="Pacific/Kosrae"]', 'Pacific/Kosrae - GMT +12:00'), m('option[value="Pacific/Kwajalein"]', 'Pacific/Kwajalein - GMT -12:00'), m('option[value="Pacific/Majuro"]', 'Pacific/Majuro - GMT +12:00'), m('option[value="Pacific/Marquesas"]', 'Pacific/Marquesas - GMT -09:30'), m('option[value="Pacific/Midway"]', 'Pacific/Midway - GMT -11:00'), m('option[value="Pacific/Nauru"]', 'Pacific/Nauru - GMT +11:30'), m('option[value="Pacific/Niue"]', 'Pacific/Niue - GMT -11:30'), m('option[value="Pacific/Norfolk"]', 'Pacific/Norfolk - GMT +11:30'), m('option[value="Pacific/Noumea"]', 'Pacific/Noumea - GMT +11:00'), m('option[value="Pacific/Pago_Pago"]', 'Pacific/Pago_Pago - GMT -11:00'), m('option[value="Pacific/Palau"]', 'Pacific/Palau - GMT +09:00'), m('option[value="Pacific/Pitcairn"]', 'Pacific/Pitcairn - GMT -08:30'), m('option[value="Pacific/Pohnpei"]', 'Pacific/Pohnpei - GMT +11:00'), m('option[value="Pacific/Port_Moresby"]', 'Pacific/Port_Moresby - GMT +10:00'), m('option[value="Pacific/Rarotonga"]', 'Pacific/Rarotonga - GMT -10:30'), m('option[value="Pacific/Saipan"]', 'Pacific/Saipan - GMT +10:00'), m('option[value="Pacific/Tahiti"]', 'Pacific/Tahiti - GMT -10:00'), m('option[value="Pacific/Tarawa"]', 'Pacific/Tarawa - GMT +12:00'), m('option[value="Pacific/Tongatapu"]', 'Pacific/Tongatapu - GMT +13:00'), m('option[value="Pacific/Wake"]', 'Pacific/Wake - GMT +12:00'), m('option[value="Pacific/Wallis"]', 'Pacific/Wallis - GMT +12:00'), m('option[value="UTC"]', 'UTC - GMT +00:00')]), + m('span.help-block', 'Set the system timezone.') + ]) + ]), + //m('.form-group.form-actions', [ + // m('.col-sm-offset-2.col-sm-10', [ + // m('button.btn.btn-primary.btn-lg[name="save"][type="submit"][value="save"]', 'Apply settings') + // ]) + //]), + m('.form-group.form-actions', [ + m('.col-sm-offset-2.col-sm-10', [ + m('button.btn.btn-default.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.cancel('environment'); + } + }, 'Cancel'), + m('button.btn.btn-primary.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.save('environment'); + } + }, 'Save and apply') + ]) + ]) + ]), + m('fieldset', [ + m('legend', 'RuneOS kernel settings'), + m('.form-group', [ + m('label.control-label.col-sm-2[for="i2smodule"]', 'Linux Kernel'), + m('.col-sm-10', [ + m('select.selectpicker[data-style="btn-default btn-lg"][name="kernel"]', { + style: { + 'display': ' none' + } + }, [ + m('option[selected=""][value="linux-arch-rpi_3.12.26-1-ARCH"]', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), + m('option[value="linux-rune-rpi_3.12.19-2-ARCH"]', 'Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]'), + m('option[value="linux-rune-rpi_3.6.11-18-ARCH+"]', 'Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]'), + m('option[value="linux-rune-rpi_3.12.13-rt21_wosa"]', 'Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]') + ]), + m('.btn-group.bootstrap-select', [m('button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle="dropdown"][title="Linux kernel 3.12.26-1   ARCH [RuneAudio v0.3-beta]"][type="button"]', [m('span.filter-option.pull-left', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), ' ', m('span.caret')]), m('.dropdown-menu.open', [m('ul.dropdown-menu.inner.selectpicker[role="menu"]', [m('li.selected[rel="0"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.26-1 ARCH [RuneAudio v0.3-beta]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="1"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.19-2 RUNE [RuneAudio v0.3-alpha]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="2"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.6.11-18 ARCH+ [RuneAudio v0.1-beta/v0.2-beta]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="3"]', [m('a[tabindex="0"]', [m('span.text', 'Linux kernel 3.12.13-rt RUNE-RT [Wolfson Audio Card]'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])])])])]), + m('span.help-block', ['Switch Linux Kernel version (REBOOT REQUIRED). ', m('strong', 'Linux kernel 3.12.26-1'), ' is the default kernel in the current release, ', m('strong', 'Linux kernel 3.12.19-2'), ' is the kernel used in RuneAudio v0.3-alpha, ', m('strong', 'Linux kernel 3.6.11-18'), ' is the kernel used in RuneAudio v0.1-beta/v0.2-beta (it has no support for I²S), ', m('strong', 'Linux kernel 3.12.13-rt'), ' is an EXPERIMENTAL kernel (not suitable for all configurations), it is optimized for ', m('strong', 'Wolfson Audio Card'), ' support and it is the default option for that type of soundcard.']) + ]), + m('label.control-label.col-sm-2[for="i2smodule"]', 'I²S kernel modules'), + m('.col-sm-10', [ + m('select.selectpicker[data-style="btn-default btn-lg"][name="i2smodule"]', { + style: { + 'display': ' none' + } + }, [ + m('option[value="none"]', 'I²S disabled (default)'), + m('option[value="berrynos"]', 'G2Labs BerryNOS'), + m('option[value="berrynosmini"]', 'G2Labs BerryNOS mini'), + m('option[value="hifiberrydac"]', 'HiFiBerry DAC'), + m('option[value="hifiberrydacplus"]', 'HiFiBerry DAC+'), + m('option[value="hifiberrydigi"]', 'HiFiBerry Digi / Digi+'), + m('option[value="iqaudiopidac"]', 'IQaudIO Pi-DAC / Pi-DAC+'), + m('option[value="raspyplay3"]', 'RaspyPlay3'), + m('option[value="raspyplay4"]', 'RaspyPlay4'), + m('option[selected=""][value="transducer"]', 'Transducer') + ]), + m('.btn-group.bootstrap-select', [m('button.btn.dropdown-toggle.selectpicker.btn-default.btn-lg[data-toggle="dropdown"][title="Transducer"][type="button"]', [m('span.filter-option.pull-left', 'Transducer'), ' ', m('span.caret')]), m('.dropdown-menu.open', [m('ul.dropdown-menu.inner.selectpicker[role="menu"]', [m('li[rel="0"]', [m('a[tabindex="0"]', [m('span.text', 'I²S disabled (default)'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="1"]', [m('a[tabindex="0"]', [m('span.text', 'G2Labs BerryNOS'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="2"]', [m('a[tabindex="0"]', [m('span.text', 'G2Labs BerryNOS mini'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="3"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry DAC'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="4"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry DAC+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="5"]', [m('a[tabindex="0"]', [m('span.text', 'HiFiBerry Digi / Digi+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="6"]', [m('a[tabindex="0"]', [m('span.text', 'IQaudIO Pi-DAC / Pi-DAC+'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="7"]', [m('a[tabindex="0"]', [m('span.text', 'RaspyPlay3'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li[rel="8"]', [m('a[tabindex="0"]', [m('span.text', 'RaspyPlay4'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])]), m('li.selected[rel="9"]', [m('a[tabindex="0"]', [m('span.text', 'Transducer'), m('i.glyphicon.glyphicon-ok.icon-ok.check-mark')])])])])]), + m('span.help-block', ['Enable I²S output selecting one of the available sets of modules, specific for each hardware. Once set, the output interface will appear in the ', m('a[href="/mpd/"]', 'MPD configuration select menu'), ', and modules will also auto-load from the next reboot.']) + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="orionprofile"]', 'Sound Signature (optimization profiles)'), + m('.col-sm-10', [ + m('select.selectpicker[data-style="btn-default btn-lg"][name="orionprofile"]', mithril.createInput(settings.vm.data, "orionprofile", helpers.selectpicker), [ + m('option[value="default"]', 'ArchLinux default'), + m('option[value="RuneAudio"]', 'RuneAudio'), + m('option[selected=""][value="ACX"]', 'ACX'), + m('option[value="Orion"]', 'Orion'), + m('option[value="OrionV2"]', 'OrionV2'), + m('option[value="OrionV3_berrynosmini"]', 'OrionV3 - (BerryNOS-mini)'), + m('option[value="OrionV3_iqaudio"]', 'OrionV3 - (IQaudioPi-DAC)'), + m('option[value="Um3ggh1U"]', 'Um3ggh1U') + ]), + m('span.help-block', ['These profiles include a set of performance tweaks that act on some system kernel parameters.\n It does not have anything to do with DSPs or other sound effects: the output is kept untouched (bit perfect).\n It happens that these parameters introduce an audible impact on the overall sound quality, acting on kernel latency parameters (and probably on the amount of overall \n ', m('a[href="http://www.thewelltemperedcomputer.com/KB/BitPerfectJitter.htm"][target="_blank"][title="Bit Perfect Jitter by Vincent Kars"]', 'jitter'), ').\n Sound results may vary depending on where music is listened, so choose according to your personal taste.\n (If you can"t hear any tangible differences... nevermind, just stick to the default settings.)']) + ]) + ]), + m('.form-group.form-actions', [ + m('.col-sm-offset-2.col-sm-10', [ + m('button.btn.btn-default.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.cancel('kernel'); + } + }, 'Cancel'), + m('button.btn.btn-primary.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.save('kernel'); + } + }, 'Save and apply') + ]) + ]) + ]), + m('fieldset[id="features-management"]', [ + m('legend', 'Features management'), + m('p', 'Enable/disable optional modules that best suit your needs. Disabling unusued features will free system resources and might improve the overall performance.'), + m('[id="airplayBox"]', { + className: settings.vm.data.features.airplay.enable ? 'boxed-group' : '' + }, [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="airplay"]', 'AirPlay'), + m('.col-sm-10', [ + mithril.createYesNo('enable', settings.vm.data.features.airplay, 'enable'), + m('span.help-block', 'Toggle the capability of receiving wireless streaming of audio via AirPlay protocol') + ]) + ]), + m('[id="airplayName"]', { + className: settings.vm.data.features.airplay.enable ? '' : 'hide' + }, [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="airplay-name"]', 'AirPlay name'), + m('.col-sm-10', [ + m('input.form-control.input-lg[data-parsley-id="0928"][data-trigger="change"][id="airplay_name"][name="features[airplay][name]"][placeholder="runeaudio"][type="text"][value="RuneAudio"]'), + m('ul.parsley-errors-list[id="parsley-id-0928"]'), + m('span.help-block', 'AirPlay broadcast name') + ]) + ]) + ]) + ]), + m('[id="spotifyBox"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="spotify"]', 'Spotify'), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[data-parsley-id="3701"][data-parsley-multiple="featuresspotifyenable"][id="spotify"][name="features[spotify][enable]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary.') + ]), + m('ul.parsley-errors-list[id="parsley-id-multiple-featuresspotifyenable"]'), + m('span.help-block', ['Enable Spotify client [EXPERIMENTAL]. You must have a ', m('strong', [m('a[href="https://www.spotify.com/uk/premium/"][target="_blank"]', 'Spotify PREMIUM')]), ' account.']) + ]) + ]), + m('.hide[id="spotifyAuth"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="spotify-usr"]', 'Username'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="0174"][data-trigger="change"][id="spotify_user"][name="features[spotify][user]"][placeholder="user"][type="text"][value="user"]'), + m('ul.parsley-errors-list[id="parsley-id-0174"]'), + m('span.help-block', ['Insert your Spotify ', m('i', 'username')]) + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="spotify-pasw"]', 'Password'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="0985"][id="spotify_pass"][name="features[spotify][pass]"][placeholder="pass"][type="password"][value="pass"]'), + m('ul.parsley-errors-list[id="parsley-id-0985"]'), + m('span.help-block', ['Insert your Spotify ', m('i', 'password'), ' (case sensitive)']) + ]) + ]) + ]) + ]), + m('[id="dlnaBox"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="dlna"]', 'UPnP / DLNA'), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[data-parsley-id="1837"][data-parsley-multiple="featuresdlnaenable"][id="dlna"][name="features[dlna][enable]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]), + m('ul.parsley-errors-list[id="parsley-id-multiple-featuresdlnaenable"]'), + m('span.help-block', 'Toggle the capability of receiving wireless streaming of audio via UPnP / DLNA protocol') + ]) + ]), + m('.hide[id="dlnaName"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="dlna-name"]', 'UPnP / DLNA name'), + m('.col-sm-10', [ + m('input.form-control.input-lg[data-parsley-id="8193"][data-trigger="change"][id="dlna_name"][name="features[dlna][name]"][placeholder="runeaudio"][type="text"][value="RuneAudio"]'), + m('ul.parsley-errors-list[id="parsley-id-8193"]'), + m('span.help-block', 'UPnP / DLNA broadcast name') + ]) + ]) + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="udevil"]', 'USB Automount'), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[data-parsley-id="1024"][data-parsley-multiple="featuresudevil"][name="features[udevil]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]), + m('ul.parsley-errors-list[id="parsley-id-multiple-featuresudevil"]'), + m('span.help-block', 'Toggle automount for USB drives') + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="coverart"]', 'Display album cover'), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[checked="checked"][data-parsley-id="5818"][data-parsley-multiple="featurescoverart"][name="features[coverart]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]), + m('ul.parsley-errors-list[id="parsley-id-multiple-featurescoverart"]'), + m('span.help-block', 'Toggle the display of album art on the Playback main screen') + ]) + ]), + m('[id="lastfmBox"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="lastfm"]', [m('i.fa.fa.fa-lastfm-square'), ' Last.fm']), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[data-parsley-id="6913"][data-parsley-multiple="featureslastfmenable"][id="scrobbling-lastfm"][name="features[lastfm][enable]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]), + m('ul.parsley-errors-list[id="parsley-id-multiple-featureslastfmenable"]'), + m('span.help-block', 'Send to Last.fm informations about the music you are listening to (requires a Last.fm account)') + ]) + ]), + m('.hide[id="lastfmAuth"]', [ + m('.form-group', [ + m('label.control-label.col-sm-2[for="lastfm-usr"]', 'Username'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="9931"][data-trigger="change"][id="lastfm_user"][name="features[lastfm][user]"][placeholder="user"][type="text"][value="user"]'), + m('ul.parsley-errors-list[id="parsley-id-9931"]'), + m('span.help-block', ['Insert your Last.fm ', m('i', 'username')]) + ]) + ]), + m('.form-group', [ + m('label.control-label.col-sm-2[for="lastfm-pasw"]', 'Password'), + m('.col-sm-10', [ + m('input.form-control.input-lg[autocomplete="off"][data-parsley-id="2505"][id="lastfm_pass"][name="features[lastfm][pass]"][placeholder="pass"][type="password"][value="pass"]'), + m('ul.parsley-errors-list[id="parsley-id-2505"]'), + m('span.help-block', ['Insert your Last.fm ', m('i', 'password'), ' (case sensitive)']) + ]) + ]) + ]) + ]), + m('.form-group.form-actions', [ + m('.col-sm-offset-2.col-sm-10', [ + m('button.btn.btn-default.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.cancel('features'); + } + }, 'Cancel'), + m('button.btn.btn-primary.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.save('features'); + } + }, 'Save and apply') + ]) + ]) + ]), + m('fieldset', [ + m('legend', 'Compatibility fixes'), + m('p', 'For people suffering problems with some receivers and DACs.'), + m('.form-group', [ + m('label.control-label.col-sm-2[for="cmediafix"]', 'CMedia fix'), + m('.col-sm-10', [ + m('label.switch-light.well[onclick=""]', [ + m('input[name="cmediafix[1]"][type="checkbox"][value="1"]'), + m('span', [m('span', 'OFF'), m('span', 'ON')]), + m('a.btn.btn-primary') + ]), + m('span.help-block', ['For those who have a CM6631 receiver and experiment issues (noise, crackling) between tracks with different sample rates and/or bit depth.', m('br'), ' \n A \'dirty\' fix that should avoid the problem, do NOT use if everything works normally.']) + ]) + ]), + m('.form-group.form-actions', [ + m('.col-sm-offset-2.col-sm-10', [ + m('button.btn.btn-default.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.cancel('cmediafix'); + } + }, 'Cancel'), + m('button.btn.btn-primary.btn-lg[type="button"]', { + onclick: function (e) { + settings.vm.save('cmediafix'); + } + }, 'Save and apply') + ]) + ]) + ]), + m('fieldset', [ + m('legend', 'Backup / Restore configuration'), + m('p', 'Transfer settings between multiple RuneAudio installations, saving time during new/upgrade installations.'), + m('.form-group', [ + m('label.control-label.col-sm-2', 'Backup player config'), + m('.col-sm-10', [ + m('button.btn.btn-primary.btn-lg[type="button"]', { + onclick: function (e) { + modal.vm.backup(); + } + }, 'Backup'), + m('span.help-block', 'NOTE: restore feature will come in 0.4 release.') + ]) + ]) + ]) + ]; }; \ No newline at end of file diff --git a/assets/js/runeui.sources.js b/assets/js/runeui.sources.js index e8563ca9..287c537a 100644 --- a/assets/js/runeui.sources.js +++ b/assets/js/runeui.sources.js @@ -1,41 +1,66 @@ -window.helpers = window.helpers || {}; -window.mithril = window.mithril || {}; -window.data = window.data || {}; - -window.sources = new mithril.RuneModule('/sources'); - -sources.vm.updateMDP = function () { - data.postData(sources.vm.url, { updatempd: true }); -}; -sources.vm.updateMDP = function () { - data.postData(sources.vm.url, { mountall: true }); -}; -sources.vm.add = function () { - console.log('source add'); - m.route('/sources/0'); -}; -sources.vm.edit = function (id) { - console.log('source edit'); - m.route('/sources/' + id); -}; - -// 'Sources' view -sources.view = function (ctrl) { - return [m('.container', [ - m('h1', 'Local sources'), - m('.boxed', [ - m('p', ['Your ', m('a[href="/#panel-sx"]', 'music library'), ' is composed by two main content types: ', m('strong', 'local sources'), ' and streaming sources.', m('br'), '\n This section lets you configure your local sources, telling ', m('a[href="http://www.musicpd.org/"][rel="nofollow"][target="_blank"][title="Music Player Daemon"]', 'MPD'), ' to scan the contents of ', m('strong', 'network mounts'), ' and ', m('strong', 'USB mounts'), '.']), - m('button.btn.btn-lg.btn-primary[id="updatempddb"][type="button"]', { onclick: sources.vm.updateMDP }, [m('i.fa.fa-refresh.sx'), 'Rebuild MPD Library']) - ]), - m('h2', 'Network mounts'), - m('p', 'List of configured network mounts. Click an existing entry to edit it, or add a new one.'), - m('p', [m('button.btn.btn-lg.btn-primary.btn-block[id="mountall"][type="button"]', { onclick: sources.vm.mountall }, [m('i.fa.fa-refresh.sx'), ' Remount all sources'])]), - // loop through existing mounts - m('p', [m('a.btn.btn-lg.btn-primary.btn-block', { onclick: sources.vm.add }, [m('i.fa.fa-plus.sx'), ' Add new mount'])]), - m('h2', 'USB mounts'), - m('p', ['List of mounted USB drives. To safe unmount a drive, click on it and confirm at the dialog prompt.', m('br'), '\n If a drive is connected but not shown in the list, please check if ', m('a[href="/settings/#features-management"]', 'USB automount'), ' is enabled.']), - m('.button-list[id="usb-mount-list"]', [ - m('p', [m('button.btn.btn-lg.btn-disabled.btn-block[disabled="disabled"]', 'no USB mounts present')]) - ]) - ])]; -}; \ No newline at end of file +window.helpers = window.helpers || {}; +window.mithril = window.mithril || {}; +window.data = window.data || {}; + +window.sources = new mithril.RuneModule('/sources'); + +sources.Source = function (data) { + this.id = m.prop(data.id); + this.title = m.prop(data.title); + this.path = m.prop(data.path); + this.status = m.prop(data.status); +}; + +sources.vm.updateMDP = function () { + data.postData(sources.vm.url, { updatempd: true }); +}; +sources.vm.mountAll = function () { + data.postData(sources.vm.url, { mountall: true }); +}; +sources.vm.add = function () { + m.route('/sources/0'); +}; +sources.vm.edit = function (id) { + m.route('/sources/' + id); +}; +sources.vm.unmountUSB = function (id) { + modal.unmountUSB.vm.current(id); + m.module(document.getElementById('dialog'), modal.unmountUSB); +}; + +// 'Sources' view +sources.view = function (ctrl) { + return [m('.container', [ + m('h1', 'Local sources'), + m('.boxed', [ + m('p', ['Your ', m('a[href="/#panel-sx"]', 'music library'), ' is composed by two main content types: ', m('strong', 'local sources'), ' and streaming sources.', m('br'), '\n This section lets you configure your local sources, telling ', m('a[href="http://www.musicpd.org/"][rel="nofollow"][target="_blank"][title="Music Player Daemon"]', 'MPD'), ' to scan the contents of ', m('strong', 'network mounts'), ' and ', m('strong', 'USB mounts'), '.']), + m('button.btn.btn-lg.btn-primary[id="updatempddb"][type="button"]', { onclick: sources.vm.updateMDP }, [m('i.fa.fa-refresh.sx'), 'Rebuild MPD Library']) + ]), + m('h2', 'Network mounts'), + m('p', 'List of configured network mounts. Click an existing entry to edit it, or add a new one.'), + m('p', [m('button.btn.btn-lg.btn-primary.btn-block[id="mountall"][type="button"]', { onclick: sources.vm.mountAll }, [m('i.fa.fa-refresh.sx'), ' Remount all sources'])]), + sources.vm.data.mounts.map(function (item, index) { + return m("p", [m("a.btn.btn-lg.btn-default.btn-block[href='/sources/edit/" + item.id + "']", { + onclick: function (e) { + sources.vm.edit(item.id); + } + }, + [" ", m("i.fa.sx", { className: (item.status) ? 'fa-check green' : 'fa-times red' }), item.name, m("span", "\\\\" + item.address + "\\" + item.remotedir)]) + ]); + }), + m('p', [m('a.btn.btn-lg.btn-primary.btn-block', { onclick: sources.vm.add }, [m('i.fa.fa-plus.sx'), ' Add new mount'])]), + m('h2', 'USB mounts'), + m('p', ['List of mounted USB drives. To safely unmount a drive, click on it then confirm at the dialog prompt.', m('br'), '\n If a drive is connected but not shown in the list, please check if ', m('a[href="/settings"]', { config: m.route }, 'USB automount'), ' is enabled.']), + m('.button-list[id="usb-mount-list"]', [ + sources.vm.data.usbmounts.map(function (item, index) { + // handle the No USB Mounts case: + // m('p', [m('button.btn.btn-lg.btn-disabled.btn-block[disabled="disabled"]', 'no USB mounts present')]) + return m("p", [m("a.btn.btn-lg.btn-default.btn-block[href='javascript:;']", { + onclick: function (e) { + sources.vm.unmountUSB(item.device); + } + }, [m("i.fa.fa-check.green.sx"), item.device, m("span", "(size: " + item.size + ", " + item.use + " in use)")])]); + }), + ]) + ])]; +}; From ab20b873254d7f354019eeedd65fa9df3e3fd0eb Mon Sep 17 00:00:00 2001 From: Kevin Welsh Date: Sat, 10 Jan 2015 00:59:05 -0500 Subject: [PATCH 63/80] Merge branch 'next' of https://github.com/RuneAudio/RuneUI.git Conflicts: assets/js/runeui._data.js assets/js/runeui._helpers.js assets/js/runeui._mithril.js Also, I think I had some end line change issues.. :) --- .gitignore | 8 +- Gruntfile.js | 194 +- README.md | 58 +- app/api/coverart_ctl.php | 416 +- app/api/credits_ctl.php | 72 +- app/api/debug_ctl.php | 84 +- app/api/dev_ctl.php | 188 +- app/api/login_ctl.php | 66 +- app/api/network_ctl.php | 290 +- app/api/playback_ctl.php | 106 +- app/api/sources_ctl.php | 236 +- app/api/system_ctl.php | 100 +- app/api/tun_ctl.php | 82 +- app/api_ctl.php | 6 +- app/config/_os/boot/cmdline.txt | 10 +- app/config/_os/etc/php/conf.d/opcache.ini | 32 +- app/config/_os/etc/php/php.ini | 192 +- app/config/_os/etc/profile.d/proxy.sh | 14 +- app/config_ctl.php | 66 +- app/coverart_ctl.php | 416 +- app/credits_ctl.php | 70 +- app/debug_ctl.php | 76 +- app/dev_ctl.php | 186 +- app/libs/composer.json | 8 +- app/libs/composer.lock | 532 +- app/libs/vendor/Zend/Bit/Twiddling.php | 446 +- app/libs/vendor/Zend/Exception.php | 192 +- app/libs/vendor/Zend/Io/Exception.php | 76 +- app/libs/vendor/Zend/Io/FileReader.php | 132 +- app/libs/vendor/Zend/Io/FileWriter.php | 132 +- app/libs/vendor/Zend/Io/Reader.php | 1786 ++--- app/libs/vendor/Zend/Io/StringReader.php | 172 +- app/libs/vendor/Zend/Io/StringWriter.php | 178 +- app/libs/vendor/Zend/Io/Writer.php | 1262 +-- app/libs/vendor/Zend/Media/Asf.php | 444 +- app/libs/vendor/Zend/Media/Asf/Exception.php | 80 +- app/libs/vendor/Zend/Media/Asf/Object.php | 644 +- .../Asf/Object/AdvancedContentEncryption.php | 336 +- .../Asf/Object/AdvancedMutualExclusion.php | 280 +- .../Media/Asf/Object/BandwidthSharing.php | 434 +- .../Asf/Object/BitrateMutualExclusion.php | 282 +- .../Zend/Media/Asf/Object/CodecList.php | 330 +- .../Zend/Media/Asf/Object/Compatibility.php | 240 +- .../Zend/Media/Asf/Object/Container.php | 722 +- .../Zend/Media/Asf/Object/ContentBranding.php | 406 +- .../Media/Asf/Object/ContentDescription.php | 480 +- .../Media/Asf/Object/ContentEncryption.php | 378 +- .../vendor/Zend/Media/Asf/Object/Data.php | 236 +- .../Media/Asf/Object/DigitalSignature.php | 250 +- .../Zend/Media/Asf/Object/ErrorCorrection.php | 272 +- .../Asf/Object/ExtendedContentDescription.php | 460 +- .../Asf/Object/ExtendedContentEncryption.php | 202 +- .../Asf/Object/ExtendedStreamProperties.php | 1418 ++-- .../Zend/Media/Asf/Object/FileProperties.php | 880 +-- .../Media/Asf/Object/GroupMutualExclusion.php | 324 +- .../vendor/Zend/Media/Asf/Object/Header.php | 262 +- .../Zend/Media/Asf/Object/HeaderExtension.php | 220 +- .../vendor/Zend/Media/Asf/Object/Index.php | 386 +- .../Zend/Media/Asf/Object/IndexParameters.php | 250 +- .../Zend/Media/Asf/Object/LanguageList.php | 232 +- .../vendor/Zend/Media/Asf/Object/Marker.php | 394 +- .../Media/Asf/Object/MediaObjectIndex.php | 372 +- .../Asf/Object/MediaObjectIndexParameters.php | 266 +- .../vendor/Zend/Media/Asf/Object/Metadata.php | 436 +- .../Zend/Media/Asf/Object/MetadataLibrary.php | 512 +- .../vendor/Zend/Media/Asf/Object/Padding.php | 154 +- .../Zend/Media/Asf/Object/ScriptCommand.php | 366 +- .../Zend/Media/Asf/Object/SimpleIndex.php | 300 +- .../Asf/Object/StreamBitrateProperties.php | 268 +- .../Media/Asf/Object/StreamPrioritization.php | 264 +- .../Media/Asf/Object/StreamProperties.php | 1068 +-- .../Zend/Media/Asf/Object/TimecodeIndex.php | 378 +- .../Asf/Object/TimecodeIndexParameters.php | 258 +- .../vendor/Zend/Media/Asf/Object/Unknown.php | 142 +- app/libs/vendor/Zend/Media/Exception.php | 78 +- app/libs/vendor/Zend/Media/Flac.php | 540 +- app/libs/vendor/Zend/Media/Flac/Exception.php | 80 +- .../vendor/Zend/Media/Flac/MetadataBlock.php | 346 +- .../Media/Flac/MetadataBlock/Application.php | 154 +- .../Media/Flac/MetadataBlock/Cuesheet.php | 378 +- .../Zend/Media/Flac/MetadataBlock/Padding.php | 106 +- .../Zend/Media/Flac/MetadataBlock/Picture.php | 398 +- .../Media/Flac/MetadataBlock/Seektable.php | 164 +- .../Media/Flac/MetadataBlock/Streaminfo.php | 370 +- .../Flac/MetadataBlock/VorbisComment.php | 310 +- app/libs/vendor/Zend/Media/Id3/DateFrame.php | 218 +- app/libs/vendor/Zend/Media/Id3/Encoding.php | 164 +- app/libs/vendor/Zend/Media/Id3/Exception.php | 80 +- .../vendor/Zend/Media/Id3/ExtendedHeader.php | 696 +- app/libs/vendor/Zend/Media/Id3/Frame.php | 654 +- app/libs/vendor/Zend/Media/Id3/Frame/Aenc.php | 356 +- app/libs/vendor/Zend/Media/Id3/Frame/Apic.php | 580 +- app/libs/vendor/Zend/Media/Id3/Frame/Aspi.php | 320 +- app/libs/vendor/Zend/Media/Id3/Frame/Comm.php | 310 +- app/libs/vendor/Zend/Media/Id3/Frame/Comr.php | 980 +-- app/libs/vendor/Zend/Media/Id3/Frame/Encr.php | 330 +- app/libs/vendor/Zend/Media/Id3/Frame/Equ2.php | 390 +- app/libs/vendor/Zend/Media/Id3/Frame/Equa.php | 266 +- app/libs/vendor/Zend/Media/Id3/Frame/Etco.php | 336 +- app/libs/vendor/Zend/Media/Id3/Frame/Geob.php | 528 +- app/libs/vendor/Zend/Media/Id3/Frame/Grid.php | 320 +- app/libs/vendor/Zend/Media/Id3/Frame/Ipls.php | 400 +- app/libs/vendor/Zend/Media/Id3/Frame/Link.php | 376 +- app/libs/vendor/Zend/Media/Id3/Frame/Mcdi.php | 204 +- app/libs/vendor/Zend/Media/Id3/Frame/Mllt.php | 374 +- app/libs/vendor/Zend/Media/Id3/Frame/Owne.php | 516 +- app/libs/vendor/Zend/Media/Id3/Frame/Pcnt.php | 220 +- app/libs/vendor/Zend/Media/Id3/Frame/Popm.php | 352 +- app/libs/vendor/Zend/Media/Id3/Frame/Poss.php | 258 +- app/libs/vendor/Zend/Media/Id3/Frame/Priv.php | 250 +- app/libs/vendor/Zend/Media/Id3/Frame/Rbuf.php | 380 +- app/libs/vendor/Zend/Media/Id3/Frame/Rva2.php | 426 +- app/libs/vendor/Zend/Media/Id3/Frame/Rvad.php | 476 +- app/libs/vendor/Zend/Media/Id3/Frame/Rvrb.php | 662 +- app/libs/vendor/Zend/Media/Id3/Frame/Seek.php | 190 +- app/libs/vendor/Zend/Media/Id3/Frame/Sign.php | 246 +- app/libs/vendor/Zend/Media/Id3/Frame/Sylt.php | 748 +- app/libs/vendor/Zend/Media/Id3/Frame/Sytc.php | 314 +- app/libs/vendor/Zend/Media/Id3/Frame/Talb.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tbpm.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tcmp.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tcom.php | 78 +- app/libs/vendor/Zend/Media/Id3/Frame/Tcon.php | 98 +- app/libs/vendor/Zend/Media/Id3/Frame/Tcop.php | 92 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdat.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tden.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdly.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdor.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdrc.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdrl.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tdtg.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tenc.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Text.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tflt.php | 114 +- app/libs/vendor/Zend/Media/Id3/Frame/Time.php | 210 +- app/libs/vendor/Zend/Media/Id3/Frame/Tipl.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tit1.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tit2.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tit3.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tkey.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tlan.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tlen.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tmcl.php | 88 +- app/libs/vendor/Zend/Media/Id3/Frame/Tmed.php | 248 +- app/libs/vendor/Zend/Media/Id3/Frame/Tmoo.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Toal.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tofn.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Toly.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tope.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tory.php | 152 +- app/libs/vendor/Zend/Media/Id3/Frame/Town.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpe1.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpe2.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpe3.php | 78 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpe4.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpos.php | 220 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpro.php | 96 +- app/libs/vendor/Zend/Media/Id3/Frame/Tpub.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Trck.php | 218 +- app/libs/vendor/Zend/Media/Id3/Frame/Trda.php | 90 +- app/libs/vendor/Zend/Media/Id3/Frame/Trsn.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Trso.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsiz.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Tso2.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsoa.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsoc.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsop.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsot.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsrc.php | 404 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsse.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Tsst.php | 84 +- app/libs/vendor/Zend/Media/Id3/Frame/Txxx.php | 288 +- app/libs/vendor/Zend/Media/Id3/Frame/Tyer.php | 146 +- app/libs/vendor/Zend/Media/Id3/Frame/Ufid.php | 262 +- .../vendor/Zend/Media/Id3/Frame/Unknown.php | 96 +- app/libs/vendor/Zend/Media/Id3/Frame/User.php | 86 +- app/libs/vendor/Zend/Media/Id3/Frame/Uslt.php | 308 +- app/libs/vendor/Zend/Media/Id3/Frame/Wcom.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Wcop.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Woaf.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Woar.php | 82 +- app/libs/vendor/Zend/Media/Id3/Frame/Woas.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Wors.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Wpay.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Wpub.php | 80 +- app/libs/vendor/Zend/Media/Id3/Frame/Wxxx.php | 360 +- app/libs/vendor/Zend/Media/Id3/Header.php | 356 +- app/libs/vendor/Zend/Media/Id3/Language.php | 112 +- .../Zend/Media/Id3/LanguageTextFrame.php | 444 +- app/libs/vendor/Zend/Media/Id3/LinkFrame.php | 184 +- .../vendor/Zend/Media/Id3/NumberFrame.php | 186 +- app/libs/vendor/Zend/Media/Id3/Object.php | 722 +- app/libs/vendor/Zend/Media/Id3/TextFrame.php | 390 +- app/libs/vendor/Zend/Media/Id3/Timing.php | 120 +- app/libs/vendor/Zend/Media/Id3v1.php | 838 +- app/libs/vendor/Zend/Media/Id3v2.php | 1432 ++-- app/libs/vendor/Zend/Media/Iso14496.php | 838 +- app/libs/vendor/Zend/Media/Iso14496/Box.php | 1334 ++-- .../vendor/Zend/Media/Iso14496/Box/Bxml.php | 236 +- .../vendor/Zend/Media/Iso14496/Box/Cdsc.php | 238 +- .../vendor/Zend/Media/Iso14496/Box/Chpl.php | 218 +- .../vendor/Zend/Media/Iso14496/Box/Co64.php | 266 +- .../vendor/Zend/Media/Iso14496/Box/Cprt.php | 300 +- .../vendor/Zend/Media/Iso14496/Box/Ctts.php | 278 +- .../vendor/Zend/Media/Iso14496/Box/Dinf.php | 144 +- .../vendor/Zend/Media/Iso14496/Box/Dref.php | 200 +- .../vendor/Zend/Media/Iso14496/Box/Edts.php | 152 +- .../vendor/Zend/Media/Iso14496/Box/Elst.php | 338 +- .../vendor/Zend/Media/Iso14496/Box/Free.php | 178 +- .../vendor/Zend/Media/Iso14496/Box/Frma.php | 232 +- .../vendor/Zend/Media/Iso14496/Box/Ftyp.php | 420 +- .../vendor/Zend/Media/Iso14496/Box/Hdlr.php | 348 +- .../vendor/Zend/Media/Iso14496/Box/Hint.php | 240 +- .../vendor/Zend/Media/Iso14496/Box/Hmhd.php | 374 +- .../vendor/Zend/Media/Iso14496/Box/Id32.php | 322 +- .../vendor/Zend/Media/Iso14496/Box/Iinf.php | 200 +- .../vendor/Zend/Media/Iso14496/Box/Iloc.php | 490 +- .../vendor/Zend/Media/Iso14496/Box/Ilst.php | 652 +- .../vendor/Zend/Media/Iso14496/Box/Imif.php | 182 +- .../vendor/Zend/Media/Iso14496/Box/Infe.php | 466 +- .../vendor/Zend/Media/Iso14496/Box/Ipro.php | 190 +- .../vendor/Zend/Media/Iso14496/Box/Mdhd.php | 486 +- .../vendor/Zend/Media/Iso14496/Box/Mdia.php | 142 +- .../vendor/Zend/Media/Iso14496/Box/Mehd.php | 256 +- .../vendor/Zend/Media/Iso14496/Box/Meta.php | 182 +- .../vendor/Zend/Media/Iso14496/Box/Mfhd.php | 228 +- .../vendor/Zend/Media/Iso14496/Box/Mfra.php | 172 +- .../vendor/Zend/Media/Iso14496/Box/Mfro.php | 246 +- .../vendor/Zend/Media/Iso14496/Box/Minf.php | 142 +- .../vendor/Zend/Media/Iso14496/Box/Moof.php | 162 +- .../vendor/Zend/Media/Iso14496/Box/Moov.php | 144 +- .../vendor/Zend/Media/Iso14496/Box/Mvex.php | 148 +- .../vendor/Zend/Media/Iso14496/Box/Mvhd.php | 686 +- .../vendor/Zend/Media/Iso14496/Box/Ndrm.php | 218 +- .../vendor/Zend/Media/Iso14496/Box/Pdin.php | 286 +- .../vendor/Zend/Media/Iso14496/Box/Pitm.php | 232 +- .../vendor/Zend/Media/Iso14496/Box/Pssh.php | 316 +- .../vendor/Zend/Media/Iso14496/Box/Sbgp.php | 394 +- .../vendor/Zend/Media/Iso14496/Box/Schi.php | 148 +- .../vendor/Zend/Media/Iso14496/Box/Schm.php | 354 +- .../vendor/Zend/Media/Iso14496/Box/Sdtp.php | 374 +- .../vendor/Zend/Media/Iso14496/Box/Sinf.php | 174 +- .../vendor/Zend/Media/Iso14496/Box/Skip.php | 146 +- .../vendor/Zend/Media/Iso14496/Box/Smhd.php | 246 +- .../vendor/Zend/Media/Iso14496/Box/Stbl.php | 184 +- .../vendor/Zend/Media/Iso14496/Box/Stco.php | 268 +- .../vendor/Zend/Media/Iso14496/Box/Stdp.php | 244 +- .../vendor/Zend/Media/Iso14496/Box/Stsc.php | 322 +- .../vendor/Zend/Media/Iso14496/Box/Stsd.php | 182 +- .../vendor/Zend/Media/Iso14496/Box/Stsh.php | 316 +- .../vendor/Zend/Media/Iso14496/Box/Stss.php | 246 +- .../vendor/Zend/Media/Iso14496/Box/Stsz.php | 328 +- .../vendor/Zend/Media/Iso14496/Box/Stts.php | 296 +- .../vendor/Zend/Media/Iso14496/Box/Tenc.php | 360 +- .../vendor/Zend/Media/Iso14496/Box/Tfra.php | 668 +- .../vendor/Zend/Media/Iso14496/Box/Tkhd.php | 864 +-- .../vendor/Zend/Media/Iso14496/Box/Traf.php | 154 +- .../vendor/Zend/Media/Iso14496/Box/Trak.php | 166 +- .../vendor/Zend/Media/Iso14496/Box/Tref.php | 162 +- .../vendor/Zend/Media/Iso14496/Box/Trex.php | 428 +- .../vendor/Zend/Media/Iso14496/Box/Udta.php | 150 +- .../vendor/Zend/Media/Iso14496/Box/Url.php | 244 +- .../vendor/Zend/Media/Iso14496/Box/Urn.php | 296 +- .../vendor/Zend/Media/Iso14496/Box/Vmhd.php | 306 +- .../vendor/Zend/Media/Iso14496/Box/Xml.php | 246 +- .../vendor/Zend/Media/Iso14496/Exception.php | 104 +- .../vendor/Zend/Media/Iso14496/FullBox.php | 300 +- app/libs/vendor/Zend/Media/Mpeg/Abs.php | 912 +-- app/libs/vendor/Zend/Media/Mpeg/Abs/Frame.php | 1148 +-- .../vendor/Zend/Media/Mpeg/Abs/LameHeader.php | 1054 +-- .../vendor/Zend/Media/Mpeg/Abs/Object.php | 300 +- .../vendor/Zend/Media/Mpeg/Abs/VbriHeader.php | 354 +- .../vendor/Zend/Media/Mpeg/Abs/XingHeader.php | 274 +- app/libs/vendor/Zend/Media/Mpeg/Exception.php | 80 +- app/libs/vendor/Zend/Media/Mpeg/Object.php | 534 +- app/libs/vendor/Zend/Media/Mpeg/Ps.php | 306 +- app/libs/vendor/Zend/Media/Ogg/Exception.php | 78 +- app/libs/vendor/Zend/Media/Ogg/Page.php | 470 +- app/libs/vendor/Zend/Media/Ogg/Reader.php | 382 +- app/libs/vendor/Zend/Media/Riff.php | 150 +- app/libs/vendor/Zend/Media/Riff/Chunk.php | 250 +- .../vendor/Zend/Media/Riff/Chunk/Cgrp.php | 94 +- .../vendor/Zend/Media/Riff/Chunk/Cset.php | 344 +- .../vendor/Zend/Media/Riff/Chunk/Ctoc.php | 94 +- .../vendor/Zend/Media/Riff/Chunk/Iarl.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Iart.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Icms.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Icmt.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Icop.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Icrd.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Icrp.php | 56 +- app/libs/vendor/Zend/Media/Riff/Chunk/Id3.php | 124 +- .../vendor/Zend/Media/Riff/Chunk/Idim.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Idpi.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Ieng.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Ignr.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Ikey.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Ilgt.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Imed.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Inam.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Iplt.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Iprd.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Isbj.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Isft.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Ishp.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Isrc.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Isrf.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/Itch.php | 56 +- .../vendor/Zend/Media/Riff/Chunk/Junk.php | 58 +- .../vendor/Zend/Media/Riff/Chunk/List.php | 56 +- .../vendor/Zend/Media/Riff/ContainerChunk.php | 284 +- app/libs/vendor/Zend/Media/Riff/Exception.php | 56 +- .../vendor/Zend/Media/Riff/StringChunk.php | 134 +- app/libs/vendor/Zend/Media/Vorbis.php | 282 +- .../vendor/Zend/Media/Vorbis/Exception.php | 78 +- app/libs/vendor/Zend/Media/Vorbis/Header.php | 230 +- .../Zend/Media/Vorbis/Header/Comment.php | 398 +- .../Media/Vorbis/Header/Identification.php | 340 +- .../vendor/Zend/Media/Vorbis/Header/Setup.php | 108 +- app/libs/vendor/Zend/Mime/Magic.php | 392 +- app/libs/vendor/autoload.php | 14 +- app/libs/vendor/composer/ClassLoader.php | 756 +- .../vendor/composer/autoload_classmap.php | 18 +- app/libs/vendor/composer/autoload_files.php | 20 +- .../vendor/composer/autoload_namespaces.php | 24 +- app/libs/vendor/composer/autoload_psr4.php | 22 +- app/libs/vendor/composer/autoload_real.php | 116 +- app/libs/vendor/composer/installed.json | 506 +- .../vendor/evenement/evenement/.gitignore | 4 +- .../vendor/evenement/evenement/.travis.yml | 20 +- .../vendor/evenement/evenement/CHANGELOG.md | 16 +- app/libs/vendor/evenement/evenement/README.md | 166 +- .../vendor/evenement/evenement/composer.json | 50 +- .../evenement/evenement/phpunit.xml.dist | 50 +- .../evenement/src/Evenement/EventEmitter.php | 34 +- .../src/Evenement/EventEmitterInterface.php | 44 +- .../src/Evenement/EventEmitterTrait.php | 134 +- .../Evenement/Tests/EventEmitterTest.php | 470 +- .../tests/Evenement/Tests/Listener.php | 46 +- .../evenement/evenement/tests/bootstrap.php | 26 +- app/libs/vendor/getid3/audioinfo.class.php | 632 +- .../vendor/getid3/extension.cache.dbm.php | 416 +- .../vendor/getid3/extension.cache.mysql.php | 342 +- .../vendor/getid3/extension.cache.sqlite3.php | 528 +- app/libs/vendor/getid3/getid3.lib.php | 2684 +++---- app/libs/vendor/getid3/getid3.php | 3552 ++++----- .../vendor/getid3/module.archive.gzip.php | 560 +- app/libs/vendor/getid3/module.archive.rar.php | 100 +- .../vendor/getid3/module.archive.szip.php | 192 +- app/libs/vendor/getid3/module.archive.tar.php | 352 +- app/libs/vendor/getid3/module.archive.zip.php | 1024 +-- .../vendor/getid3/module.audio-video.asf.php | 4038 +++++----- .../vendor/getid3/module.audio-video.bink.php | 142 +- .../vendor/getid3/module.audio-video.flv.php | 1458 ++-- .../getid3/module.audio-video.matroska.php | 3530 ++++----- .../vendor/getid3/module.audio-video.mpeg.php | 592 +- .../vendor/getid3/module.audio-video.nsv.php | 446 +- .../getid3/module.audio-video.quicktime.php | 4442 +++++------ .../vendor/getid3/module.audio-video.real.php | 1054 +-- .../vendor/getid3/module.audio-video.riff.php | 4870 ++++++------ .../vendor/getid3/module.audio-video.swf.php | 278 +- .../vendor/getid3/module.audio-video.ts.php | 156 +- app/libs/vendor/getid3/module.audio.aa.php | 116 +- app/libs/vendor/getid3/module.audio.aac.php | 1024 +-- app/libs/vendor/getid3/module.audio.ac3.php | 946 +-- app/libs/vendor/getid3/module.audio.au.php | 324 +- app/libs/vendor/getid3/module.audio.avr.php | 248 +- app/libs/vendor/getid3/module.audio.bonk.php | 454 +- app/libs/vendor/getid3/module.audio.dss.php | 154 +- app/libs/vendor/getid3/module.audio.dts.php | 580 +- app/libs/vendor/getid3/module.audio.flac.php | 884 +-- app/libs/vendor/getid3/module.audio.la.php | 450 +- app/libs/vendor/getid3/module.audio.lpac.php | 254 +- app/libs/vendor/getid3/module.audio.midi.php | 1058 +-- app/libs/vendor/getid3/module.audio.mod.php | 196 +- .../vendor/getid3/module.audio.monkey.php | 406 +- app/libs/vendor/getid3/module.audio.mp3.php | 4018 +++++----- app/libs/vendor/getid3/module.audio.mpc.php | 1012 +-- app/libs/vendor/getid3/module.audio.ogg.php | 1342 ++-- .../vendor/getid3/module.audio.optimfrog.php | 852 +- app/libs/vendor/getid3/module.audio.rkau.php | 184 +- .../vendor/getid3/module.audio.shorten.php | 362 +- app/libs/vendor/getid3/module.audio.tta.php | 212 +- app/libs/vendor/getid3/module.audio.voc.php | 408 +- app/libs/vendor/getid3/module.audio.vqf.php | 318 +- .../vendor/getid3/module.audio.wavpack.php | 794 +- app/libs/vendor/getid3/module.graphic.bmp.php | 1374 ++-- .../vendor/getid3/module.graphic.efax.php | 100 +- app/libs/vendor/getid3/module.graphic.gif.php | 362 +- app/libs/vendor/getid3/module.graphic.jpg.php | 688 +- app/libs/vendor/getid3/module.graphic.pcd.php | 264 +- app/libs/vendor/getid3/module.graphic.png.php | 1034 +-- app/libs/vendor/getid3/module.graphic.svg.php | 202 +- .../vendor/getid3/module.graphic.tiff.php | 448 +- app/libs/vendor/getid3/module.misc.cue.php | 622 +- app/libs/vendor/getid3/module.misc.exe.php | 116 +- app/libs/vendor/getid3/module.misc.iso.php | 774 +- .../vendor/getid3/module.misc.msoffice.php | 74 +- app/libs/vendor/getid3/module.misc.par2.php | 60 +- app/libs/vendor/getid3/module.misc.pdf.php | 60 +- app/libs/vendor/getid3/module.tag.apetag.php | 740 +- app/libs/vendor/getid3/module.tag.id3v1.php | 718 +- app/libs/vendor/getid3/module.tag.id3v2.php | 6828 ++++++++--------- app/libs/vendor/getid3/module.tag.lyrics3.php | 588 +- app/libs/vendor/getid3/module.tag.xmp.php | 1534 ++-- app/libs/vendor/getid3/write.apetag.php | 446 +- app/libs/vendor/getid3/write.id3v1.php | 272 +- app/libs/vendor/getid3/write.id3v2.php | 4098 +++++----- app/libs/vendor/getid3/write.lyrics3.php | 142 +- app/libs/vendor/getid3/write.metaflac.php | 322 +- app/libs/vendor/getid3/write.php | 1226 +-- app/libs/vendor/getid3/write.real.php | 546 +- .../vendor/getid3/write.vorbiscomment.php | 238 +- .../Guzzle/Parser/Cookie/CookieParser.php | 172 +- .../Parser/Cookie/CookieParserInterface.php | 66 +- .../Parser/Message/AbstractMessageParser.php | 116 +- .../Guzzle/Parser/Message/MessageParser.php | 220 +- .../Parser/Message/MessageParserInterface.php | 54 +- .../Parser/Message/PeclHttpMessageParser.php | 96 +- .../parser/Guzzle/Parser/ParserRegistry.php | 150 +- .../Parser/UriTemplate/PeclUriTemplate.php | 52 +- .../Guzzle/Parser/UriTemplate/UriTemplate.php | 508 +- .../UriTemplate/UriTemplateInterface.php | 42 +- .../parser/Guzzle/Parser/Url/UrlParser.php | 96 +- .../Guzzle/Parser/Url/UrlParserInterface.php | 38 +- .../guzzle/parser/Guzzle/Parser/composer.json | 38 +- app/libs/vendor/league/plates/.gitignore | 2 +- app/libs/vendor/league/plates/.travis.yml | 30 +- app/libs/vendor/league/plates/CONTRIBUTING.md | 42 +- app/libs/vendor/league/plates/README.md | 108 +- app/libs/vendor/league/plates/composer.json | 58 +- app/libs/vendor/league/plates/phpunit.xml | 30 +- app/libs/vendor/league/plates/src/Engine.php | 472 +- .../league/plates/src/Extension/Asset.php | 100 +- .../league/plates/src/Extension/Batch.php | 62 +- .../league/plates/src/Extension/Escape.php | 52 +- .../src/Extension/ExtensionInterface.php | 16 +- .../league/plates/src/Extension/URI.php | 152 +- .../vendor/league/plates/src/Template.php | 174 +- .../plates/tests/League/Plates/EngineTest.php | 460 +- .../League/Plates/Extension/AssetTest.php | 90 +- .../League/Plates/Extension/BatchTest.php | 86 +- .../League/Plates/Extension/EscapeTest.php | 70 +- .../tests/League/Plates/Extension/URITest.php | 142 +- .../tests/League/Plates/TemplateTest.php | 162 +- app/libs/vendor/react/promise/.gitignore | 8 +- app/libs/vendor/react/promise/.travis.yml | 20 +- app/libs/vendor/react/promise/CHANGELOG.md | 86 +- app/libs/vendor/react/promise/README.md | 1148 +-- app/libs/vendor/react/promise/composer.json | 44 +- .../vendor/react/promise/phpunit.xml.dist | 50 +- .../promise/src/React/Promise/Deferred.php | 90 +- .../src/React/Promise/FulfilledPromise.php | 64 +- .../promise/src/React/Promise/LazyPromise.php | 54 +- .../promise/src/React/Promise/Promise.php | 208 +- .../src/React/Promise/PromiseInterface.php | 16 +- .../src/React/Promise/PromisorInterface.php | 16 +- .../src/React/Promise/RejectedPromise.php | 60 +- .../promise/src/React/Promise/functions.php | 328 +- .../tests/React/Promise/DeferredTest.php | 40 +- .../React/Promise/FulfilledPromiseTest.php | 88 +- .../tests/React/Promise/FunctionAllTest.php | 194 +- .../tests/React/Promise/FunctionAnyTest.php | 232 +- .../tests/React/Promise/FunctionMapTest.php | 250 +- .../tests/React/Promise/FunctionRaceTest.php | 244 +- .../React/Promise/FunctionReduceTest.php | 580 +- .../React/Promise/FunctionRejectTest.php | 128 +- .../React/Promise/FunctionResolveTest.php | 188 +- .../tests/React/Promise/FunctionSomeTest.php | 252 +- .../tests/React/Promise/LazyPromiseTest.php | 208 +- .../tests/React/Promise/PromiseTest.php | 94 +- .../Promise/PromiseTest/FullTestTrait.php | 26 +- .../Promise/PromiseTest/ProgressTestTrait.php | 592 +- .../PromiseTest/PromiseFulfilledTestTrait.php | 274 +- .../PromiseTest/PromiseRejectedTestTrait.php | 284 +- .../Promise/PromiseTest/PromiseTestTrait.php | 48 +- .../Promise/PromiseTest/RejectTestTrait.php | 202 +- .../Promise/PromiseTest/ResolveTestTrait.php | 204 +- .../React/Promise/RejectedPromiseTest.php | 88 +- .../tests/React/Promise/Stub/CallableStub.php | 20 +- .../promise/tests/React/Promise/TestCase.php | 82 +- .../vendor/react/promise/tests/bootstrap.php | 8 +- app/libs/vendor/react/react/.gitignore | 4 +- app/libs/vendor/react/react/.travis.yml | 28 +- app/libs/vendor/react/react/CHANGELOG.md | 224 +- app/libs/vendor/react/react/README.md | 208 +- app/libs/vendor/react/react/UPGRADE-0.3.md | 66 +- .../vendor/react/react/benchmark/bench.php | 94 +- .../vendor/react/react/benchmark/timers.php | 64 +- app/libs/vendor/react/react/composer.json | 88 +- app/libs/vendor/react/react/composer.lock | 1148 +-- .../react/react/examples/child-child.php | 20 +- .../react/react/examples/child-process.php | 50 +- .../react/react/examples/dns-resolver.php | 46 +- .../react/react/examples/echo-server.php | 36 +- .../react/react/examples/http-client.php | 80 +- .../vendor/react/react/examples/next-tick.php | 116 +- .../react/examples/parallel-download.php | 92 +- .../react/examples/pump-shitload-of-data.php | 46 +- .../react/react/examples/scalability.php | 42 +- .../vendor/react/react/examples/tcp-chat.php | 70 +- .../react/react/examples/test-close-conn.php | 44 +- .../react/react/examples/test-memory-http.php | 56 +- .../react/react/examples/test-memory.php | 52 +- app/libs/vendor/react/react/phpunit.xml.dist | 50 +- .../vendor/react/react/scripts/do-split.sh | 44 +- .../react/react/scripts/git-subsplit.sh | 464 +- .../vendor/react/react/scripts/travis-init.sh | 72 +- .../react/react/src/Cache/ArrayCache.php | 58 +- .../react/react/src/Cache/CacheInterface.php | 26 +- .../vendor/react/react/src/Cache/README.md | 172 +- .../react/react/src/Cache/composer.json | 36 +- .../react/react/src/ChildProcess/Process.php | 856 +-- .../react/react/src/ChildProcess/README.md | 186 +- .../react/src/ChildProcess/composer.json | 40 +- .../react/src/Dns/BadServerException.php | 14 +- .../react/react/src/Dns/Config/Config.php | 16 +- .../src/Dns/Config/FilesystemFactory.php | 148 +- .../react/react/src/Dns/Model/HeaderBag.php | 112 +- .../react/react/src/Dns/Model/Message.php | 94 +- .../react/react/src/Dns/Model/Record.php | 42 +- .../react/src/Dns/Protocol/BinaryDumper.php | 124 +- .../react/react/src/Dns/Protocol/Parser.php | 456 +- .../react/src/Dns/Query/CachedExecutor.php | 132 +- .../react/react/src/Dns/Query/Executor.php | 214 +- .../react/src/Dns/Query/ExecutorInterface.php | 16 +- .../react/react/src/Dns/Query/Query.php | 38 +- .../react/react/src/Dns/Query/RecordBag.php | 54 +- .../react/react/src/Dns/Query/RecordCache.php | 164 +- .../react/src/Dns/Query/RetryExecutor.php | 100 +- .../react/src/Dns/Query/TimeoutException.php | 14 +- app/libs/vendor/react/react/src/Dns/README.md | 110 +- .../react/src/Dns/RecordNotFoundException.php | 14 +- .../react/react/src/Dns/Resolver/Factory.php | 120 +- .../react/react/src/Dns/Resolver/Resolver.php | 196 +- .../vendor/react/react/src/Dns/composer.json | 40 +- .../react/react/src/Dns/doc/rfc1034.txt | 6154 +++++++-------- .../react/react/src/Dns/doc/rfc1035.txt | 6154 +++++++-------- .../react/src/EventLoop/ExtEventLoop.php | 652 +- .../react/react/src/EventLoop/Factory.php | 42 +- .../react/react/src/EventLoop/LibEvLoop.php | 436 +- .../react/src/EventLoop/LibEventLoop.php | 686 +- .../react/src/EventLoop/LoopInterface.php | 242 +- .../react/react/src/EventLoop/README.md | 132 +- .../react/src/EventLoop/StreamSelectLoop.php | 524 +- .../src/EventLoop/Tick/FutureTickQueue.php | 118 +- .../src/EventLoop/Tick/NextTickQueue.php | 114 +- .../react/react/src/EventLoop/Timer/Timer.php | 138 +- .../src/EventLoop/Timer/TimerInterface.php | 30 +- .../react/src/EventLoop/Timer/Timers.php | 200 +- .../react/react/src/EventLoop/composer.json | 44 +- .../vendor/react/react/src/Http/README.md | 60 +- .../vendor/react/react/src/Http/Request.php | 178 +- .../react/src/Http/RequestHeaderParser.php | 114 +- .../vendor/react/react/src/Http/Response.php | 276 +- .../react/react/src/Http/ResponseCodes.php | 144 +- .../vendor/react/react/src/Http/Server.php | 126 +- .../react/react/src/Http/ServerInterface.php | 18 +- .../vendor/react/react/src/Http/composer.json | 38 +- .../react/react/src/HttpClient/Client.php | 66 +- .../react/react/src/HttpClient/Factory.php | 38 +- .../react/react/src/HttpClient/README.md | 112 +- .../react/react/src/HttpClient/Request.php | 494 +- .../react/src/HttpClient/RequestData.php | 162 +- .../react/react/src/HttpClient/Response.php | 252 +- .../react/react/src/HttpClient/composer.json | 40 +- .../react/react/src/Socket/Connection.php | 84 +- .../react/src/Socket/ConnectionException.php | 14 +- .../react/src/Socket/ConnectionInterface.php | 24 +- .../vendor/react/react/src/Socket/README.md | 106 +- .../vendor/react/react/src/Socket/Server.php | 142 +- .../react/src/Socket/ServerInterface.php | 26 +- .../react/react/src/Socket/composer.json | 40 +- .../src/SocketClient/ConnectionException.php | 14 +- .../react/src/SocketClient/Connector.php | 204 +- .../src/SocketClient/ConnectorInterface.php | 16 +- .../react/react/src/SocketClient/README.md | 124 +- .../src/SocketClient/SecureConnector.php | 60 +- .../src/SocketClient/StreamEncryption.php | 190 +- .../react/src/SocketClient/composer.json | 40 +- .../vendor/react/react/src/Stream/Buffer.php | 270 +- .../react/react/src/Stream/BufferedSink.php | 118 +- .../react/src/Stream/CompositeStream.php | 168 +- .../vendor/react/react/src/Stream/README.md | 134 +- .../react/react/src/Stream/ReadableStream.php | 84 +- .../src/Stream/ReadableStreamInterface.php | 40 +- .../vendor/react/react/src/Stream/Stream.php | 264 +- .../react/react/src/Stream/ThroughStream.php | 66 +- .../vendor/react/react/src/Stream/Util.php | 90 +- .../react/react/src/Stream/WritableStream.php | 80 +- .../src/Stream/WritableStreamInterface.php | 38 +- .../react/react/src/Stream/composer.json | 44 +- .../react/tests/Cache/ArrayCacheTest.php | 122 +- .../ChildProcess/AbstractProcessTest.php | 644 +- .../ChildProcess/LibEvLoopProcessTest.php | 34 +- .../ChildProcess/LibEventLoopProcessTest.php | 34 +- .../StreamSelectLoopProcessTest.php | 26 +- .../Dns/Config/FilesystemFactoryTest.php | 134 +- .../tests/Dns/Protocol/BinaryDumperTest.php | 94 +- .../react/tests/Dns/Protocol/ParserTest.php | 492 +- .../tests/Dns/Query/CachedExecutorTest.php | 228 +- .../react/tests/Dns/Query/ExecutorTest.php | 600 +- .../react/tests/Dns/Query/RecordBagTest.php | 126 +- .../react/tests/Dns/Query/RecordCacheTest.php | 244 +- .../tests/Dns/Query/RetryExecutorTest.php | 368 +- .../react/tests/Dns/Resolver/FactoryTest.php | 154 +- .../tests/Dns/Resolver/ResolveAliasesTest.php | 198 +- .../react/tests/Dns/Resolver/ResolverTest.php | 318 +- .../tests/EventLoop/AbstractLoopTest.php | 994 +-- .../tests/EventLoop/ExtEventLoopTest.php | 118 +- .../react/tests/EventLoop/LibEvLoopTest.php | 44 +- .../tests/EventLoop/LibEventLoopTest.php | 116 +- .../tests/EventLoop/StreamSelectLoopTest.php | 60 +- .../EventLoop/Timer/AbstractTimerTest.php | 196 +- .../EventLoop/Timer/ExtEventTimerTest.php | 34 +- .../tests/EventLoop/Timer/LibEvTimerTest.php | 34 +- .../EventLoop/Timer/LibEventTimerTest.php | 34 +- .../EventLoop/Timer/StreamSelectTimerTest.php | 26 +- .../tests/Http/RequestHeaderParserTest.php | 274 +- .../react/react/tests/Http/RequestTest.php | 54 +- .../react/react/tests/Http/ResponseTest.php | 412 +- .../react/react/tests/Http/ServerTest.php | 162 +- .../react/tests/HttpClient/RequestTest.php | 814 +- .../react/tests/HttpClient/ResponseTest.php | 156 +- .../react/tests/Socket/ConnectionTest.php | 154 +- .../react/react/tests/Socket/ServerTest.php | 386 +- .../react/tests/Socket/Stub/CallableStub.php | 20 +- .../tests/Socket/Stub/ConnectionStub.php | 126 +- .../react/tests/Socket/Stub/ServerStub.php | 44 +- .../react/react/tests/Socket/TestCase.php | 82 +- .../tests/SocketClient/ConnectorTest.php | 204 +- .../react/react/tests/Stream/BufferTest.php | 470 +- .../react/tests/Stream/BufferedSinkTest.php | 390 +- .../tests/Stream/CompositeStreamTest.php | 312 +- .../react/tests/Stream/ReadableStreamTest.php | 98 +- .../react/react/tests/Stream/StreamTest.php | 274 +- .../tests/Stream/Stub/ReadableStreamStub.php | 122 +- .../react/tests/Stream/ThroughStreamTest.php | 286 +- .../react/react/tests/Stream/UtilTest.php | 316 +- .../react/tests/Stream/WritableStreamTest.php | 144 +- .../vendor/react/react/tests/bootstrap.php | 10 +- .../vendor/ziegler/iwlist-parser.class.php | 136 +- app/login_ctl.php | 66 +- app/mpd_ctl.php | 200 +- app/network_ctl.php | 252 +- app/playback_ctl.php | 106 +- app/settings_ctl.php | 382 +- app/sources_ctl.php | 168 +- app/templates/config.php | 14 +- app/templates/credits.php | 164 +- app/templates/debug.php | 22 +- app/templates/default_lo.php | 26 +- app/templates/dev.php | 376 +- app/templates/error.php | 34 +- app/templates/footer.php | 140 +- app/templates/header.php | 210 +- app/templates/login.php | 44 +- app/templates/mpd.php | 364 +- app/templates/mpd_manual.php | 82 +- app/templates/network.php | 32 +- app/templates/network_edit.php | 264 +- app/templates/network_edit_manual.php | 70 +- app/templates/network_wlan.php | 246 +- app/templates/settings.php | 772 +- app/templates/sources.php | 108 +- app/templates/sources_edit.php | 292 +- app/tun_ctl.php | 82 +- assets/img/browserconfig.xml | 24 +- assets/js/runeui._data.js | 94 +- assets/js/runeui._helpers.js | 186 +- assets/js/runeui._init.js | 502 +- assets/js/runeui._mithril.js | 344 +- assets/js/runeui._modal.js | 142 +- assets/js/runeui.audio.js | 194 +- assets/js/runeui.debug.js | 6 +- assets/js/runeui.dev.js | 16 +- assets/js/runeui.error.js | 6 +- assets/js/runeui.js | 5564 +++++++------- assets/js/runeui.mpd.js | 294 +- assets/js/runeui.navigation.js | 118 +- assets/js/runeui.network.js | 14 +- assets/js/runeui.playback_controls.js | 174 +- assets/js/runeui.settings.js | 668 +- assets/js/runeui.sources.js | 132 +- assets/js/vendor/Sortable.js | 1142 +-- assets/js/vendor/ZeroClipboard.min.js | 18 +- assets/js/vendor/bootstrap-contextmenu.js | 414 +- assets/js/vendor/bootstrap-select.min.js | 14 +- assets/js/vendor/bootstrap.min.js | 12 +- assets/js/vendor/fastclick.js | 1544 ++-- assets/js/vendor/i18n/_messages.en.js | 92 +- assets/js/vendor/i18n/messages.ca.js | 78 +- assets/js/vendor/i18n/messages.cs.js | 74 +- assets/js/vendor/i18n/messages.cy.js | 76 +- assets/js/vendor/i18n/messages.de.js | 74 +- assets/js/vendor/i18n/messages.es.js | 72 +- assets/js/vendor/i18n/messages.fa.js | 78 +- assets/js/vendor/i18n/messages.fi.js | 80 +- assets/js/vendor/i18n/messages.fr.js | 80 +- assets/js/vendor/i18n/messages.id.js | 80 +- assets/js/vendor/i18n/messages.is.js | 64 +- assets/js/vendor/i18n/messages.it.js | 78 +- assets/js/vendor/i18n/messages.lt.js | 80 +- assets/js/vendor/i18n/messages.nl.js | 74 +- assets/js/vendor/i18n/messages.no.js | 64 +- assets/js/vendor/i18n/messages.pl.js | 80 +- assets/js/vendor/i18n/messages.pt_br.js | 62 +- assets/js/vendor/i18n/messages.ru.js | 70 +- assets/js/vendor/i18n/messages.vn.js | 72 +- assets/js/vendor/inline-worker.min.js | 2 +- assets/js/vendor/jquery-1.11.0.min.js | 8 +- assets/js/vendor/jquery-2.1.0.min.js | 8 +- assets/js/vendor/jquery.countdown.min.js | 10 +- assets/js/vendor/jquery.knob.js | 1668 ++-- assets/js/vendor/jquery.plugin.min.js | 6 +- assets/js/vendor/jquery.scrollTo.min.js | 12 +- assets/js/vendor/mithril.js | 1978 ++--- assets/js/vendor/mithril.min.js | 14 +- .../modernizr-2.6.2-respond-1.1.0.min.js | 20 +- assets/js/vendor/openwebapp.js | 134 +- assets/js/vendor/parsley.min.js | 16 +- assets/js/vendor/pnotify.custom.min.js | 96 +- assets/js/vendor/pushstream.js | 2144 +++--- assets/less/bootstrap/.csscomb.json | 594 +- command/cachectl.php | 124 +- command/index.php | 238 +- command/opcache.php | 1408 ++-- command/orion_optimize.sh | 588 +- command/session.php | 18 +- command/ui_notify.php | 178 +- db/index.php | 648 +- db/phpinfo.php | 14 +- index.php | 304 +- package.json | 82 +- 734 files changed, 117387 insertions(+), 117387 deletions(-) diff --git a/.gitignore b/.gitignore index ee4c38df..0758dd7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ -test/ -sync.ffs_db -node_modules -_Test/ +test/ +sync.ffs_db +node_modules +_Test/ app/api/test.php /.project \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 0b1bc308..25f939a3 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -1,97 +1,97 @@ -'use strict'; -module.exports = function(grunt) { - - grunt.initConfig({ - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'Gruntfile.js', - 'assets/js/*.js', - '!assets/js/runeui.min.js', - '!assets/js/vendor/*.js' - ] - }, - less: { - dist: { - options: { - compile: true, - compress: true - }, - files: { - 'assets/css/runeui.css': [ - 'assets/less/runeui.less' - ] - } - } - }, - uglify: { - dist: { - files: { - 'assets/js/runeui.min.js': [ - 'assets/js/runeui.js' - ] - } - } - }, - watch: { - less: { - files: [ - 'assets/less/*.less', - 'assets/less/bootstrap/*.less', - 'assets/less/bootstrap-select/*.less', - 'assets/less/csspinner/*.less', - 'assets/less/themes/*.less', - 'assets/less/toggle-switch/*.less', - ], - tasks: ['less'] - }, - js: { - files: [ - '<%= jshint.all %>' - ], - tasks: ['jshint', 'uglify'] - // tasks: ['jshint'] - }, - livereload: { - // Browser live reloading - // https://github.com/gruntjs/grunt-contrib-watch#live-reloading - options: { - livereload: false - }, - files: [ - 'assets/css/runeui.css', - 'assets/js/runeui.min.js', - 'app/*.php', - 'app/templates/*.php', - '*.php' - ] - } - }, - clean: { - dist: [ - 'assets/css/runeui.css', - 'assets/js/runeui.min.js' - ] - } - }); - - // Load tasks - grunt.loadNpmTasks('grunt-contrib-clean'); - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-less'); - - // Register tasks - grunt.registerTask('default', [ - 'clean', - 'less', - 'uglify' - ]); - grunt.registerTask('dev', [ - 'watch' - ]); - -}; +'use strict'; +module.exports = function(grunt) { + + grunt.initConfig({ + jshint: { + options: { + jshintrc: '.jshintrc' + }, + all: [ + 'Gruntfile.js', + 'assets/js/*.js', + '!assets/js/runeui.min.js', + '!assets/js/vendor/*.js' + ] + }, + less: { + dist: { + options: { + compile: true, + compress: true + }, + files: { + 'assets/css/runeui.css': [ + 'assets/less/runeui.less' + ] + } + } + }, + uglify: { + dist: { + files: { + 'assets/js/runeui.min.js': [ + 'assets/js/runeui.js' + ] + } + } + }, + watch: { + less: { + files: [ + 'assets/less/*.less', + 'assets/less/bootstrap/*.less', + 'assets/less/bootstrap-select/*.less', + 'assets/less/csspinner/*.less', + 'assets/less/themes/*.less', + 'assets/less/toggle-switch/*.less', + ], + tasks: ['less'] + }, + js: { + files: [ + '<%= jshint.all %>' + ], + tasks: ['jshint', 'uglify'] + // tasks: ['jshint'] + }, + livereload: { + // Browser live reloading + // https://github.com/gruntjs/grunt-contrib-watch#live-reloading + options: { + livereload: false + }, + files: [ + 'assets/css/runeui.css', + 'assets/js/runeui.min.js', + 'app/*.php', + 'app/templates/*.php', + '*.php' + ] + } + }, + clean: { + dist: [ + 'assets/css/runeui.css', + 'assets/js/runeui.min.js' + ] + } + }); + + // Load tasks + grunt.loadNpmTasks('grunt-contrib-clean'); + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-contrib-uglify'); + grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-contrib-less'); + + // Register tasks + grunt.registerTask('default', [ + 'clean', + 'less', + 'uglify' + ]); + grunt.registerTask('dev', [ + 'watch' + ]); + +}; diff --git a/README.md b/README.md index 59c702d0..9a3b1c1a 100644 --- a/README.md +++ b/README.md @@ -1,29 +1,29 @@ -RuneAudio -Free and open source Hi-Fi music player for embedded hardware - - -Copyright (C) 2013-2014 RuneAudio Team -http://www.runeaudio.com - -RuneUI -copyright (C) 2013-2014 - Andrea Coiutti (aka ACX) & Simone De Gregori (aka Orion) - -RuneOS -copyright (C) 2013-2014 - Simone De Gregori (aka Orion) & Carmelo San Giovanni (aka Um3ggh1U) - -RuneAudio website and logo -copyright (C) 2013-2014 - ACX webdesign (Andrea Coiutti) - -This Program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -This Program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with RuneAudio; see the file COPYING. If not, see -. +RuneAudio +Free and open source Hi-Fi music player for embedded hardware + + +Copyright (C) 2013-2014 RuneAudio Team +http://www.runeaudio.com + +RuneUI +copyright (C) 2013-2014 - Andrea Coiutti (aka ACX) & Simone De Gregori (aka Orion) + +RuneOS +copyright (C) 2013-2014 - Simone De Gregori (aka Orion) & Carmelo San Giovanni (aka Um3ggh1U) + +RuneAudio website and logo +copyright (C) 2013-2014 - ACX webdesign (Andrea Coiutti) + +This Program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +This Program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with RuneAudio; see the file COPYING. If not, see +. diff --git a/app/api/coverart_ctl.php b/app/api/coverart_ctl.php index 98a6aa75..f844057c 100644 --- a/app/api/coverart_ctl.php +++ b/app/api/coverart_ctl.php @@ -1,208 +1,208 @@ -. - * - * file: file: app/coverart_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -// direct output bypass template system -$tplfile = 0; -runelog("\n--------------------- coverart (start) ---------------------"); -// turn off output buffering -ob_implicit_flush(0); -// --------------------- MPD --------------------- -if ($activePlayer === 'MPD') { - // output switch - $output = 0; - include('getid3/audioinfo.class.php'); - // get Last.FM api-key - $lastfm_apikey = $redis->get('lastfm_apikey'); - // get HTTP proxy settings - $proxy = $redis->hGetall('proxy'); - // connect to MPD daemon - $mpd2 = openMpdSocket('/run/mpd.sock', 0); - // fetch MPD status - $status = _parseStatusResponse(MpdStatus($mpd2)); - $curTrack = getTrackInfo($mpd2, $status['song']); - $mpdRoot = "/mnt/MPD/"; - $trackMpdPath = findPLposPath($status['song'], $mpd2); - $currentpath = $mpdRoot.$trackMpdPath; - closeMpdSocket($mpd2); - // debug - runelog("MPD current path", $currentpath); - $request_uri = urldecode($_SERVER['REQUEST_URI']); - runelog("HTTP GET request_uri (urldecoded)", $request_uri); - $request_folder = substr(substr($request_uri, 0, strrpos($request_uri, "/")), 10); - runelog("HTTP GET (request_folder)", $request_folder); - $request_coverfile = substr($request_uri, strrpos($request_uri, "/") + 1); - runelog("HTTP GET (request_coverfile)", $request_coverfile); - $current_mpd_folder = substr(substr($currentpath, 0, strrpos($currentpath, "/")), 9); - runelog("MPD (current_mpd_folder)", $current_mpd_folder); -// --------------------- Spotify --------------------- -} elseif ($redis->get('activePlayer') === 'Spotify') { - runelog('rune_PL_wrk: open SPOP socket'); - $spop = openSpopSocket('localhost', 6602, 1); -} -if ((substr($request_coverfile, 0, 2) === '?v' OR $current_mpd_folder === $request_folder) && $activePlayer === 'MPD') { - // extact song details - if (isset($curTrack[0]['Title'])) { - $status['currentartist'] = $curTrack[0]['Artist']; - $status['currentsong'] = $curTrack[0]['Title']; - $status['currentalbum'] = $curTrack[0]['Album']; - $status['fileext'] = parseFileStr($curTrack[0]['file'], '.'); - } - //Extract info from current audio file (using ZendMedia library) - /* if ($status['fileext'] === 'flac') { - require_once('Zend/Media/Flac.php'); - $flac = new Zend_Media_Flac($currentpath); - if ($flac->hasMetadataBlock(Zend_Media_Flac::PICTURE)) { - // debug - runelog("coverart match: embedded (ZendMedia lib)"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$flac->getPicture()->getMimeType()); - echo $flac->getPicture()->getData(); - $output = 1; - } - } */ - //Extract info from current audio file (using GetID3 library) - if ($output === 0) { - $au = new AudioInfo(); - $auinfo = $au->Info($currentpath); - // 1. try to find embedded coverart - if (!empty($auinfo['comments']['picture'][0]['data'])) { - // debug - runelog("coverart match: embedded (GetID3 lib)"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .$auinfo['comments']['picture'][0]['image_mime']); - echo $auinfo['comments']['picture'][0]['data']; - $output = 1; - } - } - // 2. try to find local coverart - if ($output === 0) { - $local_cover_root = substr($currentpath, 0, strrpos($currentpath, "/")); - $local_cover_path[] = $local_cover_root.'/folder.jpg'; - $local_cover_path[] = $local_cover_root.'/cover.jpg'; - $local_cover_path[] = $local_cover_root.'/folder.png'; - $local_cover_path[] = $local_cover_root.'/cover.png'; - foreach ($local_cover_path as $path) { - if (file_exists($path)) { - $local_cover_path = $path; - $output = 1; - break; - } - } - // debug - runelog("coverart: local (path): ", $local_cover_path); - if ($output === 1) { - // debug - runelog("coverart match: cover-local"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .mime_content_type($local_cover_path)); - readfile($local_cover_path); - } - } - // 3.0 try to find coverart on Last.FM (Album) - if ($output === 0) { - $cover_url = ui_lastFM_coverart($status['currentartist'], $status['currentalbum'], $lastfm_apikey, $proxy); - if (!empty($cover_url)) { - // debug - runelog("coverart match: lastfm (query 1) coverURL=", $cover_url); - $lastfm_img = curlGet($cover_url, $proxy); - $bufferinfo = new finfo(FILEINFO_MIME); - $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); - } else { - // 3.1 try to find coverart on Last.FM (Artist) - $cover_url = ui_lastFM_coverart($status['currentartist'], '', $lastfm_apikey, $proxy); - if (!empty($cover_url)) { - // debug - runelog("coverart match: lastfm (query 2) coverURL=", $cover_url); - if (!empty($cover_url)) { - $lastfm_img = curlGet($cover_url, $proxy); - $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); - } - } - } - if (!empty($lastfm_img)) { - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$lastfm_img_mime); - echo $lastfm_img; - $output = 1; - } - } - // 4. serve DEFAULT rune-cover image - if ($output === 0) { - // debug - runelog("coverart match: cover-default"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .mime_content_type($_SERVER['HOME'].'/assets/img/cover-default.png')); - readfile($_SERVER['HOME'].'/assets/img/cover-default.png'); - $output = 1; - } -} else { - if ($activePlayer === 'Spotify') { - $count = 1; - do { - sendSpopCommand($spop, 'image'); - unset($spotify_cover); - $spotify_cover = readSpopResponse($spop); - $spotify_cover = json_decode($spotify_cover); - usleep(500000); - runelog('coverart (spotify): retry n: '.$count, $spotify_cover->status); - if ($spotify_cover->status === 'ok') { - $spotify_cover = base64_decode($spotify_cover->data); - break; - } - $count++; - } while ($count !== 10); - $bufferinfo = new finfo(FILEINFO_MIME); - $spotify_cover_mime = $bufferinfo->buffer($spotify_cover); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$spotify_cover_mime); - echo $spotify_cover; - } else { - // redirect to /covers NGiNX location - $local_cover_url = 'http://'.$_SERVER["SERVER_ADDR"].'/covers/'.$request_folder.'/'.$request_coverfile; - runelog("coverart: redirect to local-coverart (url): ", $local_cover_url); - header('Location: '.$local_cover_url, true, 301); - } -} -runelog("\n--------------------- coverart (end) ---------------------"); +. + * + * file: file: app/coverart_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// direct output bypass template system +$tplfile = 0; +runelog("\n--------------------- coverart (start) ---------------------"); +// turn off output buffering +ob_implicit_flush(0); +// --------------------- MPD --------------------- +if ($activePlayer === 'MPD') { + // output switch + $output = 0; + include('getid3/audioinfo.class.php'); + // get Last.FM api-key + $lastfm_apikey = $redis->get('lastfm_apikey'); + // get HTTP proxy settings + $proxy = $redis->hGetall('proxy'); + // connect to MPD daemon + $mpd2 = openMpdSocket('/run/mpd.sock', 0); + // fetch MPD status + $status = _parseStatusResponse(MpdStatus($mpd2)); + $curTrack = getTrackInfo($mpd2, $status['song']); + $mpdRoot = "/mnt/MPD/"; + $trackMpdPath = findPLposPath($status['song'], $mpd2); + $currentpath = $mpdRoot.$trackMpdPath; + closeMpdSocket($mpd2); + // debug + runelog("MPD current path", $currentpath); + $request_uri = urldecode($_SERVER['REQUEST_URI']); + runelog("HTTP GET request_uri (urldecoded)", $request_uri); + $request_folder = substr(substr($request_uri, 0, strrpos($request_uri, "/")), 10); + runelog("HTTP GET (request_folder)", $request_folder); + $request_coverfile = substr($request_uri, strrpos($request_uri, "/") + 1); + runelog("HTTP GET (request_coverfile)", $request_coverfile); + $current_mpd_folder = substr(substr($currentpath, 0, strrpos($currentpath, "/")), 9); + runelog("MPD (current_mpd_folder)", $current_mpd_folder); +// --------------------- Spotify --------------------- +} elseif ($redis->get('activePlayer') === 'Spotify') { + runelog('rune_PL_wrk: open SPOP socket'); + $spop = openSpopSocket('localhost', 6602, 1); +} +if ((substr($request_coverfile, 0, 2) === '?v' OR $current_mpd_folder === $request_folder) && $activePlayer === 'MPD') { + // extact song details + if (isset($curTrack[0]['Title'])) { + $status['currentartist'] = $curTrack[0]['Artist']; + $status['currentsong'] = $curTrack[0]['Title']; + $status['currentalbum'] = $curTrack[0]['Album']; + $status['fileext'] = parseFileStr($curTrack[0]['file'], '.'); + } + //Extract info from current audio file (using ZendMedia library) + /* if ($status['fileext'] === 'flac') { + require_once('Zend/Media/Flac.php'); + $flac = new Zend_Media_Flac($currentpath); + if ($flac->hasMetadataBlock(Zend_Media_Flac::PICTURE)) { + // debug + runelog("coverart match: embedded (ZendMedia lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$flac->getPicture()->getMimeType()); + echo $flac->getPicture()->getData(); + $output = 1; + } + } */ + //Extract info from current audio file (using GetID3 library) + if ($output === 0) { + $au = new AudioInfo(); + $auinfo = $au->Info($currentpath); + // 1. try to find embedded coverart + if (!empty($auinfo['comments']['picture'][0]['data'])) { + // debug + runelog("coverart match: embedded (GetID3 lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .$auinfo['comments']['picture'][0]['image_mime']); + echo $auinfo['comments']['picture'][0]['data']; + $output = 1; + } + } + // 2. try to find local coverart + if ($output === 0) { + $local_cover_root = substr($currentpath, 0, strrpos($currentpath, "/")); + $local_cover_path[] = $local_cover_root.'/folder.jpg'; + $local_cover_path[] = $local_cover_root.'/cover.jpg'; + $local_cover_path[] = $local_cover_root.'/folder.png'; + $local_cover_path[] = $local_cover_root.'/cover.png'; + foreach ($local_cover_path as $path) { + if (file_exists($path)) { + $local_cover_path = $path; + $output = 1; + break; + } + } + // debug + runelog("coverart: local (path): ", $local_cover_path); + if ($output === 1) { + // debug + runelog("coverart match: cover-local"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($local_cover_path)); + readfile($local_cover_path); + } + } + // 3.0 try to find coverart on Last.FM (Album) + if ($output === 0) { + $cover_url = ui_lastFM_coverart($status['currentartist'], $status['currentalbum'], $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 1) coverURL=", $cover_url); + $lastfm_img = curlGet($cover_url, $proxy); + $bufferinfo = new finfo(FILEINFO_MIME); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } else { + // 3.1 try to find coverart on Last.FM (Artist) + $cover_url = ui_lastFM_coverart($status['currentartist'], '', $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 2) coverURL=", $cover_url); + if (!empty($cover_url)) { + $lastfm_img = curlGet($cover_url, $proxy); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } + } + } + if (!empty($lastfm_img)) { + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$lastfm_img_mime); + echo $lastfm_img; + $output = 1; + } + } + // 4. serve DEFAULT rune-cover image + if ($output === 0) { + // debug + runelog("coverart match: cover-default"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($_SERVER['HOME'].'/assets/img/cover-default.png')); + readfile($_SERVER['HOME'].'/assets/img/cover-default.png'); + $output = 1; + } +} else { + if ($activePlayer === 'Spotify') { + $count = 1; + do { + sendSpopCommand($spop, 'image'); + unset($spotify_cover); + $spotify_cover = readSpopResponse($spop); + $spotify_cover = json_decode($spotify_cover); + usleep(500000); + runelog('coverart (spotify): retry n: '.$count, $spotify_cover->status); + if ($spotify_cover->status === 'ok') { + $spotify_cover = base64_decode($spotify_cover->data); + break; + } + $count++; + } while ($count !== 10); + $bufferinfo = new finfo(FILEINFO_MIME); + $spotify_cover_mime = $bufferinfo->buffer($spotify_cover); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$spotify_cover_mime); + echo $spotify_cover; + } else { + // redirect to /covers NGiNX location + $local_cover_url = 'http://'.$_SERVER["SERVER_ADDR"].'/covers/'.$request_folder.'/'.$request_coverfile; + runelog("coverart: redirect to local-coverart (url): ", $local_cover_url); + header('Location: '.$local_cover_url, true, 301); + } +} +runelog("\n--------------------- coverart (end) ---------------------"); diff --git a/app/api/credits_ctl.php b/app/api/credits_ctl.php index a93e5a85..87eeddb6 100644 --- a/app/api/credits_ctl.php +++ b/app/api/credits_ctl.php @@ -1,37 +1,37 @@ -. - * - * file: app/credits_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ - - $template->buildversion = $redis->get('buildversion'); - $template->release = $redis->get('release'); +. + * + * file: app/credits_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + + $template->buildversion = $redis->get('buildversion'); + $template->release = $redis->get('release'); \ No newline at end of file diff --git a/app/api/debug_ctl.php b/app/api/debug_ctl.php index 5ae00dd6..8b254114 100644 --- a/app/api/debug_ctl.php +++ b/app/api/debug_ctl.php @@ -1,43 +1,43 @@ -. - * - * file: app/debug_ctl.php - * version: 1.3 - * - */ -// ob_start(); -// echo debug_data($redis); -// $debugdata = ob_get_clean(); - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - -} else { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'debug')); - waitSyWrk($redis, $jobID); - $template->debug = $redis->get('debugdata'); +. + * + * file: app/debug_ctl.php + * version: 1.3 + * + */ +// ob_start(); +// echo debug_data($redis); +// $debugdata = ob_get_clean(); + +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + +} else { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'debug')); + waitSyWrk($redis, $jobID); + $template->debug = $redis->get('debugdata'); } \ No newline at end of file diff --git a/app/api/dev_ctl.php b/app/api/dev_ctl.php index 1af3c4ba..b361e581 100644 --- a/app/api/dev_ctl.php +++ b/app/api/dev_ctl.php @@ -1,94 +1,94 @@ -. - * - * file: app/dev_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -// inspect POST -if (isset($_POST)) { - // ----- DEV MODE ----- - if (isset($_POST['mode'])) { - if ($_POST['mode']['dev']['enable'] == 1) { - // create worker job (start udevil) - $redis->get('dev') == 1 || $redis->set('dev', 1); - $redis->get('debug') == 1 || $redis->set('debug', 1); - } else { - // create worker job (stop udevil) - $redis->get('dev') == 0 || $redis->set('dev', 0); - } - // ----- DEBUG ----- - if ($_POST['mode']['debug']['enable'] == 1) { - // create worker job (start udevil) - $redis->get('debug') == 1 || $redis->set('debug', 1); - } else { - // create worker job (stop udevil) - $redis->get('debug') == 0 || $redis->set('debug', 0); - } - } - // ----- OPCACHE ----- - if (isset($_POST['opcache'])) { - if ($_POST['opcache']['enable'] == 1) { - // create worker job (enable php opcache) - $redis->get('opcache') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'enable')); - } else { - // create worker job (disable php opcache) - $redis->get('opcache') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'disable')); - } - } - if (isset($_POST['syscmd'])) { - // ----- BLANK PLAYERID ----- - if ($_POST['syscmd'] === 'blankplayerid') $redis->set('playerid',''); - // ----- CLEARIMG ----- - if ($_POST['syscmd'] === 'clearimg') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'clearimg')); - // ----- CHECK FS PERMISSIONS ----- - if ($_POST['syscmd'] === 'syschmod') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sysAcl')); - // ----- RESTART MPD ----- - if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); - // ----- RESET NET CONFIG ----- - if ($_POST['syscmd'] === 'netconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'reset')); - // ----- RESET MPD CONFIG ----- - if ($_POST['syscmd'] === 'mpdconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); - // ----- RESTART PHP-FPM ----- - if ($_POST['syscmd'] === 'phprestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'phprestart')); - // ----- GIT PULL ----- - if ($_POST['syscmd'] === 'gitpull') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'gitpull')); - // ----- RESTART WORKERS ----- - if (isset($_POST['syscmd']['wrkrestart'])) $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wrkrestart', 'args' => $_POST['syscmd']['wrkrestart'])); - } -} -waitSyWrk($redis, $jobID); -$template->debug = $redis->get('debug'); -$template->playerid = $redis->get('playerid'); -$template->opcache = $redis->get('opcache'); -$template->gitbranch = $redis->hGet('git', 'branch'); -// debug -// var_dump($template->dev); -// var_dump($template->debug); -// var_dump($template->opcache); +. + * + * file: app/dev_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// inspect POST +if (isset($_POST)) { + // ----- DEV MODE ----- + if (isset($_POST['mode'])) { + if ($_POST['mode']['dev']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('dev') == 1 || $redis->set('dev', 1); + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('dev') == 0 || $redis->set('dev', 0); + } + // ----- DEBUG ----- + if ($_POST['mode']['debug']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('debug') == 0 || $redis->set('debug', 0); + } + } + // ----- OPCACHE ----- + if (isset($_POST['opcache'])) { + if ($_POST['opcache']['enable'] == 1) { + // create worker job (enable php opcache) + $redis->get('opcache') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'enable')); + } else { + // create worker job (disable php opcache) + $redis->get('opcache') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'disable')); + } + } + if (isset($_POST['syscmd'])) { + // ----- BLANK PLAYERID ----- + if ($_POST['syscmd'] === 'blankplayerid') $redis->set('playerid',''); + // ----- CLEARIMG ----- + if ($_POST['syscmd'] === 'clearimg') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'clearimg')); + // ----- CHECK FS PERMISSIONS ----- + if ($_POST['syscmd'] === 'syschmod') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sysAcl')); + // ----- RESTART MPD ----- + if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); + // ----- RESET NET CONFIG ----- + if ($_POST['syscmd'] === 'netconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'reset')); + // ----- RESET MPD CONFIG ----- + if ($_POST['syscmd'] === 'mpdconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); + // ----- RESTART PHP-FPM ----- + if ($_POST['syscmd'] === 'phprestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'phprestart')); + // ----- GIT PULL ----- + if ($_POST['syscmd'] === 'gitpull') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'gitpull')); + // ----- RESTART WORKERS ----- + if (isset($_POST['syscmd']['wrkrestart'])) $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wrkrestart', 'args' => $_POST['syscmd']['wrkrestart'])); + } +} +waitSyWrk($redis, $jobID); +$template->debug = $redis->get('debug'); +$template->playerid = $redis->get('playerid'); +$template->opcache = $redis->get('opcache'); +$template->gitbranch = $redis->hGet('git', 'branch'); +// debug +// var_dump($template->dev); +// var_dump($template->debug); +// var_dump($template->opcache); diff --git a/app/api/login_ctl.php b/app/api/login_ctl.php index a9a766d8..3f9377c0 100644 --- a/app/api/login_ctl.php +++ b/app/api/login_ctl.php @@ -1,34 +1,34 @@ -. - * - * file: app/login_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ +. + * + * file: app/login_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ \ No newline at end of file diff --git a/app/api/network_ctl.php b/app/api/network_ctl.php index d5f7a2b4..74b03ff5 100644 --- a/app/api/network_ctl.php +++ b/app/api/network_ctl.php @@ -1,145 +1,145 @@ -. - * - * file: app/network_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ - -// inspect POST -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - - - // get the data that was POSTed - $postData = file_get_contents("php://input"); - // convert to an associative array - $json = json_decode($postData, true); - - if ($json['refresh']==true) { - //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'refresh'", $_POST['nic']); - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'refresh')); - waitSyWrk($redis,$jobID); - return; - } - - - - if (isset($_POST['nic']) && !isset($_POST['wifiprofile'])) { - //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'config'", $_POST['nic']); - $redis->get($_POST['nic']['name']) === json_encode($nic) || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'config', 'args' => $_POST['nic'])); - } - - if (isset($_POST['wifiprofile'])) { - switch ($_POST['wifiprofile']['action']) { - case 'add': - //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'add'", $_POST['wifiprofile']); - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'add', 'args' => $_POST['wifiprofile'])); - break; - case 'edit': - //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'edit'", $_POST['wifiprofile']); - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'edit', 'args' => $_POST['wifiprofile'])); - break; - case 'delete': - //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'delete'", $_POST['wifiprofile']); - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'delete', 'args' => $_POST['wifiprofile'])); - break; - case 'connect': - //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'connect'", $_POST['wifiprofile']); - $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'connect', 'args' => $_POST['wifiprofile'] )); - break; - case 'disconnect': - //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'disconnect'", $_POST['wifiprofile']); - $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'disconnect', 'args' => $_POST['wifiprofile'] )); - break; - } - } -} - -waitSyWrk($redis,$jobID); -$template->nics = wrk_netconfig($redis, 'getnics'); -$template->wlan_autoconnect = $redis->Get('wlan_autoconnect'); -if ($redis->Exists(urldecode($template->uri(4)))) $template->stored = 1; -if (isset($template->action)) { - // check if we are into interface details (ex. http://runeaudio/network/edit/eth0) - if (isset($template->arg)) { - // check if there is a stored profile for current nic - $nic_stored_profile = json_decode($redis->Get($template->uri(3))); - // runelog('nic stored profile: ',$nic_stored_profile); - if (!empty($nic_stored_profile)) { - if ($nic_stored_profile->dhcp === '0') { - // read nic stored profile - $template->nic_stored = $nic_stored_profile; - } - } - // retrieve current nic status data (detected from the system) - $nic_connection = $redis->hGet('nics', $template->arg); - $template->nic = json_decode($nic_connection); - // check if we action is = 'edit' or 'wlan' (ex. http://runeaudio/network/edit/....) - if ($template->action === 'edit') { - // fetch current (stored) nic configuration data - if ($redis->get($template->arg)) { - $template->{$template->arg} = json_decode($redis->get($template->arg)); - // ok nic configuration not stored, but check if it is configured - } else if ($nic_connection == null) { - // last case, nonexistant nic. route to error template - $template->content = 'error'; - } - // check if the current nic is wireless - if ($template->nic->wireless === 1) { - $template->wlans = json_decode($redis->get('wlans')); - $template->wlan_profiles = new stdClass(); - if ($wlan_profiles = wrk_netconfig($redis, 'getstoredwlans')) { - foreach ($wlan_profiles as $key => $value) { - $template->wlan_profiles->{$key} = json_decode($value); - } - } - } - // we are in the wlan subtemplate (ex. http://runeaudio/network/wlan/....) - } else { - // check if we want to store a wifi profile, that is not in range. (ex. http://runeaudio/network/wlan/add ) - if ($template->uri(4) === 'add') { - $template->addprofile = 1; - } else { - // we are connecting to a visible network - $template->wlans = json_decode($redis->get('wlans')); - foreach ($template->wlans->{$template->uri(3)} as $key => $value) { - // if we are in a stored profile, retrieve his details - if ($template->stored) { - $template->profile_{urldecode($template->uri(4))} = json_decode($redis->hGet('wlan_profiles', urldecode($template->uri(4)))); - } - // check if we are in a connected profile - if ($template->uri(4) === $value->ESSID) { - // retrieve SSID details - $template->{$template->uri(4)} = $value; - } - } - } - } - } -} +. + * + * file: app/network_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + +// inspect POST +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + + + // get the data that was POSTed + $postData = file_get_contents("php://input"); + // convert to an associative array + $json = json_decode($postData, true); + + if ($json['refresh']==true) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'refresh'", $_POST['nic']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'refresh')); + waitSyWrk($redis,$jobID); + return; + } + + + + if (isset($_POST['nic']) && !isset($_POST['wifiprofile'])) { + //ui_notify_async("'wrkcmd' => 'netcfg', 'action' => 'config'", $_POST['nic']); + $redis->get($_POST['nic']['name']) === json_encode($nic) || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'config', 'args' => $_POST['nic'])); + } + + if (isset($_POST['wifiprofile'])) { + switch ($_POST['wifiprofile']['action']) { + case 'add': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'add'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'add', 'args' => $_POST['wifiprofile'])); + break; + case 'edit': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'edit'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'edit', 'args' => $_POST['wifiprofile'])); + break; + case 'delete': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'delete'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wificfg', 'action' => 'delete', 'args' => $_POST['wifiprofile'])); + break; + case 'connect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'connect'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'connect', 'args' => $_POST['wifiprofile'] )); + break; + case 'disconnect': + //ui_notify_async("'wrkcmd' => 'wificfg', 'action' => 'disconnect'", $_POST['wifiprofile']); + $jobID[] = wrk_control($redis, 'newjob', $data = array( 'wrkcmd' => 'wificfg', 'action' => 'disconnect', 'args' => $_POST['wifiprofile'] )); + break; + } + } +} + +waitSyWrk($redis,$jobID); +$template->nics = wrk_netconfig($redis, 'getnics'); +$template->wlan_autoconnect = $redis->Get('wlan_autoconnect'); +if ($redis->Exists(urldecode($template->uri(4)))) $template->stored = 1; +if (isset($template->action)) { + // check if we are into interface details (ex. http://runeaudio/network/edit/eth0) + if (isset($template->arg)) { + // check if there is a stored profile for current nic + $nic_stored_profile = json_decode($redis->Get($template->uri(3))); + // runelog('nic stored profile: ',$nic_stored_profile); + if (!empty($nic_stored_profile)) { + if ($nic_stored_profile->dhcp === '0') { + // read nic stored profile + $template->nic_stored = $nic_stored_profile; + } + } + // retrieve current nic status data (detected from the system) + $nic_connection = $redis->hGet('nics', $template->arg); + $template->nic = json_decode($nic_connection); + // check if we action is = 'edit' or 'wlan' (ex. http://runeaudio/network/edit/....) + if ($template->action === 'edit') { + // fetch current (stored) nic configuration data + if ($redis->get($template->arg)) { + $template->{$template->arg} = json_decode($redis->get($template->arg)); + // ok nic configuration not stored, but check if it is configured + } else if ($nic_connection == null) { + // last case, nonexistant nic. route to error template + $template->content = 'error'; + } + // check if the current nic is wireless + if ($template->nic->wireless === 1) { + $template->wlans = json_decode($redis->get('wlans')); + $template->wlan_profiles = new stdClass(); + if ($wlan_profiles = wrk_netconfig($redis, 'getstoredwlans')) { + foreach ($wlan_profiles as $key => $value) { + $template->wlan_profiles->{$key} = json_decode($value); + } + } + } + // we are in the wlan subtemplate (ex. http://runeaudio/network/wlan/....) + } else { + // check if we want to store a wifi profile, that is not in range. (ex. http://runeaudio/network/wlan/add ) + if ($template->uri(4) === 'add') { + $template->addprofile = 1; + } else { + // we are connecting to a visible network + $template->wlans = json_decode($redis->get('wlans')); + foreach ($template->wlans->{$template->uri(3)} as $key => $value) { + // if we are in a stored profile, retrieve his details + if ($template->stored) { + $template->profile_{urldecode($template->uri(4))} = json_decode($redis->hGet('wlan_profiles', urldecode($template->uri(4)))); + } + // check if we are in a connected profile + if ($template->uri(4) === $value->ESSID) { + // retrieve SSID details + $template->{$template->uri(4)} = $value; + } + } + } + } + } +} diff --git a/app/api/playback_ctl.php b/app/api/playback_ctl.php index 55eb045e..296ad06a 100644 --- a/app/api/playback_ctl.php +++ b/app/api/playback_ctl.php @@ -1,53 +1,53 @@ -. - * - * file: app/playback_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -$template->activePlayer = $redis->get('activePlayer'); -if ($redis->get('coverart') == 1) { - $template->coverart = 1; - $template->colspan = 4; -} else { - $template->coverart = 0; - $template->colspan = 6; -} -if ($redis->get('volume') == 1 && $template->activePlayer !== 'Spotify') { - $template->volume['color'] = '#0095D8'; - $template->volume['readonly'] = 'false'; -} else { - //$_volumeColor = '#002c40'; - $template->volume['color'] = '#1A242F'; - $template->volume['readonly'] = 'true'; - $template->volume['disabled'] = 1; - $template->volume['divclass'] = 'nomixer'; -} -$template->dev = $redis->get; -$template->spotify = $redis->hGet('spotify', 'enable'); +. + * + * file: app/playback_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +$template->activePlayer = $redis->get('activePlayer'); +if ($redis->get('coverart') == 1) { + $template->coverart = 1; + $template->colspan = 4; +} else { + $template->coverart = 0; + $template->colspan = 6; +} +if ($redis->get('volume') == 1 && $template->activePlayer !== 'Spotify') { + $template->volume['color'] = '#0095D8'; + $template->volume['readonly'] = 'false'; +} else { + //$_volumeColor = '#002c40'; + $template->volume['color'] = '#1A242F'; + $template->volume['readonly'] = 'true'; + $template->volume['disabled'] = 1; + $template->volume['divclass'] = 'nomixer'; +} +$template->dev = $redis->get; +$template->spotify = $redis->hGet('spotify', 'enable'); diff --git a/app/api/sources_ctl.php b/app/api/sources_ctl.php index bd656ecd..383c1c1a 100644 --- a/app/api/sources_ctl.php +++ b/app/api/sources_ctl.php @@ -1,119 +1,119 @@ -. - * - * file: app/sources_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - - // get the data that was POSTed - $postData = file_get_contents("php://input"); - // convert to an associative array - $json = json_decode($postData, true); - - if ($json['updatempd'] == true) { - sendMpdCommand($mpd, 'update'); - return; - } - - if ($json['mountall'] == true) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'mountall' )); - waitSyWrk($redis, $jobID); - return ; - } - - if ($json['usb-umount']) { - $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'umountusb', 'args' => $json['usb-umount'])); - waitSyWrk($redis, $jobID); - return; - } - - if ($json['mount']) { - $json['mount']['remotedir'] = str_replace('\\', '/', $json['mount']['remotedir']); - if ($json['mount']['rsize'] == '') $json['mount']['rsize'] = 16384; - if ($json['mount']['wsize'] == '') $json['mount']['wsize'] = 17408; - if ($json['mount']['options'] == '') { - if ($json['mount']['type'] === 'cifs' OR $json['mount']['type'] === 'osx') { - $json['mount']['options'] = "cache=none,ro"; - } else { - $json['mount']['options'] = "nfsvers=3,ro"; - } - } - if ($json['action'] == 'add') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'add', 'args' => $json['mount'])); - if ($json['action'] == 'edit') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'edit', 'args' => $json['mount'])); - if ($json['action'] == 'delete') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'delete', 'args' => $json['mount'])); - if ($json['action'] == 'reset') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfgman', 'action' => 'reset' )); - } - - waitSyWrk($redis, $jobID); -} else { - $id = $template->arg; // null when the id = 0 - - if ($id == '0') { - // THe user is doing a GET to setup the UI for a new source - $template->nas_name = ''; - $template->nas_ip = ''; - $template->nas_dir = ''; - - } else { - - } - - $source = netMounts($redis, 'read'); - if($source !== true) { - foreach ($source as $mp) { - if (wrk_checkStrSysfile('/proc/mounts', '/mnt/MPD/NAS/'.$mp['name'])) { - $mp['status'] = true; - } else { - $mp['status'] = false; - } - $mounts[]=$mp; - } - } - $template->mounts = $mounts; - $usbmounts = $redis->hGetAll('usbmounts'); - foreach ($usbmounts as $usbmount) { - $template->usbmounts[] = json_decode($usbmount); - } - if (isset($template->action)) { - if (isset($template->arg)) { - foreach ($source as $mp) { - if ($mp['id'] == $template->arg) { - $template->mount = $mp; - } - } - $template->title = 'Edit network mount'; - } else { - $template->title = 'Add new network mount'; - } - } - - +. + * + * file: app/sources_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + + // get the data that was POSTed + $postData = file_get_contents("php://input"); + // convert to an associative array + $json = json_decode($postData, true); + + if ($json['updatempd'] == true) { + sendMpdCommand($mpd, 'update'); + return; + } + + if ($json['mountall'] == true) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'mountall' )); + waitSyWrk($redis, $jobID); + return ; + } + + if ($json['usb-umount']) { + $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'umountusb', 'args' => $json['usb-umount'])); + waitSyWrk($redis, $jobID); + return; + } + + if ($json['mount']) { + $json['mount']['remotedir'] = str_replace('\\', '/', $json['mount']['remotedir']); + if ($json['mount']['rsize'] == '') $json['mount']['rsize'] = 16384; + if ($json['mount']['wsize'] == '') $json['mount']['wsize'] = 17408; + if ($json['mount']['options'] == '') { + if ($json['mount']['type'] === 'cifs' OR $json['mount']['type'] === 'osx') { + $json['mount']['options'] = "cache=none,ro"; + } else { + $json['mount']['options'] = "nfsvers=3,ro"; + } + } + if ($json['action'] == 'add') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'add', 'args' => $json['mount'])); + if ($json['action'] == 'edit') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'edit', 'args' => $json['mount'])); + if ($json['action'] == 'delete') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfg', 'action' => 'delete', 'args' => $json['mount'])); + if ($json['action'] == 'reset') $jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sourcecfgman', 'action' => 'reset' )); + } + + waitSyWrk($redis, $jobID); +} else { + $id = $template->arg; // null when the id = 0 + + if ($id == '0') { + // THe user is doing a GET to setup the UI for a new source + $template->nas_name = ''; + $template->nas_ip = ''; + $template->nas_dir = ''; + + } else { + + } + + $source = netMounts($redis, 'read'); + if($source !== true) { + foreach ($source as $mp) { + if (wrk_checkStrSysfile('/proc/mounts', '/mnt/MPD/NAS/'.$mp['name'])) { + $mp['status'] = true; + } else { + $mp['status'] = false; + } + $mounts[]=$mp; + } + } + $template->mounts = $mounts; + $usbmounts = $redis->hGetAll('usbmounts'); + foreach ($usbmounts as $usbmount) { + $template->usbmounts[] = json_decode($usbmount); + } + if (isset($template->action)) { + if (isset($template->arg)) { + foreach ($source as $mp) { + if ($mp['id'] == $template->arg) { + $template->mount = $mp; + } + } + $template->title = 'Edit network mount'; + } else { + $template->title = 'Add new network mount'; + } + } + + } \ No newline at end of file diff --git a/app/api/system_ctl.php b/app/api/system_ctl.php index 20ff4fca..d9764873 100644 --- a/app/api/system_ctl.php +++ b/app/api/system_ctl.php @@ -1,50 +1,50 @@ -. - * - * file: system_ctl.php - * version: 1.3 - * coder: Kevin Welsh - * - */ -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - // get the data that was POSTed - $postData = file_get_contents("php://input"); - // convert to an associative array - $json = json_decode($postData, true); - - if ($json['syscmd'] === 'reboot') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'reboot')); - if ($json['syscmd'] === 'poweroff') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'poweroff')); - // push backup file - if ($json['syscmd'] === 'backup') { - $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'backup')); - pushFile($redis->hGet('w_msg', $jobID[0])); - $redis->hDel('w_msg', $jobID[0]); - } - - waitSyWrk($redis,$jobID); -}; +. + * + * file: system_ctl.php + * version: 1.3 + * coder: Kevin Welsh + * + */ +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + // get the data that was POSTed + $postData = file_get_contents("php://input"); + // convert to an associative array + $json = json_decode($postData, true); + + if ($json['syscmd'] === 'reboot') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'reboot')); + if ($json['syscmd'] === 'poweroff') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'poweroff')); + // push backup file + if ($json['syscmd'] === 'backup') { + $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'backup')); + pushFile($redis->hGet('w_msg', $jobID[0])); + $redis->hDel('w_msg', $jobID[0]); + } + + waitSyWrk($redis,$jobID); +}; diff --git a/app/api/tun_ctl.php b/app/api/tun_ctl.php index e44babbd..93ca34a4 100644 --- a/app/api/tun_ctl.php +++ b/app/api/tun_ctl.php @@ -1,42 +1,42 @@ -. - * - * file: app/tun_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -// disable main template output -$tplfile = 0; -$proxy = $redis->hGetall('proxy'); -if ($proxy['enable'] === '1') { - echo curlGet(substr($_SERVER["REQUEST_URI"], 5), $proxy); -} else { - echo curlGet(substr($_SERVER["REQUEST_URI"], 5)); -} +. + * + * file: app/tun_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// disable main template output +$tplfile = 0; +$proxy = $redis->hGetall('proxy'); +if ($proxy['enable'] === '1') { + echo curlGet(substr($_SERVER["REQUEST_URI"], 5), $proxy); +} else { + echo curlGet(substr($_SERVER["REQUEST_URI"], 5)); +} \ No newline at end of file diff --git a/app/api_ctl.php b/app/api_ctl.php index 2371a2fc..008d7b93 100644 --- a/app/api_ctl.php +++ b/app/api_ctl.php @@ -1,3 +1,3 @@ -action.'_ctl.php'); +action.'_ctl.php'); diff --git a/app/config/_os/boot/cmdline.txt b/app/config/_os/boot/cmdline.txt index c11d9876..ef0b4af3 100644 --- a/app/config/_os/boot/cmdline.txt +++ b/app/config/_os/boot/cmdline.txt @@ -1,5 +1,5 @@ -#force_turbo=1 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 elevator=noop rootfstype=ext4 rootflags=data=writeback,journal_async_commit,discard,commit=120 rootwait smsc95xx.turbo_mode=N -#force_turbo=1 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 elevator=noop rootfstype=ext4 rootwait smsc95xx.turbo_mode=N -#ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop modprobe.blacklist=snd_soc_bcm2708,snd_soc_bcm2708_i2s,bcm2708_dmaengine,snd_soc_pcm5102a,snd_soc_hifiberry_dac rootwait smsc95xx.turbo_mode=N -ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 dwc_otg.fiq_split_enable=0 dwc_otg.fiq_fix_enable=0 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop usbcore.old_scheme_first=1 rootwait -#ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 dwc_otg.fiq_enable=1 dwc_otg.fiq_fsm_enable=1 dwc_otg.fiq_fsm_mask=0x3 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop rootwait +#force_turbo=1 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 elevator=noop rootfstype=ext4 rootflags=data=writeback,journal_async_commit,discard,commit=120 rootwait smsc95xx.turbo_mode=N +#force_turbo=1 dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p3 elevator=noop rootfstype=ext4 rootwait smsc95xx.turbo_mode=N +#ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop modprobe.blacklist=snd_soc_bcm2708,snd_soc_bcm2708_i2s,bcm2708_dmaengine,snd_soc_pcm5102a,snd_soc_hifiberry_dac rootwait smsc95xx.turbo_mode=N +ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 dwc_otg.fiq_split_enable=0 dwc_otg.fiq_fix_enable=0 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop usbcore.old_scheme_first=1 rootwait +#ipv6.disable=1 selinux=0 plymouth.enable=0 smsc95xx.turbo_mode=N dwc_otg.lpm_enable=0 dwc_otg.fiq_enable=1 dwc_otg.fiq_fsm_enable=1 dwc_otg.fiq_fsm_mask=0x3 console=tty1 root=/dev/mmcblk0p5 rootfstype=ext4 elevator=noop rootwait diff --git a/app/config/_os/etc/php/conf.d/opcache.ini b/app/config/_os/etc/php/conf.d/opcache.ini index d4f8b355..e2ca77ec 100644 --- a/app/config/_os/etc/php/conf.d/opcache.ini +++ b/app/config/_os/etc/php/conf.d/opcache.ini @@ -1,16 +1,16 @@ -zend_extension=/usr/lib/php/modules/opcache.so -opcache.enable=1 -opcache.validate_timestamps=0 -opcache.consistency_checks=0 -opcache.revalidate_freq=86400 -opcache.use_cwd=0 -opcache.memory_consumption=8 -opcache.interned_strings_buffer=8 -opcache.max_accelerated_files=400 -opcache.fast_shutdown=1 -opcache.enable_cli=1 -opcache.save_comments=0 -opcache.load_comments=0 -;opcache.error_log=/var/log/runeaudio/php-opcache.log -;opcache.log_verbosity_level=4 - +zend_extension=/usr/lib/php/modules/opcache.so +opcache.enable=1 +opcache.validate_timestamps=0 +opcache.consistency_checks=0 +opcache.revalidate_freq=86400 +opcache.use_cwd=0 +opcache.memory_consumption=8 +opcache.interned_strings_buffer=8 +opcache.max_accelerated_files=400 +opcache.fast_shutdown=1 +opcache.enable_cli=1 +opcache.save_comments=0 +opcache.load_comments=0 +;opcache.error_log=/var/log/runeaudio/php-opcache.log +;opcache.log_verbosity_level=4 + diff --git a/app/config/_os/etc/php/php.ini b/app/config/_os/etc/php/php.ini index 6a51ca29..e2186889 100644 --- a/app/config/_os/etc/php/php.ini +++ b/app/config/_os/etc/php/php.ini @@ -1,96 +1,96 @@ -[PHP] - -engine = On -short_open_tag = Off -asp_tags = Off -precision = 14 -output_buffering = 4096 -date.timezone = "UTC" -zlib.output_compression = Off -implicit_flush = Off -unserialize_callback_func = -serialize_precision = 17 -disable_functions = -disable_classes = -zend.enable_gc = On -expose_php = On -max_execution_time = 30 -max_input_time = 60 -memory_limit = 128M -display_startup_errors = On -log_errors_max_len = 1024 -ignore_repeated_errors = Off -ignore_repeated_source = Off -report_memleaks = On -track_errors = Off -html_errors = Off -variables_order = "GPCS" -request_order = "GP" -register_argc_argv = Off -auto_globals_jit = On -post_max_size = 8M -auto_prepend_file = -auto_append_file = -default_mimetype = "text/html" -include_path = ".:/usr/share/pear" -doc_root = -user_dir = -extension_dir = "/usr/lib/php/modules/" -enable_dl = Off -file_uploads = On -upload_max_filesize = 2M -max_file_uploads = 20 -allow_url_fopen = On -allow_url_include = Off -default_socket_timeout = 60 -extension=pthreads.so -extension=redis.so -;extension=curl.so -;extension=gettext.so -;extension=pdo_sqlite.so -;extension=sqlite3.so -;extension=posix.so -;extension=sockets.so -; required for composer -;extension=phar.so -;extension=openssl.so -;extension=zip.so -cli_server.color = On - -[bcmath] -; Number of decimal digits for all bcmath functions. -; http://php.net/bcmath.scale -bcmath.scale = 0 - -[Session] -; Handler used to store/retrieve data. -; http://php.net/session.save-handler -session.save_handler = redis -session.save_path = "tcp://localhost:6379?weight=1" -session.serialize_handler = php_binary -;session.save_handler = file -;session.save_path = "/run" -;session.serialize_handler = php -session.use_strict_mode = 0 -session.use_cookies = 1 -session.use_only_cookies = 1 -session.name = PHPSESSID -session.auto_start = 0 -session.cookie_lifetime = 0 -session.cookie_path = / -session.cookie_domain = -session.cookie_httponly = -session.gc_probability = 1 -session.gc_divisor = 1000 -session.gc_maxlifetime = 1440 -session.bug_compat_42 = Off -session.bug_compat_warn = Off -session.referer_check = -session.cache_limiter = nocache -session.cache_expire = 180 -session.use_trans_sid = 0 -session.hash_function = 0 -session.hash_bits_per_character = 5 -url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" - - +[PHP] + +engine = On +short_open_tag = Off +asp_tags = Off +precision = 14 +output_buffering = 4096 +date.timezone = "UTC" +zlib.output_compression = Off +implicit_flush = Off +unserialize_callback_func = +serialize_precision = 17 +disable_functions = +disable_classes = +zend.enable_gc = On +expose_php = On +max_execution_time = 30 +max_input_time = 60 +memory_limit = 128M +display_startup_errors = On +log_errors_max_len = 1024 +ignore_repeated_errors = Off +ignore_repeated_source = Off +report_memleaks = On +track_errors = Off +html_errors = Off +variables_order = "GPCS" +request_order = "GP" +register_argc_argv = Off +auto_globals_jit = On +post_max_size = 8M +auto_prepend_file = +auto_append_file = +default_mimetype = "text/html" +include_path = ".:/usr/share/pear" +doc_root = +user_dir = +extension_dir = "/usr/lib/php/modules/" +enable_dl = Off +file_uploads = On +upload_max_filesize = 2M +max_file_uploads = 20 +allow_url_fopen = On +allow_url_include = Off +default_socket_timeout = 60 +extension=pthreads.so +extension=redis.so +;extension=curl.so +;extension=gettext.so +;extension=pdo_sqlite.so +;extension=sqlite3.so +;extension=posix.so +;extension=sockets.so +; required for composer +;extension=phar.so +;extension=openssl.so +;extension=zip.so +cli_server.color = On + +[bcmath] +; Number of decimal digits for all bcmath functions. +; http://php.net/bcmath.scale +bcmath.scale = 0 + +[Session] +; Handler used to store/retrieve data. +; http://php.net/session.save-handler +session.save_handler = redis +session.save_path = "tcp://localhost:6379?weight=1" +session.serialize_handler = php_binary +;session.save_handler = file +;session.save_path = "/run" +;session.serialize_handler = php +session.use_strict_mode = 0 +session.use_cookies = 1 +session.use_only_cookies = 1 +session.name = PHPSESSID +session.auto_start = 0 +session.cookie_lifetime = 0 +session.cookie_path = / +session.cookie_domain = +session.cookie_httponly = +session.gc_probability = 1 +session.gc_divisor = 1000 +session.gc_maxlifetime = 1440 +session.bug_compat_42 = Off +session.bug_compat_warn = Off +session.referer_check = +session.cache_limiter = nocache +session.cache_expire = 180 +session.use_trans_sid = 0 +session.hash_function = 0 +session.hash_bits_per_character = 5 +url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=fakeentry" + + diff --git a/app/config/_os/etc/profile.d/proxy.sh b/app/config/_os/etc/profile.d/proxy.sh index 9b785aa0..20a22a73 100644 --- a/app/config/_os/etc/profile.d/proxy.sh +++ b/app/config/_os/etc/profile.d/proxy.sh @@ -1,7 +1,7 @@ -#!/bin/sh - -export http_proxy=http://user:pass@server:port/ -export https_proxy=$http_proxy -export ftp_proxy=$http_proxy -export rsync_proxy=$http_proxy -export no_proxy="localhost,127.0.0.1,localaddress,runeaudio.local" +#!/bin/sh + +export http_proxy=http://user:pass@server:port/ +export https_proxy=$http_proxy +export ftp_proxy=$http_proxy +export rsync_proxy=$http_proxy +export no_proxy="localhost,127.0.0.1,localaddress,runeaudio.local" diff --git a/app/config_ctl.php b/app/config_ctl.php index 8500805a..4efb9ea9 100644 --- a/app/config_ctl.php +++ b/app/config_ctl.php @@ -1,34 +1,34 @@ -. - * - * file: app/config_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ +. + * + * file: app/config_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ \ No newline at end of file diff --git a/app/coverart_ctl.php b/app/coverart_ctl.php index 98a6aa75..f844057c 100755 --- a/app/coverart_ctl.php +++ b/app/coverart_ctl.php @@ -1,208 +1,208 @@ -. - * - * file: file: app/coverart_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -// direct output bypass template system -$tplfile = 0; -runelog("\n--------------------- coverart (start) ---------------------"); -// turn off output buffering -ob_implicit_flush(0); -// --------------------- MPD --------------------- -if ($activePlayer === 'MPD') { - // output switch - $output = 0; - include('getid3/audioinfo.class.php'); - // get Last.FM api-key - $lastfm_apikey = $redis->get('lastfm_apikey'); - // get HTTP proxy settings - $proxy = $redis->hGetall('proxy'); - // connect to MPD daemon - $mpd2 = openMpdSocket('/run/mpd.sock', 0); - // fetch MPD status - $status = _parseStatusResponse(MpdStatus($mpd2)); - $curTrack = getTrackInfo($mpd2, $status['song']); - $mpdRoot = "/mnt/MPD/"; - $trackMpdPath = findPLposPath($status['song'], $mpd2); - $currentpath = $mpdRoot.$trackMpdPath; - closeMpdSocket($mpd2); - // debug - runelog("MPD current path", $currentpath); - $request_uri = urldecode($_SERVER['REQUEST_URI']); - runelog("HTTP GET request_uri (urldecoded)", $request_uri); - $request_folder = substr(substr($request_uri, 0, strrpos($request_uri, "/")), 10); - runelog("HTTP GET (request_folder)", $request_folder); - $request_coverfile = substr($request_uri, strrpos($request_uri, "/") + 1); - runelog("HTTP GET (request_coverfile)", $request_coverfile); - $current_mpd_folder = substr(substr($currentpath, 0, strrpos($currentpath, "/")), 9); - runelog("MPD (current_mpd_folder)", $current_mpd_folder); -// --------------------- Spotify --------------------- -} elseif ($redis->get('activePlayer') === 'Spotify') { - runelog('rune_PL_wrk: open SPOP socket'); - $spop = openSpopSocket('localhost', 6602, 1); -} -if ((substr($request_coverfile, 0, 2) === '?v' OR $current_mpd_folder === $request_folder) && $activePlayer === 'MPD') { - // extact song details - if (isset($curTrack[0]['Title'])) { - $status['currentartist'] = $curTrack[0]['Artist']; - $status['currentsong'] = $curTrack[0]['Title']; - $status['currentalbum'] = $curTrack[0]['Album']; - $status['fileext'] = parseFileStr($curTrack[0]['file'], '.'); - } - //Extract info from current audio file (using ZendMedia library) - /* if ($status['fileext'] === 'flac') { - require_once('Zend/Media/Flac.php'); - $flac = new Zend_Media_Flac($currentpath); - if ($flac->hasMetadataBlock(Zend_Media_Flac::PICTURE)) { - // debug - runelog("coverart match: embedded (ZendMedia lib)"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$flac->getPicture()->getMimeType()); - echo $flac->getPicture()->getData(); - $output = 1; - } - } */ - //Extract info from current audio file (using GetID3 library) - if ($output === 0) { - $au = new AudioInfo(); - $auinfo = $au->Info($currentpath); - // 1. try to find embedded coverart - if (!empty($auinfo['comments']['picture'][0]['data'])) { - // debug - runelog("coverart match: embedded (GetID3 lib)"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .$auinfo['comments']['picture'][0]['image_mime']); - echo $auinfo['comments']['picture'][0]['data']; - $output = 1; - } - } - // 2. try to find local coverart - if ($output === 0) { - $local_cover_root = substr($currentpath, 0, strrpos($currentpath, "/")); - $local_cover_path[] = $local_cover_root.'/folder.jpg'; - $local_cover_path[] = $local_cover_root.'/cover.jpg'; - $local_cover_path[] = $local_cover_root.'/folder.png'; - $local_cover_path[] = $local_cover_root.'/cover.png'; - foreach ($local_cover_path as $path) { - if (file_exists($path)) { - $local_cover_path = $path; - $output = 1; - break; - } - } - // debug - runelog("coverart: local (path): ", $local_cover_path); - if ($output === 1) { - // debug - runelog("coverart match: cover-local"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .mime_content_type($local_cover_path)); - readfile($local_cover_path); - } - } - // 3.0 try to find coverart on Last.FM (Album) - if ($output === 0) { - $cover_url = ui_lastFM_coverart($status['currentartist'], $status['currentalbum'], $lastfm_apikey, $proxy); - if (!empty($cover_url)) { - // debug - runelog("coverart match: lastfm (query 1) coverURL=", $cover_url); - $lastfm_img = curlGet($cover_url, $proxy); - $bufferinfo = new finfo(FILEINFO_MIME); - $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); - } else { - // 3.1 try to find coverart on Last.FM (Artist) - $cover_url = ui_lastFM_coverart($status['currentartist'], '', $lastfm_apikey, $proxy); - if (!empty($cover_url)) { - // debug - runelog("coverart match: lastfm (query 2) coverURL=", $cover_url); - if (!empty($cover_url)) { - $lastfm_img = curlGet($cover_url, $proxy); - $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); - } - } - } - if (!empty($lastfm_img)) { - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$lastfm_img_mime); - echo $lastfm_img; - $output = 1; - } - } - // 4. serve DEFAULT rune-cover image - if ($output === 0) { - // debug - runelog("coverart match: cover-default"); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: ' .mime_content_type($_SERVER['HOME'].'/assets/img/cover-default.png')); - readfile($_SERVER['HOME'].'/assets/img/cover-default.png'); - $output = 1; - } -} else { - if ($activePlayer === 'Spotify') { - $count = 1; - do { - sendSpopCommand($spop, 'image'); - unset($spotify_cover); - $spotify_cover = readSpopResponse($spop); - $spotify_cover = json_decode($spotify_cover); - usleep(500000); - runelog('coverart (spotify): retry n: '.$count, $spotify_cover->status); - if ($spotify_cover->status === 'ok') { - $spotify_cover = base64_decode($spotify_cover->data); - break; - } - $count++; - } while ($count !== 10); - $bufferinfo = new finfo(FILEINFO_MIME); - $spotify_cover_mime = $bufferinfo->buffer($spotify_cover); - header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. - header('Pragma: no-cache'); // HTTP 1.0. - header('Expires: 0'); // Proxies. - header('Content-Type: '.$spotify_cover_mime); - echo $spotify_cover; - } else { - // redirect to /covers NGiNX location - $local_cover_url = 'http://'.$_SERVER["SERVER_ADDR"].'/covers/'.$request_folder.'/'.$request_coverfile; - runelog("coverart: redirect to local-coverart (url): ", $local_cover_url); - header('Location: '.$local_cover_url, true, 301); - } -} -runelog("\n--------------------- coverart (end) ---------------------"); +. + * + * file: file: app/coverart_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// direct output bypass template system +$tplfile = 0; +runelog("\n--------------------- coverart (start) ---------------------"); +// turn off output buffering +ob_implicit_flush(0); +// --------------------- MPD --------------------- +if ($activePlayer === 'MPD') { + // output switch + $output = 0; + include('getid3/audioinfo.class.php'); + // get Last.FM api-key + $lastfm_apikey = $redis->get('lastfm_apikey'); + // get HTTP proxy settings + $proxy = $redis->hGetall('proxy'); + // connect to MPD daemon + $mpd2 = openMpdSocket('/run/mpd.sock', 0); + // fetch MPD status + $status = _parseStatusResponse(MpdStatus($mpd2)); + $curTrack = getTrackInfo($mpd2, $status['song']); + $mpdRoot = "/mnt/MPD/"; + $trackMpdPath = findPLposPath($status['song'], $mpd2); + $currentpath = $mpdRoot.$trackMpdPath; + closeMpdSocket($mpd2); + // debug + runelog("MPD current path", $currentpath); + $request_uri = urldecode($_SERVER['REQUEST_URI']); + runelog("HTTP GET request_uri (urldecoded)", $request_uri); + $request_folder = substr(substr($request_uri, 0, strrpos($request_uri, "/")), 10); + runelog("HTTP GET (request_folder)", $request_folder); + $request_coverfile = substr($request_uri, strrpos($request_uri, "/") + 1); + runelog("HTTP GET (request_coverfile)", $request_coverfile); + $current_mpd_folder = substr(substr($currentpath, 0, strrpos($currentpath, "/")), 9); + runelog("MPD (current_mpd_folder)", $current_mpd_folder); +// --------------------- Spotify --------------------- +} elseif ($redis->get('activePlayer') === 'Spotify') { + runelog('rune_PL_wrk: open SPOP socket'); + $spop = openSpopSocket('localhost', 6602, 1); +} +if ((substr($request_coverfile, 0, 2) === '?v' OR $current_mpd_folder === $request_folder) && $activePlayer === 'MPD') { + // extact song details + if (isset($curTrack[0]['Title'])) { + $status['currentartist'] = $curTrack[0]['Artist']; + $status['currentsong'] = $curTrack[0]['Title']; + $status['currentalbum'] = $curTrack[0]['Album']; + $status['fileext'] = parseFileStr($curTrack[0]['file'], '.'); + } + //Extract info from current audio file (using ZendMedia library) + /* if ($status['fileext'] === 'flac') { + require_once('Zend/Media/Flac.php'); + $flac = new Zend_Media_Flac($currentpath); + if ($flac->hasMetadataBlock(Zend_Media_Flac::PICTURE)) { + // debug + runelog("coverart match: embedded (ZendMedia lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$flac->getPicture()->getMimeType()); + echo $flac->getPicture()->getData(); + $output = 1; + } + } */ + //Extract info from current audio file (using GetID3 library) + if ($output === 0) { + $au = new AudioInfo(); + $auinfo = $au->Info($currentpath); + // 1. try to find embedded coverart + if (!empty($auinfo['comments']['picture'][0]['data'])) { + // debug + runelog("coverart match: embedded (GetID3 lib)"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .$auinfo['comments']['picture'][0]['image_mime']); + echo $auinfo['comments']['picture'][0]['data']; + $output = 1; + } + } + // 2. try to find local coverart + if ($output === 0) { + $local_cover_root = substr($currentpath, 0, strrpos($currentpath, "/")); + $local_cover_path[] = $local_cover_root.'/folder.jpg'; + $local_cover_path[] = $local_cover_root.'/cover.jpg'; + $local_cover_path[] = $local_cover_root.'/folder.png'; + $local_cover_path[] = $local_cover_root.'/cover.png'; + foreach ($local_cover_path as $path) { + if (file_exists($path)) { + $local_cover_path = $path; + $output = 1; + break; + } + } + // debug + runelog("coverart: local (path): ", $local_cover_path); + if ($output === 1) { + // debug + runelog("coverart match: cover-local"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($local_cover_path)); + readfile($local_cover_path); + } + } + // 3.0 try to find coverart on Last.FM (Album) + if ($output === 0) { + $cover_url = ui_lastFM_coverart($status['currentartist'], $status['currentalbum'], $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 1) coverURL=", $cover_url); + $lastfm_img = curlGet($cover_url, $proxy); + $bufferinfo = new finfo(FILEINFO_MIME); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } else { + // 3.1 try to find coverart on Last.FM (Artist) + $cover_url = ui_lastFM_coverart($status['currentartist'], '', $lastfm_apikey, $proxy); + if (!empty($cover_url)) { + // debug + runelog("coverart match: lastfm (query 2) coverURL=", $cover_url); + if (!empty($cover_url)) { + $lastfm_img = curlGet($cover_url, $proxy); + $lastfm_img_mime = $bufferinfo->buffer($lastfm_img); + } + } + } + if (!empty($lastfm_img)) { + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$lastfm_img_mime); + echo $lastfm_img; + $output = 1; + } + } + // 4. serve DEFAULT rune-cover image + if ($output === 0) { + // debug + runelog("coverart match: cover-default"); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: ' .mime_content_type($_SERVER['HOME'].'/assets/img/cover-default.png')); + readfile($_SERVER['HOME'].'/assets/img/cover-default.png'); + $output = 1; + } +} else { + if ($activePlayer === 'Spotify') { + $count = 1; + do { + sendSpopCommand($spop, 'image'); + unset($spotify_cover); + $spotify_cover = readSpopResponse($spop); + $spotify_cover = json_decode($spotify_cover); + usleep(500000); + runelog('coverart (spotify): retry n: '.$count, $spotify_cover->status); + if ($spotify_cover->status === 'ok') { + $spotify_cover = base64_decode($spotify_cover->data); + break; + } + $count++; + } while ($count !== 10); + $bufferinfo = new finfo(FILEINFO_MIME); + $spotify_cover_mime = $bufferinfo->buffer($spotify_cover); + header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. + header('Pragma: no-cache'); // HTTP 1.0. + header('Expires: 0'); // Proxies. + header('Content-Type: '.$spotify_cover_mime); + echo $spotify_cover; + } else { + // redirect to /covers NGiNX location + $local_cover_url = 'http://'.$_SERVER["SERVER_ADDR"].'/covers/'.$request_folder.'/'.$request_coverfile; + runelog("coverart: redirect to local-coverart (url): ", $local_cover_url); + header('Location: '.$local_cover_url, true, 301); + } +} +runelog("\n--------------------- coverart (end) ---------------------"); diff --git a/app/credits_ctl.php b/app/credits_ctl.php index 5066511b..5a2ae29c 100644 --- a/app/credits_ctl.php +++ b/app/credits_ctl.php @@ -1,36 +1,36 @@ -. - * - * file: app/credits_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ - - $template->buildversion = $redis->get('buildversion'); +. + * + * file: app/credits_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ + + $template->buildversion = $redis->get('buildversion'); \ No newline at end of file diff --git a/app/debug_ctl.php b/app/debug_ctl.php index a526dc6e..e1ddb424 100644 --- a/app/debug_ctl.php +++ b/app/debug_ctl.php @@ -1,38 +1,38 @@ -. - * - * file: app/debug_ctl.php - * version: 1.3 - * - */ -// ob_start(); -// echo debug_data($redis); -// $debugdata = ob_get_clean(); -$jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'debug')); -waitSyWrk($redis, $jobID); -$template->debug = $redis->get('debugdata'); +. + * + * file: app/debug_ctl.php + * version: 1.3 + * + */ +// ob_start(); +// echo debug_data($redis); +// $debugdata = ob_get_clean(); +$jobID = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'debug')); +waitSyWrk($redis, $jobID); +$template->debug = $redis->get('debugdata'); diff --git a/app/dev_ctl.php b/app/dev_ctl.php index e9da3ad0..8bee4b72 100755 --- a/app/dev_ctl.php +++ b/app/dev_ctl.php @@ -1,93 +1,93 @@ -. - * - * file: app/dev_ctl.php - * version: 1.3 - * coder: Simone De Gregori - * - */ -// inspect POST -if (isset($_POST)) { - // ----- DEV MODE ----- - if (isset($_POST['mode'])) { - if ($_POST['mode']['dev']['enable'] == 1) { - // create worker job (start udevil) - $redis->get('dev') == 1 || $redis->set('dev', 1); - $redis->get('debug') == 1 || $redis->set('debug', 1); - } else { - // create worker job (stop udevil) - $redis->get('dev') == 0 || $redis->set('dev', 0); - } - // ----- DEBUG ----- - if ($_POST['mode']['debug']['enable'] == 1) { - // create worker job (start udevil) - $redis->get('debug') == 1 || $redis->set('debug', 1); - } else { - // create worker job (stop udevil) - $redis->get('debug') == 0 || $redis->set('debug', 0); - } - } - // ----- OPCACHE ----- - if (isset($_POST['opcache'])) { - if ($_POST['opcache']['enable'] == 1) { - // create worker job (enable php opcache) - $redis->get('opcache') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'enable')); - } else { - // create worker job (disable php opcache) - $redis->get('opcache') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'disable')); - } - } - if (isset($_POST['syscmd'])) { - // ----- BLANK PLAYERID ----- - if ($_POST['syscmd'] === 'blankplayerid') $redis->set('playerid',''); - // ----- CLEARIMG ----- - if ($_POST['syscmd'] === 'clearimg') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'clearimg')); - // ----- CHECK FS PERMISSIONS ----- - if ($_POST['syscmd'] === 'syschmod') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sysAcl')); - // ----- RESTART MPD ----- - if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); - // ----- RESET NET CONFIG ----- - if ($_POST['syscmd'] === 'netconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'reset')); - // ----- RESET MPD CONFIG ----- - if ($_POST['syscmd'] === 'mpdconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); - // ----- RESTART PHP-FPM ----- - if ($_POST['syscmd'] === 'phprestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'phprestart')); - // ----- GIT PULL ----- - if ($_POST['syscmd'] === 'gitpull') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'gitpull')); - // ----- RESTART WORKERS ----- - if (isset($_POST['syscmd']['wrkrestart'])) $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wrkrestart', 'args' => $_POST['syscmd']['wrkrestart'])); - } -} -waitSyWrk($redis, $jobID); -$template->debug = $redis->get('debug'); -$template->playerid = $redis->get('playerid'); -$template->opcache = $redis->get('opcache'); -// debug -// var_dump($template->dev); -// var_dump($template->debug); -// var_dump($template->opcache); +. + * + * file: app/dev_ctl.php + * version: 1.3 + * coder: Simone De Gregori + * + */ +// inspect POST +if (isset($_POST)) { + // ----- DEV MODE ----- + if (isset($_POST['mode'])) { + if ($_POST['mode']['dev']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('dev') == 1 || $redis->set('dev', 1); + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('dev') == 0 || $redis->set('dev', 0); + } + // ----- DEBUG ----- + if ($_POST['mode']['debug']['enable'] == 1) { + // create worker job (start udevil) + $redis->get('debug') == 1 || $redis->set('debug', 1); + } else { + // create worker job (stop udevil) + $redis->get('debug') == 0 || $redis->set('debug', 0); + } + } + // ----- OPCACHE ----- + if (isset($_POST['opcache'])) { + if ($_POST['opcache']['enable'] == 1) { + // create worker job (enable php opcache) + $redis->get('opcache') == 1 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'enable')); + } else { + // create worker job (disable php opcache) + $redis->get('opcache') == 0 || $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'opcache', 'action' => 'disable')); + } + } + if (isset($_POST['syscmd'])) { + // ----- BLANK PLAYERID ----- + if ($_POST['syscmd'] === 'blankplayerid') $redis->set('playerid',''); + // ----- CLEARIMG ----- + if ($_POST['syscmd'] === 'clearimg') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'clearimg')); + // ----- CHECK FS PERMISSIONS ----- + if ($_POST['syscmd'] === 'syschmod') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'sysAcl')); + // ----- RESTART MPD ----- + if ($_POST['syscmd'] === 'mpdrestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdrestart')); + // ----- RESET NET CONFIG ----- + if ($_POST['syscmd'] === 'netconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'netcfg', 'action' => 'reset')); + // ----- RESET MPD CONFIG ----- + if ($_POST['syscmd'] === 'mpdconfreset') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'mpdcfg', 'action' => 'reset')); + // ----- RESTART PHP-FPM ----- + if ($_POST['syscmd'] === 'phprestart') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'phprestart')); + // ----- GIT PULL ----- + if ($_POST['syscmd'] === 'gitpull') $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'gitpull')); + // ----- RESTART WORKERS ----- + if (isset($_POST['syscmd']['wrkrestart'])) $jobID[] = wrk_control($redis, 'newjob', $data = array('wrkcmd' => 'wrkrestart', 'args' => $_POST['syscmd']['wrkrestart'])); + } +} +waitSyWrk($redis, $jobID); +$template->debug = $redis->get('debug'); +$template->playerid = $redis->get('playerid'); +$template->opcache = $redis->get('opcache'); +// debug +// var_dump($template->dev); +// var_dump($template->debug); +// var_dump($template->opcache); diff --git a/app/libs/composer.json b/app/libs/composer.json index 29f3f8d6..bbf45b3b 100644 --- a/app/libs/composer.json +++ b/app/libs/composer.json @@ -1,5 +1,5 @@ -{ - "require": { - "league/plates": "1.1.*", - } +{ + "require": { + "league/plates": "1.1.*", + } } \ No newline at end of file diff --git a/app/libs/composer.lock b/app/libs/composer.lock index 10d73a50..308092ad 100644 --- a/app/libs/composer.lock +++ b/app/libs/composer.lock @@ -1,266 +1,266 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" - ], - "hash": "9bd3bf98f71ebe47072d3f31c0f2f717", - "packages": [ - { - "name": "evenement/evenement", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-0": { - "Evenement": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch", - "homepage": "http://wiedler.ch/igor/" - } - ], - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": [ - "event-dispatcher", - "event-emitter" - ], - "time": "2012-11-02 14:49:47" - }, - { - "name": "guzzle/parser", - "version": "v3.8.1", - "target-dir": "Guzzle/Parser", - "source": { - "type": "git", - "url": "https://github.com/guzzle/parser.git", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle\\Parser": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Interchangeable parsers used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "URI Template", - "cookie", - "http", - "message", - "url" - ], - "time": "2013-10-24 00:04:09" - }, - { - "name": "league/plates", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/plates.git", - "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/plates/zipball/d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", - "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", - "shasum": "" - }, - "require-dev": { - "mikey179/vfsstream": "v1.2.0", - "mockery/mockery": "dev-master@dev", - "phpunit/phpunit": "3.7.*" - }, - "type": "library", - "autoload": { - "psr-4": { - "League\\Plates\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jonathan Reinink", - "email": "jonathan@reinink.ca", - "role": "Developer" - } - ], - "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", - "homepage": "http://platesphp.com", - "keywords": [ - "league", - "package", - "templating" - ], - "time": "2014-01-31 23:43:18" - }, - { - "name": "react/promise", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-0": { - "React\\Promise": "src/" - }, - "files": [ - "src/React/Promise/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@googlemail.com", - "homepage": "http://sorgalla.com", - "role": "maintainer" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "time": "2013-12-10 15:40:36" - }, - { - "name": "react/react", - "version": "v0.4.1", - "source": { - "type": "git", - "url": "https://github.com/reactphp/react.git", - "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/react/zipball/17044db0ab6a9c145fb1ac40822c5c17d045dc36", - "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36", - "shasum": "" - }, - "require": { - "evenement/evenement": "~2.0", - "guzzle/parser": "~3.0", - "php": ">=5.4.0", - "react/promise": "~2.0" - }, - "replace": { - "react/cache": "self.version", - "react/dns": "self.version", - "react/event-loop": "self.version", - "react/http": "self.version", - "react/http-client": "self.version", - "react/socket": "self.version", - "react/socket-client": "self.version", - "react/stream": "self.version" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "suggest": { - "ext-event": "Allows for use of a more performant event-loop implementation.", - "ext-libev": "Allows for use of a more performant event-loop implementation.", - "ext-libevent": "Allows for use of a more performant event-loop implementation." - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5-dev" - } - }, - "autoload": { - "psr-4": { - "React\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Nuclear Reactor written in PHP.", - "keywords": [ - "event-loop", - "reactor" - ], - "time": "2014-04-13 17:03:14" - } - ], - "packages-dev": [ - - ], - "aliases": [ - - ], - "minimum-stability": "stable", - "stability-flags": [ - - ], - "platform": [ - - ], - "platform-dev": [ - - ] -} +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "9bd3bf98f71ebe47072d3f31c0f2f717", + "packages": [ + { + "name": "evenement/evenement", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch", + "homepage": "http://wiedler.ch/igor/" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2012-11-02 14:49:47" + }, + { + "name": "guzzle/parser", + "version": "v3.8.1", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/guzzle/parser.git", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ], + "time": "2013-10-24 00:04:09" + }, + { + "name": "league/plates", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/plates.git", + "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/plates/zipball/d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", + "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", + "shasum": "" + }, + "require-dev": { + "mikey179/vfsstream": "v1.2.0", + "mockery/mockery": "dev-master@dev", + "phpunit/phpunit": "3.7.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Plates\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "role": "Developer" + } + ], + "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", + "homepage": "http://platesphp.com", + "keywords": [ + "league", + "package", + "templating" + ], + "time": "2014-01-31 23:43:18" + }, + { + "name": "react/promise", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "React\\Promise": "src/" + }, + "files": [ + "src/React/Promise/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com", + "homepage": "http://sorgalla.com", + "role": "maintainer" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2013-12-10 15:40:36" + }, + { + "name": "react/react", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/reactphp/react.git", + "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/react/zipball/17044db0ab6a9c145fb1ac40822c5c17d045dc36", + "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36", + "shasum": "" + }, + "require": { + "evenement/evenement": "~2.0", + "guzzle/parser": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "replace": { + "react/cache": "self.version", + "react/dns": "self.version", + "react/event-loop": "self.version", + "react/http": "self.version", + "react/http-client": "self.version", + "react/socket": "self.version", + "react/socket-client": "self.version", + "react/stream": "self.version" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "ext-event": "Allows for use of a more performant event-loop implementation.", + "ext-libev": "Allows for use of a more performant event-loop implementation.", + "ext-libevent": "Allows for use of a more performant event-loop implementation." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5-dev" + } + }, + "autoload": { + "psr-4": { + "React\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Nuclear Reactor written in PHP.", + "keywords": [ + "event-loop", + "reactor" + ], + "time": "2014-04-13 17:03:14" + } + ], + "packages-dev": [ + + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": [ + + ], + "platform": [ + + ], + "platform-dev": [ + + ] +} diff --git a/app/libs/vendor/Zend/Bit/Twiddling.php b/app/libs/vendor/Zend/Bit/Twiddling.php index 7ced7824..45232eb6 100644 --- a/app/libs/vendor/Zend/Bit/Twiddling.php +++ b/app/libs/vendor/Zend/Bit/Twiddling.php @@ -1,223 +1,223 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Twiddling.php 177 2010-03-09 13:13:34Z svollbehr $ - * @static - */ -final class Zend_Bit_Twiddling -{ - /** - * Default private constructor for a static class. - */ - private function __construct() - { - } - - /** - * Sets a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to set. - * @param boolean $on Whether to enable or clear the bit. - * @return integer - */ - public static function setBit($integer, $position, $on) - { - return $on ? self::enableBit($integer, $position) : - self::clearBit($integer, $position); - } - - /** - * Enables a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to enable. - * @return integer - */ - public static function enableBit($integer, $position) - { - return $integer | (1 << $position); - } - - /** - * Clears a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to clear. - * @return integer - */ - public static function clearBit($integer, $position) - { - return $integer & ~(1 << $position); - } - - /** - * Toggles a bit at a given position in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $position The position of the bit to toggle. - * @return integer - */ - public static function toggleBit($integer, $position) - { - return $integer ^ (1 << $position); - } - - /** - * Tests a bit at a given position in an integer. - * - * @param integer $integer The value to test. - * @param integer $position The position of the bit to test. - * @return boolean - */ - public static function testBit($integer, $position) - { - return ($integer & (1 << $position)) != 0; - } - - /** - * Sets a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to set. - * @param boolean $on Whether to enable or clear the bits. - * @return integer - */ - public static function setBits($integer, $bits, $on) - { - return $on ? self::enableBits($integer, $bits) : - self::clearBits($integer, $bits); - } - - /** - * Enables a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to enable. - * @return integer - */ - public static function enableBits($integer, $bits) - { - return $integer | $bits; - } - - /** - * Clears a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to clear. - * @return integer - */ - public static function clearBits($integer, $bits) - { - return $integer & ~$bits; - } - - /** - * Toggles a given set of bits in an integer. - * - * @param integer $integer The value to manipulate. - * @param integer $bits The bits to toggle. - * @return integer - */ - public static function toggleBits($integer, $bits) - { - return $integer ^ $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether all bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAllBits($integer, $bits) - { - return ($integer & $bits) == $bits; - } - - /** - * Tests a given set of bits in an integer - * returning whether any bits are set. - * - * @param integer $integer The value to test. - * @param integer $bits The bits to test. - * @return boolean - */ - public static function testAnyBits($integer, $bits) - { - return ($integer & $bits) != 0; - } - - /** - * Stores a value in a given range in an integer. - * - * @param integer $integer The value to store into. - * @param integer $start The position to store from. Must be <= $end. - * @param integer $end The position to store to. Must be >= $start. - * @param integer $value The value to store. - * @return integer - */ - public static function setValue($integer, $start, $end, $value) - { - return self::clearBits - ($integer, self::getMask - ($start, $end) << $start) | ($value << $start); - } - - /** - * Retrieves a value from a given range in an integer, inclusive. - * - * @param integer $integer The value to read from. - * @param integer $start The position to read from. Must be <= $end. - * @param integer $end The position to read to. Must be >= $start. - * @return integer - */ - public static function getValue($integer, $start, $end) - { - return ($integer & self::getMask($start, $end)) >> $start; - } - - /** - * Returns an integer with all bits set from start to end. - * - * @param integer $start The position to start setting bits from. Must - * be <= $end. - * @param integer $end The position to stop setting bits. Must - * be >= $start. - * @return integer - */ - public static function getMask($start, $end) - { - return ($tmp = (1 << $end)) + $tmp - (1 << $start); - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Twiddling.php 177 2010-03-09 13:13:34Z svollbehr $ + * @static + */ +final class Zend_Bit_Twiddling +{ + /** + * Default private constructor for a static class. + */ + private function __construct() + { + } + + /** + * Sets a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to set. + * @param boolean $on Whether to enable or clear the bit. + * @return integer + */ + public static function setBit($integer, $position, $on) + { + return $on ? self::enableBit($integer, $position) : + self::clearBit($integer, $position); + } + + /** + * Enables a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to enable. + * @return integer + */ + public static function enableBit($integer, $position) + { + return $integer | (1 << $position); + } + + /** + * Clears a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to clear. + * @return integer + */ + public static function clearBit($integer, $position) + { + return $integer & ~(1 << $position); + } + + /** + * Toggles a bit at a given position in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $position The position of the bit to toggle. + * @return integer + */ + public static function toggleBit($integer, $position) + { + return $integer ^ (1 << $position); + } + + /** + * Tests a bit at a given position in an integer. + * + * @param integer $integer The value to test. + * @param integer $position The position of the bit to test. + * @return boolean + */ + public static function testBit($integer, $position) + { + return ($integer & (1 << $position)) != 0; + } + + /** + * Sets a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to set. + * @param boolean $on Whether to enable or clear the bits. + * @return integer + */ + public static function setBits($integer, $bits, $on) + { + return $on ? self::enableBits($integer, $bits) : + self::clearBits($integer, $bits); + } + + /** + * Enables a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to enable. + * @return integer + */ + public static function enableBits($integer, $bits) + { + return $integer | $bits; + } + + /** + * Clears a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to clear. + * @return integer + */ + public static function clearBits($integer, $bits) + { + return $integer & ~$bits; + } + + /** + * Toggles a given set of bits in an integer. + * + * @param integer $integer The value to manipulate. + * @param integer $bits The bits to toggle. + * @return integer + */ + public static function toggleBits($integer, $bits) + { + return $integer ^ $bits; + } + + /** + * Tests a given set of bits in an integer + * returning whether all bits are set. + * + * @param integer $integer The value to test. + * @param integer $bits The bits to test. + * @return boolean + */ + public static function testAllBits($integer, $bits) + { + return ($integer & $bits) == $bits; + } + + /** + * Tests a given set of bits in an integer + * returning whether any bits are set. + * + * @param integer $integer The value to test. + * @param integer $bits The bits to test. + * @return boolean + */ + public static function testAnyBits($integer, $bits) + { + return ($integer & $bits) != 0; + } + + /** + * Stores a value in a given range in an integer. + * + * @param integer $integer The value to store into. + * @param integer $start The position to store from. Must be <= $end. + * @param integer $end The position to store to. Must be >= $start. + * @param integer $value The value to store. + * @return integer + */ + public static function setValue($integer, $start, $end, $value) + { + return self::clearBits + ($integer, self::getMask + ($start, $end) << $start) | ($value << $start); + } + + /** + * Retrieves a value from a given range in an integer, inclusive. + * + * @param integer $integer The value to read from. + * @param integer $start The position to read from. Must be <= $end. + * @param integer $end The position to read to. Must be >= $start. + * @return integer + */ + public static function getValue($integer, $start, $end) + { + return ($integer & self::getMask($start, $end)) >> $start; + } + + /** + * Returns an integer with all bits set from start to end. + * + * @param integer $start The position to start setting bits from. Must + * be <= $end. + * @param integer $end The position to stop setting bits. Must + * be >= $start. + * @return integer + */ + public static function getMask($start, $end) + { + return ($tmp = (1 << $end)) + $tmp - (1 << $start); + } +} diff --git a/app/libs/vendor/Zend/Exception.php b/app/libs/vendor/Zend/Exception.php index 0eda91d9..a439b5fb 100644 --- a/app/libs/vendor/Zend/Exception.php +++ b/app/libs/vendor/Zend/Exception.php @@ -1,96 +1,96 @@ -_previous = $previous; - } else { - parent::__construct($msg, (int) $code, $previous); - } - } - - /** - * Overloading - * - * For PHP < 5.3.0, provides access to the getPrevious() method. - * - * @param string $method - * @param array $args - * @return mixed - */ - public function __call($method, array $args) - { - if ('getprevious' == strtolower($method)) { - return $this->_getPrevious(); - } - return null; - } - - /** - * String representation of the exception - * - * @return string - */ - public function __toString() - { - if (version_compare(PHP_VERSION, '5.3.0', '<')) { - if (null !== ($e = $this->getPrevious())) { - return $e->__toString() - . "\n\nNext " - . parent::__toString(); - } - } - return parent::__toString(); - } - - /** - * Returns previous Exception - * - * @return Exception|null - */ - protected function _getPrevious() - { - return $this->_previous; - } -} +_previous = $previous; + } else { + parent::__construct($msg, (int) $code, $previous); + } + } + + /** + * Overloading + * + * For PHP < 5.3.0, provides access to the getPrevious() method. + * + * @param string $method + * @param array $args + * @return mixed + */ + public function __call($method, array $args) + { + if ('getprevious' == strtolower($method)) { + return $this->_getPrevious(); + } + return null; + } + + /** + * String representation of the exception + * + * @return string + */ + public function __toString() + { + if (version_compare(PHP_VERSION, '5.3.0', '<')) { + if (null !== ($e = $this->getPrevious())) { + return $e->__toString() + . "\n\nNext " + . parent::__toString(); + } + } + return parent::__toString(); + } + + /** + * Returns previous Exception + * + * @return Exception|null + */ + protected function _getPrevious() + { + return $this->_previous; + } +} diff --git a/app/libs/vendor/Zend/Io/Exception.php b/app/libs/vendor/Zend/Io/Exception.php index fe1cde78..b7b6e6fa 100644 --- a/app/libs/vendor/Zend/Io/Exception.php +++ b/app/libs/vendor/Zend/Io/Exception.php @@ -1,38 +1,38 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_Exception extends Zend_Exception -{} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_Exception extends Zend_Exception +{} diff --git a/app/libs/vendor/Zend/Io/FileReader.php b/app/libs/vendor/Zend/Io/FileReader.php index 1beb1e7f..0e9565c9 100644 --- a/app/libs/vendor/Zend/Io/FileReader.php +++ b/app/libs/vendor/Zend/Io/FileReader.php @@ -1,66 +1,66 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FileReader.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_FileReader extends Zend_Io_Reader -{ - /** - * Constructs the Zend_Io_FileReader class with given path to the file. By - * default the file is opened in read (rb) mode. - * - * @param string $filename The path to the file. - * @throws Zend_Io_Exception if the file cannot be read - */ - public function __construct($filename, $mode = null) - { - if ($mode === null) - $mode = 'rb'; - if (!file_exists($filename) || !is_readable($filename) || - ($fd = fopen($filename, $mode)) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Unable to open file for reading: ' . $filename); - } - parent::__construct($fd); - } - - /** - * Closes the file descriptor. - */ - public function __destruct() - { - $this->close(); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: FileReader.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_FileReader extends Zend_Io_Reader +{ + /** + * Constructs the Zend_Io_FileReader class with given path to the file. By + * default the file is opened in read (rb) mode. + * + * @param string $filename The path to the file. + * @throws Zend_Io_Exception if the file cannot be read + */ + public function __construct($filename, $mode = null) + { + if ($mode === null) + $mode = 'rb'; + if (!file_exists($filename) || !is_readable($filename) || + ($fd = fopen($filename, $mode)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Unable to open file for reading: ' . $filename); + } + parent::__construct($fd); + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/app/libs/vendor/Zend/Io/FileWriter.php b/app/libs/vendor/Zend/Io/FileWriter.php index 1fb3fd96..5f3b6bde 100644 --- a/app/libs/vendor/Zend/Io/FileWriter.php +++ b/app/libs/vendor/Zend/Io/FileWriter.php @@ -1,66 +1,66 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FileWriter.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_FileWriter extends Zend_Io_Writer -{ - /** - * Constructs the Zend_Io_FileWriter class with given path to the file. By - * default the file is opened in write mode without altering its content - * (ie r+b mode if the file exists, and wb mode if not). - * - * @param string $filename The path to the file. - * @throws Zend_Io_Exception if the file cannot be written - */ - public function __construct($filename, $mode = null) - { - if ($mode === null) - $mode = file_exists($filename) ? 'r+b' : 'wb'; - if (($fd = fopen($filename, $mode)) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Unable to open file for writing: ' . $filename); - } - parent::__construct($fd); - } - - /** - * Closes the file descriptor. - */ - public function __destruct() - { - $this->close(); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: FileWriter.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_FileWriter extends Zend_Io_Writer +{ + /** + * Constructs the Zend_Io_FileWriter class with given path to the file. By + * default the file is opened in write mode without altering its content + * (ie r+b mode if the file exists, and wb mode if not). + * + * @param string $filename The path to the file. + * @throws Zend_Io_Exception if the file cannot be written + */ + public function __construct($filename, $mode = null) + { + if ($mode === null) + $mode = file_exists($filename) ? 'r+b' : 'wb'; + if (($fd = fopen($filename, $mode)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Unable to open file for writing: ' . $filename); + } + parent::__construct($fd); + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/app/libs/vendor/Zend/Io/Reader.php b/app/libs/vendor/Zend/Io/Reader.php index 52091ef5..17abc08f 100644 --- a/app/libs/vendor/Zend/Io/Reader.php +++ b/app/libs/vendor/Zend/Io/Reader.php @@ -1,893 +1,893 @@ - - * @author Ryan Butterfield - * @author Marc Bennewitz - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Reader.php 214 2011-04-30 08:19:28Z svollbehr $ - */ -class Zend_Io_Reader -{ - const MACHINE_ENDIAN_ORDER = 0; - const LITTLE_ENDIAN_ORDER = 1; - const BIG_ENDIAN_ORDER = 2; - - /** - * The endianess of the current machine. - * - * @var integer - */ - private static $_endianess = 0; - - /** - * The resource identifier of the stream. - * - * @var resource - */ - protected $_fd = null; - - /** - * Size of the underlying stream. - * - * @var integer - */ - protected $_size = 0; - - /** - * Constructs the Zend_Io_Reader class with given open file descriptor. - * - * @param resource $fd The file descriptor. - * @throws Zend_Io_Exception if given file descriptor is not valid - */ - public function __construct($fd) - { - if (!is_resource($fd) || - !in_array(get_resource_type($fd), array('stream'))) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Invalid resource type (only resources of type stream are supported)'); - } - - $this->_fd = $fd; - - $offset = $this->getOffset(); - fseek($this->_fd, 0, SEEK_END); - $this->_size = ftell($this->_fd); - fseek($this->_fd, $offset); - } - - /** - * Default destructor. - */ - public function __destruct() {} - - /** - * Checks whether there is more to be read from the stream. Returns - * true if the end has not yet been reached; false - * otherwise. - * - * @return boolean - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function available() - { - return $this->getOffset() < $this->getSize(); - } - - /** - * Returns the current point of operation. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function getOffset() - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - return ftell($this->_fd); - } - - /** - * Sets the point of operation, ie the cursor offset value. The offset may - * also be set to a negative value when it is interpreted as an offset from - * the end of the stream instead of the beginning. - * - * @param integer $offset The new point of operation. - * @return void - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function setOffset($offset) - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); - } - - /** - * Returns the stream size in bytes. - * - * @return integer - */ - public function getSize() - { - return $this->_size; - } - - /** - * Returns the underlying stream file descriptor. - * - * @return resource - */ - public function getFileDescriptor() - { - return $this->_fd; - } - - /** - * Jumps size amount of bytes in the stream. - * - * @param integer $size The amount of bytes. - * @return void - * @throws Zend_Io_Exception if size attribute is negative or if - * an I/O error occurs - */ - public function skip($size) - { - if ($size < 0) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Size cannot be negative'); - } - if ($size == 0) { - return; - } - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - fseek($this->_fd, $size, SEEK_CUR); - } - - /** - * Reads length amount of bytes from the stream. - * - * @param integer $length The amount of bytes. - * @return string - * @throws Zend_Io_Exception if length attribute is negative or - * if an I/O error occurs - */ - public function read($length) - { - if ($length < 0) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Length cannot be negative'); - } - if ($length == 0) { - return ''; - } - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - return fread($this->_fd, $length); - } - - /** - * Reads 1 byte from the stream and returns binary data as an 8-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt8() - { - $ord = ord($this->read(1)); - if ($ord > 127) { - return -$ord - 2 * (128 - $ord); - } else { - return $ord; - } - } - - /** - * Reads 1 byte from the stream and returns binary data as an unsigned 8-bit - * integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt8() - { - return ord($this->read(1)); - } - - /** - * Returns machine endian ordered binary data as signed 16-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - private function _fromInt16($value) - { - list(, $int) = unpack('s*', $value); - return $int; - } - - /** - * Reads 2 bytes from the stream and returns little-endian ordered binary - * data as signed 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt16LE() - { - if ($this->_isBigEndian()) { - return $this->_fromInt16(strrev($this->read(2))); - } else { - return $this->_fromInt16($this->read(2)); - } - } - - /** - * Reads 2 bytes from the stream and returns big-endian ordered binary data - * as signed 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt16BE() - { - if ($this->_isLittleEndian()) { - return $this->_fromInt16(strrev($this->read(2))); - } else { - return $this->_fromInt16($this->read(2)); - } - } - - /** - * Reads 2 bytes from the stream and returns machine ordered binary data - * as signed 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt16() - { - return $this->_fromInt16($this->read(2)); - } - - /** - * Returns machine endian ordered binary data as unsigned 16-bit integer. - * - * @param string $value The binary data string. - * @param integer $order The byte order of the binary data string. - * @return integer - */ - private function _fromUInt16($value, $order = 0) - { - list(, $int) = unpack - (($order == self::BIG_ENDIAN_ORDER ? 'n' : - ($order == self::LITTLE_ENDIAN_ORDER ? 'v' : 'S')) . '*', - $value); - return $int; - } - - /** - * Reads 2 bytes from the stream and returns little-endian ordered binary - * data as unsigned 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt16LE() - { - return $this->_fromUInt16($this->read(2), self::LITTLE_ENDIAN_ORDER); - } - - /** - * Reads 2 bytes from the stream and returns big-endian ordered binary data - * as unsigned 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt16BE() - { - return $this->_fromUInt16($this->read(2), self::BIG_ENDIAN_ORDER); - } - - /** - * Reads 2 bytes from the stream and returns machine ordered binary data - * as unsigned 16-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt16() - { - return $this->_fromUInt16($this->read(2), self::MACHINE_ENDIAN_ORDER); - } - - /** - * Returns machine endian ordered binary data as signed 24-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - private function _fromInt24($value) - { - list(, $int) = unpack('l*', $this->_isLittleEndian() ? ("\x00" . $value) : ($value . "\x00")); - return $int; - } - - /** - * Reads 3 bytes from the stream and returns little-endian ordered binary - * data as signed 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt24LE() - { - if ($this->_isBigEndian()) { - return $this->_fromInt24(strrev($this->read(3))); - } else { - return $this->_fromInt24($this->read(3)); - } - } - - /** - * Reads 3 bytes from the stream and returns big-endian ordered binary data - * as signed 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt24BE() - { - if ($this->_isLittleEndian()) { - return $this->_fromInt24(strrev($this->read(3))); - } else { - return $this->_fromInt24($this->read(3)); - } - } - - /** - * Reads 3 bytes from the stream and returns machine ordered binary data - * as signed 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt24() - { - return $this->_fromInt24($this->read(3)); - } - - /** - * Returns machine endian ordered binary data as unsigned 24-bit integer. - * - * @param string $value The binary data string. - * @param integer $order The byte order of the binary data string. - * @return integer - */ - private function _fromUInt24($value, $order = 0) - { - list(, $int) = unpack - (($order == self::BIG_ENDIAN_ORDER ? 'N' : - ($order == self::LITTLE_ENDIAN_ORDER ? 'V' : 'L')) . '*', - $this->_isLittleEndian() ? ("\x00" . $value) : ($value . "\x00")); - return $int; - } - - /** - * Reads 3 bytes from the stream and returns little-endian ordered binary - * data as unsigned 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt24LE() - { - return $this->_fromUInt24($this->read(3), self::LITTLE_ENDIAN_ORDER); - } - - /** - * Reads 3 bytes from the stream and returns big-endian ordered binary data - * as unsigned 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt24BE() - { - return $this->_fromUInt24($this->read(3), self::BIG_ENDIAN_ORDER); - } - - /** - * Reads 3 bytes from the stream and returns machine ordered binary data - * as unsigned 24-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt24() - { - return $this->_fromUInt24($this->read(3), self::MACHINE_ENDIAN_ORDER); - } - - /** - * Returns machine-endian ordered binary data as signed 32-bit integer. - * - * @param string $value The binary data string. - * @return integer - */ - private final function _fromInt32($value) - { - list(, $int) = unpack('l*', $value); - return $int; - } - - /** - * Reads 4 bytes from the stream and returns little-endian ordered binary - * data as signed 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt32LE() - { - if ($this->_isBigEndian()) - return $this->_fromInt32(strrev($this->read(4))); - else - return $this->_fromInt32($this->read(4)); - } - - /** - * Reads 4 bytes from the stream and returns big-endian ordered binary data - * as signed 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt32BE() - { - if ($this->_isLittleEndian()) - return $this->_fromInt32(strrev($this->read(4))); - else - return $this->_fromInt32($this->read(4)); - } - - /** - * Reads 4 bytes from the stream and returns machine ordered binary data - * as signed 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt32() - { - return $this->_fromInt32($this->read(4)); - } - - /** - * Reads 4 bytes from the stream and returns little-endian ordered binary - * data as unsigned 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt32LE() - { - if (PHP_INT_SIZE < 8) { - list(, $lo, $hi) = unpack('v*', $this->read(4)); - return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo - } else { - list(, $int) = unpack('V*', $this->read(4)); - return $int; - } - } - - /** - * Reads 4 bytes from the stream and returns big-endian ordered binary data - * as unsigned 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt32BE() - { - if (PHP_INT_SIZE < 8) { - list(, $hi, $lo) = unpack('n*', $this->read(4)); - return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo - } else { - list(, $int) = unpack('N*', $this->read(4)); - return $int; - } - } - - /** - * Reads 4 bytes from the stream and returns machine ordered binary data - * as unsigned 32-bit integer. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readUInt32() - { - if (PHP_INT_SIZE < 8) { - list(, $hi, $lo) = unpack('L*', $this->read(4)); - return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo - } else { - list(, $int) = unpack('L*', $this->read(4)); - return $int; - } - } - - /** - * Reads 8 bytes from the stream and returns little-endian ordered binary - * data as 64-bit float. - * - * {@internal PHP does not support 64-bit integers as the long - * integer is of 32-bits but using aritmetic operations it is implicitly - * converted into floating point which is of 64-bits long.}} - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt64LE() - { - list(, $lolo, $lohi, $hilo, $hihi) = unpack('v*', $this->read(8)); - return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + - ($lohi * (0xffff+1) + $lolo); - } - - /** - * Reads 8 bytes from the stream and returns big-endian ordered binary data - * as 64-bit float. - * - * {@internal PHP does not support 64-bit integers as the long integer is of - * 32-bits but using aritmetic operations it is implicitly converted into - * floating point which is of 64-bits long.}} - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readInt64BE() - { - list(, $hihi, $hilo, $lohi, $lolo) = unpack('n*', $this->read(8)); - return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + - ($lohi * (0xffff+1) + $lolo); - } - - /** - * Returns machine endian ordered binary data as a 32-bit floating point - * number as defined by IEEE 754. - * - * @param string $value The binary data string. - * @return float - */ - private function _fromFloat($value) - { - list(, $float) = unpack('f', $value); - return $float; - } - - /** - * Reads 4 bytes from the stream and returns little-endian ordered binary - * data as a 32-bit float point number as defined by IEEE 754. - * - * @return float - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readFloatLE() - { - if ($this->_isBigEndian()) { - return $this->_fromFloat(strrev($this->read(4))); - } else { - return $this->_fromFloat($this->read(4)); - } - } - - /** - * Reads 4 bytes from the stream and returns big-endian ordered binary data - * as a 32-bit float point number as defined by IEEE 754. - * - * @return float - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readFloatBE() - { - if ($this->_isLittleEndian()) { - return $this->_fromFloat(strrev($this->read(4))); - } else { - return $this->_fromFloat($this->read(4)); - } - } - - /** - * Returns machine endian ordered binary data as a 64-bit floating point - * number as defined by IEEE754. - * - * @param string $value The binary data string. - * @return float - */ - private function _fromDouble($value) - { - list(, $double) = unpack('d', $value); - return $double; - } - - /** - * Reads 8 bytes from the stream and returns little-endian ordered binary - * data as a 64-bit floating point number as defined by IEEE 754. - * - * @return float - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readDoubleLE() - { - if ($this->_isBigEndian()) { - return $this->_fromDouble(strrev($this->read(8))); - } else { - return $this->_fromDouble($this->read(8)); - } - } - - /** - * Reads 8 bytes from the stream and returns big-endian ordered binary data - * as a 64-bit float point number as defined by IEEE 754. - * - * @return float - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readDoubleBE() - { - if ($this->_isLittleEndian()) { - return $this->_fromDouble(strrev($this->read(8))); - } else { - return $this->_fromDouble($this->read(8)); - } - } - - /** - * Reads length amount of bytes from the stream and returns - * binary data as string. Removes terminating zero. - * - * @param integer $length The amount of bytes. - * @param string $charList The list of characters you want to strip. - * @return string - * @throws Zend_Io_Exception if length attribute is negative or - * if an I/O error occurs - */ - public final function readString8($length, $charList = "\0") - { - return rtrim($this->read($length), $charList); - } - - /** - * Reads length amount of bytes from the stream and returns - * binary data as multibyte Unicode string. Removes terminating zero. - * - * The byte order is possibly determined from the byte order mark included - * in the binary data string. The order parameter is updated if the BOM is - * found. - * - * @param integer $length The amount of bytes. - * @param integer $order The endianess of the string. - * @param integer $trimOrder Whether to remove the byte order mark read the - * string. - * @return string - * @throws Zend_Io_Exception if length attribute is negative or - * if an I/O error occurs - */ - public final function readString16 - ($length, &$order = null, $trimOrder = false) - { - $value = $this->read($length); - - if (strlen($value) < 2) { - return ''; - } - - if (ord($value[0]) == 0xfe && ord($value[1]) == 0xff) { - $order = self::BIG_ENDIAN_ORDER; - if ($trimOrder) { - $value = substr($value, 2); - } - } - if (ord($value[0]) == 0xff && ord($value[1]) == 0xfe) { - $order = self::LITTLE_ENDIAN_ORDER; - if ($trimOrder) { - $value = substr($value, 2); - } - } - - while (substr($value, -2) == "\0\0") { - $value = substr($value, 0, -2); - } - - return $value; - } - - /** - * Reads length amount of bytes from the stream and returns - * binary data as hexadecimal string having high nibble first. - * - * @param integer $length The amount of bytes. - * @return string - * @throws Zend_Io_Exception if length attribute is negative or - * if an I/O error occurs - */ - public final function readHHex($length) - { - list($hex) = unpack('H*0', $this->read($length)); - return $hex; - } - - /** - * Reads length amount of bytes from the stream and returns - * binary data as hexadecimal string having low nibble first. - * - * @param integer $length The amount of bytes. - * @return string - * @throws Zend_Io_Exception if length attribute is negative or - * if an I/O error occurs - */ - public final function readLHex($length) - { - list($hex) = unpack('h*0', $this->read($length)); - return $hex; - } - - /** - * Reads 16 bytes from the stream and returns the little-endian ordered - * binary data as mixed-ordered hexadecimal GUID string. - * - * @return string - * @throws Zend_Io_Exception if an I/O error occurs - */ - public final function readGuid() - { - $C = @unpack('V1V/v2v/N2N', $this->read(16)); - list($hex) = @unpack('H*0', pack - ('NnnNN', $C['V'], $C['v1'], $C['v2'], $C['N1'], $C['N2'])); - - /* Fixes a bug in PHP versions earlier than Jan 25 2006 */ - if (implode('', unpack('H*', pack('H*', 'a'))) == 'a00') { - $hex = substr($hex, 0, -1); - } - - return preg_replace - ('/^(.{8})(.{4})(.{4})(.{4})/', "\\1-\\2-\\3-\\4-", $hex); - } - - /** - * Resets the stream. Attempts to reset it in some way appropriate to the - * particular stream, for example by repositioning it to its starting point. - * - * @return void - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function reset() - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - fseek($this->_fd, 0); - } - - /** - * Closes the stream. Once a stream has been closed, further calls to read - * methods will throw an exception. Closing a previously-closed stream, - * however, has no effect. - * - * @return void - */ - public function close() - { - if ($this->_fd !== null) { - @fclose($this->_fd); - $this->_fd = null; - } - } - - /** - * Returns the current machine endian order. - * - * @return integer - */ - private function _getEndianess() - { - if (self::$_endianess === 0) { - self::$_endianess = $this->_fromInt32("\x01\x00\x00\x00") == 1 ? - self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; - } - return self::$_endianess; - } - - /** - * Returns whether the current machine endian order is little endian. - * - * @return boolean - */ - private function _isLittleEndian() - { - return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; - } - - /** - * Returns whether the current machine endian order is big endian. - * - * @return boolean - */ - private function _isBigEndian() - { - return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { - return call_user_func - (array($this, 'get' . ucfirst(strtolower($name)))); - } else { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { - call_user_func - (array($this, 'set' . ucfirst(strtolower($name))), $value); - } else { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unknown field: ' . $name); - } - } -} + + * @author Ryan Butterfield + * @author Marc Bennewitz + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Reader.php 214 2011-04-30 08:19:28Z svollbehr $ + */ +class Zend_Io_Reader +{ + const MACHINE_ENDIAN_ORDER = 0; + const LITTLE_ENDIAN_ORDER = 1; + const BIG_ENDIAN_ORDER = 2; + + /** + * The endianess of the current machine. + * + * @var integer + */ + private static $_endianess = 0; + + /** + * The resource identifier of the stream. + * + * @var resource + */ + protected $_fd = null; + + /** + * Size of the underlying stream. + * + * @var integer + */ + protected $_size = 0; + + /** + * Constructs the Zend_Io_Reader class with given open file descriptor. + * + * @param resource $fd The file descriptor. + * @throws Zend_Io_Exception if given file descriptor is not valid + */ + public function __construct($fd) + { + if (!is_resource($fd) || + !in_array(get_resource_type($fd), array('stream'))) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Invalid resource type (only resources of type stream are supported)'); + } + + $this->_fd = $fd; + + $offset = $this->getOffset(); + fseek($this->_fd, 0, SEEK_END); + $this->_size = ftell($this->_fd); + fseek($this->_fd, $offset); + } + + /** + * Default destructor. + */ + public function __destruct() {} + + /** + * Checks whether there is more to be read from the stream. Returns + * true if the end has not yet been reached; false + * otherwise. + * + * @return boolean + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function available() + { + return $this->getOffset() < $this->getSize(); + } + + /** + * Returns the current point of operation. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function getOffset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return ftell($this->_fd); + } + + /** + * Sets the point of operation, ie the cursor offset value. The offset may + * also be set to a negative value when it is interpreted as an offset from + * the end of the stream instead of the beginning. + * + * @param integer $offset The new point of operation. + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function setOffset($offset) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); + } + + /** + * Returns the stream size in bytes. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + /** + * Returns the underlying stream file descriptor. + * + * @return resource + */ + public function getFileDescriptor() + { + return $this->_fd; + } + + /** + * Jumps size amount of bytes in the stream. + * + * @param integer $size The amount of bytes. + * @return void + * @throws Zend_Io_Exception if size attribute is negative or if + * an I/O error occurs + */ + public function skip($size) + { + if ($size < 0) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Size cannot be negative'); + } + if ($size == 0) { + return; + } + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $size, SEEK_CUR); + } + + /** + * Reads length amount of bytes from the stream. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public function read($length) + { + if ($length < 0) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Length cannot be negative'); + } + if ($length == 0) { + return ''; + } + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return fread($this->_fd, $length); + } + + /** + * Reads 1 byte from the stream and returns binary data as an 8-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt8() + { + $ord = ord($this->read(1)); + if ($ord > 127) { + return -$ord - 2 * (128 - $ord); + } else { + return $ord; + } + } + + /** + * Reads 1 byte from the stream and returns binary data as an unsigned 8-bit + * integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt8() + { + return ord($this->read(1)); + } + + /** + * Returns machine endian ordered binary data as signed 16-bit integer. + * + * @param string $value The binary data string. + * @return integer + */ + private function _fromInt16($value) + { + list(, $int) = unpack('s*', $value); + return $int; + } + + /** + * Reads 2 bytes from the stream and returns little-endian ordered binary + * data as signed 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt16LE() + { + if ($this->_isBigEndian()) { + return $this->_fromInt16(strrev($this->read(2))); + } else { + return $this->_fromInt16($this->read(2)); + } + } + + /** + * Reads 2 bytes from the stream and returns big-endian ordered binary data + * as signed 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt16BE() + { + if ($this->_isLittleEndian()) { + return $this->_fromInt16(strrev($this->read(2))); + } else { + return $this->_fromInt16($this->read(2)); + } + } + + /** + * Reads 2 bytes from the stream and returns machine ordered binary data + * as signed 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt16() + { + return $this->_fromInt16($this->read(2)); + } + + /** + * Returns machine endian ordered binary data as unsigned 16-bit integer. + * + * @param string $value The binary data string. + * @param integer $order The byte order of the binary data string. + * @return integer + */ + private function _fromUInt16($value, $order = 0) + { + list(, $int) = unpack + (($order == self::BIG_ENDIAN_ORDER ? 'n' : + ($order == self::LITTLE_ENDIAN_ORDER ? 'v' : 'S')) . '*', + $value); + return $int; + } + + /** + * Reads 2 bytes from the stream and returns little-endian ordered binary + * data as unsigned 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt16LE() + { + return $this->_fromUInt16($this->read(2), self::LITTLE_ENDIAN_ORDER); + } + + /** + * Reads 2 bytes from the stream and returns big-endian ordered binary data + * as unsigned 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt16BE() + { + return $this->_fromUInt16($this->read(2), self::BIG_ENDIAN_ORDER); + } + + /** + * Reads 2 bytes from the stream and returns machine ordered binary data + * as unsigned 16-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt16() + { + return $this->_fromUInt16($this->read(2), self::MACHINE_ENDIAN_ORDER); + } + + /** + * Returns machine endian ordered binary data as signed 24-bit integer. + * + * @param string $value The binary data string. + * @return integer + */ + private function _fromInt24($value) + { + list(, $int) = unpack('l*', $this->_isLittleEndian() ? ("\x00" . $value) : ($value . "\x00")); + return $int; + } + + /** + * Reads 3 bytes from the stream and returns little-endian ordered binary + * data as signed 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt24LE() + { + if ($this->_isBigEndian()) { + return $this->_fromInt24(strrev($this->read(3))); + } else { + return $this->_fromInt24($this->read(3)); + } + } + + /** + * Reads 3 bytes from the stream and returns big-endian ordered binary data + * as signed 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt24BE() + { + if ($this->_isLittleEndian()) { + return $this->_fromInt24(strrev($this->read(3))); + } else { + return $this->_fromInt24($this->read(3)); + } + } + + /** + * Reads 3 bytes from the stream and returns machine ordered binary data + * as signed 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt24() + { + return $this->_fromInt24($this->read(3)); + } + + /** + * Returns machine endian ordered binary data as unsigned 24-bit integer. + * + * @param string $value The binary data string. + * @param integer $order The byte order of the binary data string. + * @return integer + */ + private function _fromUInt24($value, $order = 0) + { + list(, $int) = unpack + (($order == self::BIG_ENDIAN_ORDER ? 'N' : + ($order == self::LITTLE_ENDIAN_ORDER ? 'V' : 'L')) . '*', + $this->_isLittleEndian() ? ("\x00" . $value) : ($value . "\x00")); + return $int; + } + + /** + * Reads 3 bytes from the stream and returns little-endian ordered binary + * data as unsigned 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt24LE() + { + return $this->_fromUInt24($this->read(3), self::LITTLE_ENDIAN_ORDER); + } + + /** + * Reads 3 bytes from the stream and returns big-endian ordered binary data + * as unsigned 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt24BE() + { + return $this->_fromUInt24($this->read(3), self::BIG_ENDIAN_ORDER); + } + + /** + * Reads 3 bytes from the stream and returns machine ordered binary data + * as unsigned 24-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt24() + { + return $this->_fromUInt24($this->read(3), self::MACHINE_ENDIAN_ORDER); + } + + /** + * Returns machine-endian ordered binary data as signed 32-bit integer. + * + * @param string $value The binary data string. + * @return integer + */ + private final function _fromInt32($value) + { + list(, $int) = unpack('l*', $value); + return $int; + } + + /** + * Reads 4 bytes from the stream and returns little-endian ordered binary + * data as signed 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt32LE() + { + if ($this->_isBigEndian()) + return $this->_fromInt32(strrev($this->read(4))); + else + return $this->_fromInt32($this->read(4)); + } + + /** + * Reads 4 bytes from the stream and returns big-endian ordered binary data + * as signed 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt32BE() + { + if ($this->_isLittleEndian()) + return $this->_fromInt32(strrev($this->read(4))); + else + return $this->_fromInt32($this->read(4)); + } + + /** + * Reads 4 bytes from the stream and returns machine ordered binary data + * as signed 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt32() + { + return $this->_fromInt32($this->read(4)); + } + + /** + * Reads 4 bytes from the stream and returns little-endian ordered binary + * data as unsigned 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt32LE() + { + if (PHP_INT_SIZE < 8) { + list(, $lo, $hi) = unpack('v*', $this->read(4)); + return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo + } else { + list(, $int) = unpack('V*', $this->read(4)); + return $int; + } + } + + /** + * Reads 4 bytes from the stream and returns big-endian ordered binary data + * as unsigned 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt32BE() + { + if (PHP_INT_SIZE < 8) { + list(, $hi, $lo) = unpack('n*', $this->read(4)); + return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo + } else { + list(, $int) = unpack('N*', $this->read(4)); + return $int; + } + } + + /** + * Reads 4 bytes from the stream and returns machine ordered binary data + * as unsigned 32-bit integer. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readUInt32() + { + if (PHP_INT_SIZE < 8) { + list(, $hi, $lo) = unpack('L*', $this->read(4)); + return $hi * (0xffff+1) + $lo; // eq $hi << 16 | $lo + } else { + list(, $int) = unpack('L*', $this->read(4)); + return $int; + } + } + + /** + * Reads 8 bytes from the stream and returns little-endian ordered binary + * data as 64-bit float. + * + * {@internal PHP does not support 64-bit integers as the long + * integer is of 32-bits but using aritmetic operations it is implicitly + * converted into floating point which is of 64-bits long.}} + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt64LE() + { + list(, $lolo, $lohi, $hilo, $hihi) = unpack('v*', $this->read(8)); + return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + + ($lohi * (0xffff+1) + $lolo); + } + + /** + * Reads 8 bytes from the stream and returns big-endian ordered binary data + * as 64-bit float. + * + * {@internal PHP does not support 64-bit integers as the long integer is of + * 32-bits but using aritmetic operations it is implicitly converted into + * floating point which is of 64-bits long.}} + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readInt64BE() + { + list(, $hihi, $hilo, $lohi, $lolo) = unpack('n*', $this->read(8)); + return ($hihi * (0xffff+1) + $hilo) * (0xffffffff+1) + + ($lohi * (0xffff+1) + $lolo); + } + + /** + * Returns machine endian ordered binary data as a 32-bit floating point + * number as defined by IEEE 754. + * + * @param string $value The binary data string. + * @return float + */ + private function _fromFloat($value) + { + list(, $float) = unpack('f', $value); + return $float; + } + + /** + * Reads 4 bytes from the stream and returns little-endian ordered binary + * data as a 32-bit float point number as defined by IEEE 754. + * + * @return float + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readFloatLE() + { + if ($this->_isBigEndian()) { + return $this->_fromFloat(strrev($this->read(4))); + } else { + return $this->_fromFloat($this->read(4)); + } + } + + /** + * Reads 4 bytes from the stream and returns big-endian ordered binary data + * as a 32-bit float point number as defined by IEEE 754. + * + * @return float + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readFloatBE() + { + if ($this->_isLittleEndian()) { + return $this->_fromFloat(strrev($this->read(4))); + } else { + return $this->_fromFloat($this->read(4)); + } + } + + /** + * Returns machine endian ordered binary data as a 64-bit floating point + * number as defined by IEEE754. + * + * @param string $value The binary data string. + * @return float + */ + private function _fromDouble($value) + { + list(, $double) = unpack('d', $value); + return $double; + } + + /** + * Reads 8 bytes from the stream and returns little-endian ordered binary + * data as a 64-bit floating point number as defined by IEEE 754. + * + * @return float + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readDoubleLE() + { + if ($this->_isBigEndian()) { + return $this->_fromDouble(strrev($this->read(8))); + } else { + return $this->_fromDouble($this->read(8)); + } + } + + /** + * Reads 8 bytes from the stream and returns big-endian ordered binary data + * as a 64-bit float point number as defined by IEEE 754. + * + * @return float + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readDoubleBE() + { + if ($this->_isLittleEndian()) { + return $this->_fromDouble(strrev($this->read(8))); + } else { + return $this->_fromDouble($this->read(8)); + } + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as string. Removes terminating zero. + * + * @param integer $length The amount of bytes. + * @param string $charList The list of characters you want to strip. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readString8($length, $charList = "\0") + { + return rtrim($this->read($length), $charList); + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as multibyte Unicode string. Removes terminating zero. + * + * The byte order is possibly determined from the byte order mark included + * in the binary data string. The order parameter is updated if the BOM is + * found. + * + * @param integer $length The amount of bytes. + * @param integer $order The endianess of the string. + * @param integer $trimOrder Whether to remove the byte order mark read the + * string. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readString16 + ($length, &$order = null, $trimOrder = false) + { + $value = $this->read($length); + + if (strlen($value) < 2) { + return ''; + } + + if (ord($value[0]) == 0xfe && ord($value[1]) == 0xff) { + $order = self::BIG_ENDIAN_ORDER; + if ($trimOrder) { + $value = substr($value, 2); + } + } + if (ord($value[0]) == 0xff && ord($value[1]) == 0xfe) { + $order = self::LITTLE_ENDIAN_ORDER; + if ($trimOrder) { + $value = substr($value, 2); + } + } + + while (substr($value, -2) == "\0\0") { + $value = substr($value, 0, -2); + } + + return $value; + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as hexadecimal string having high nibble first. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readHHex($length) + { + list($hex) = unpack('H*0', $this->read($length)); + return $hex; + } + + /** + * Reads length amount of bytes from the stream and returns + * binary data as hexadecimal string having low nibble first. + * + * @param integer $length The amount of bytes. + * @return string + * @throws Zend_Io_Exception if length attribute is negative or + * if an I/O error occurs + */ + public final function readLHex($length) + { + list($hex) = unpack('h*0', $this->read($length)); + return $hex; + } + + /** + * Reads 16 bytes from the stream and returns the little-endian ordered + * binary data as mixed-ordered hexadecimal GUID string. + * + * @return string + * @throws Zend_Io_Exception if an I/O error occurs + */ + public final function readGuid() + { + $C = @unpack('V1V/v2v/N2N', $this->read(16)); + list($hex) = @unpack('H*0', pack + ('NnnNN', $C['V'], $C['v1'], $C['v2'], $C['N1'], $C['N2'])); + + /* Fixes a bug in PHP versions earlier than Jan 25 2006 */ + if (implode('', unpack('H*', pack('H*', 'a'))) == 'a00') { + $hex = substr($hex, 0, -1); + } + + return preg_replace + ('/^(.{8})(.{4})(.{4})(.{4})/', "\\1-\\2-\\3-\\4-", $hex); + } + + /** + * Resets the stream. Attempts to reset it in some way appropriate to the + * particular stream, for example by repositioning it to its starting point. + * + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function reset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, 0); + } + + /** + * Closes the stream. Once a stream has been closed, further calls to read + * methods will throw an exception. Closing a previously-closed stream, + * however, has no effect. + * + * @return void + */ + public function close() + { + if ($this->_fd !== null) { + @fclose($this->_fd); + $this->_fd = null; + } + } + + /** + * Returns the current machine endian order. + * + * @return integer + */ + private function _getEndianess() + { + if (self::$_endianess === 0) { + self::$_endianess = $this->_fromInt32("\x01\x00\x00\x00") == 1 ? + self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; + } + return self::$_endianess; + } + + /** + * Returns whether the current machine endian order is little endian. + * + * @return boolean + */ + private function _isLittleEndian() + { + return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; + } + + /** + * Returns whether the current machine endian order is big endian. + * + * @return boolean + */ + private function _isBigEndian() + { + return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func + (array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Io/StringReader.php b/app/libs/vendor/Zend/Io/StringReader.php index 81ee6716..fb85c661 100644 --- a/app/libs/vendor/Zend/Io/StringReader.php +++ b/app/libs/vendor/Zend/Io/StringReader.php @@ -1,86 +1,86 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StringReader.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_StringReader extends Zend_Io_Reader -{ - /** - * Constructs the Zend_Io_StringReader class with given source string. - * - * @param string $data The string to use as the source. - * @param integer $length If the length argument is given, - * reading will stop after length bytes have been read or - * the end of string is reached, whichever comes first. - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function __construct($data, $length = null) - { - if (($this->_fd = fopen('php://memory', 'w+b')) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unable to open php://memory stream'); - } - if ($data !== null && is_string($data)) { - if ($length === null) { - $length = strlen($data); - } - if (($this->_size = fwrite($this->_fd, $data, $length)) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Unable to write data to php://memory stream'); - } - fseek($this->_fd, 0); - } - } - - /** - * Returns the string representation of this class. - */ - public function toString() - { - $offset = $this->getOffset(); - $this->setOffset(0); - $data = $this->read($this->getSize()); - $this->setOffset($offset); - return $data; - } - - /** - * Closes the file descriptor. - */ - public function __destruct() - { - $this->close(); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StringReader.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_StringReader extends Zend_Io_Reader +{ + /** + * Constructs the Zend_Io_StringReader class with given source string. + * + * @param string $data The string to use as the source. + * @param integer $length If the length argument is given, + * reading will stop after length bytes have been read or + * the end of string is reached, whichever comes first. + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function __construct($data, $length = null) + { + if (($this->_fd = fopen('php://memory', 'w+b')) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open php://memory stream'); + } + if ($data !== null && is_string($data)) { + if ($length === null) { + $length = strlen($data); + } + if (($this->_size = fwrite($this->_fd, $data, $length)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Unable to write data to php://memory stream'); + } + fseek($this->_fd, 0); + } + } + + /** + * Returns the string representation of this class. + */ + public function toString() + { + $offset = $this->getOffset(); + $this->setOffset(0); + $data = $this->read($this->getSize()); + $this->setOffset($offset); + return $data; + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/app/libs/vendor/Zend/Io/StringWriter.php b/app/libs/vendor/Zend/Io/StringWriter.php index 44810c50..595ae7fd 100644 --- a/app/libs/vendor/Zend/Io/StringWriter.php +++ b/app/libs/vendor/Zend/Io/StringWriter.php @@ -1,89 +1,89 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StringWriter.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_StringWriter extends Zend_Io_Writer -{ - /** - * Constructs the Zend_Io_StringWriter class with given source string. - * - * @param string $data The string to use as the source. - * @param integer $length If the length argument is given, - * reading will stop after length bytes have been read or - * the end of string is reached, whichever comes first. - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function __construct($data = null, $length = null) - { - if (($this->_fd = fopen('php://memory', 'w+b')) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unable to open php://memory stream'); - } - if ($data !== null && is_string($data)) { - if ($length === null) { - $length = strlen($data); - } - if (($this->_size = fwrite($this->_fd, $data, $length)) === false) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Unable to write data to php://memory stream'); - } - fseek($this->_fd, 0); - } - } - - /** - * Returns the string representation of this class. - */ - public function toString() - { - if ($this->getSize() == 0) { - return ''; - } - $offset = $this->getOffset(); - $this->setOffset(0); - $data = fread($this->getFileDescriptor(), $this->getSize()); - $this->setOffset($offset); - return $data; - } - - /** - * Closes the file descriptor. - */ - public function __destruct() - { - $this->close(); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StringWriter.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_StringWriter extends Zend_Io_Writer +{ + /** + * Constructs the Zend_Io_StringWriter class with given source string. + * + * @param string $data The string to use as the source. + * @param integer $length If the length argument is given, + * reading will stop after length bytes have been read or + * the end of string is reached, whichever comes first. + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function __construct($data = null, $length = null) + { + if (($this->_fd = fopen('php://memory', 'w+b')) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unable to open php://memory stream'); + } + if ($data !== null && is_string($data)) { + if ($length === null) { + $length = strlen($data); + } + if (($this->_size = fwrite($this->_fd, $data, $length)) === false) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Unable to write data to php://memory stream'); + } + fseek($this->_fd, 0); + } + } + + /** + * Returns the string representation of this class. + */ + public function toString() + { + if ($this->getSize() == 0) { + return ''; + } + $offset = $this->getOffset(); + $this->setOffset(0); + $data = fread($this->getFileDescriptor(), $this->getSize()); + $this->setOffset($offset); + return $data; + } + + /** + * Closes the file descriptor. + */ + public function __destruct() + { + $this->close(); + } +} diff --git a/app/libs/vendor/Zend/Io/Writer.php b/app/libs/vendor/Zend/Io/Writer.php index a003f766..31a11298 100644 --- a/app/libs/vendor/Zend/Io/Writer.php +++ b/app/libs/vendor/Zend/Io/Writer.php @@ -1,631 +1,631 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Writer.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Io_Writer -{ - const MACHINE_ENDIAN_ORDER = 0; - const LITTLE_ENDIAN_ORDER = 1; - const BIG_ENDIAN_ORDER = 2; - - /** - * The endianess of the current machine. - * - * @var integer - */ - private static $_endianess = 0; - - /** - * The resource identifier of the stream. - * - * @var resource - */ - protected $_fd = null; - - /** - * Size of the underlying stream. - * - * @var integer - */ - protected $_size = 0; - - /** - * Constructs the Zend_Io_Writer class with given open file descriptor. - * - * @param resource $fd The file descriptor. - * @throws Zend_Io_Exception if file descriptor is not valid - */ - public function __construct($fd) - { - if (!is_resource($fd) || - !in_array(get_resource_type($fd), array('stream'))) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception - ('Invalid resource type (only resources of type stream are supported)'); - } - - $this->_fd = $fd; - - $offset = $this->getOffset(); - fseek($this->_fd, 0, SEEK_END); - $this->_size = ftell($this->_fd); - fseek($this->_fd, $offset); - } - - /** - * Default destructor. - */ - public function __destruct() {} - - /** - * Returns the current point of operation. - * - * @return integer - * @throws Zend_Io_Exception if the stream is closed - */ - public function getOffset() - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - return ftell($this->_fd); - } - - /** - * Sets the point of operation, ie the cursor offset value. The offset may - * also be set to a negative value when it is interpreted as an offset from - * the end of the stream instead of the beginning. - * - * @param integer $offset The new point of operation. - * @return void - * @throws Zend_Io_Exception if the stream is closed - */ - public function setOffset($offset) - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); - } - - /** - * Returns the stream size in bytes. - * - * @return integer - * @throws Zend_Io_Exception if the stream is closed - */ - public function getSize() - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - return $this->_size; - } - - /** - * Sets the stream size in bytes, and truncates if required. - * - * @param integer $size The new size - * @return void - * @throws Zend_Io_Exception if the stream is closed - */ - public function setSize($size) - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - ftruncate($this->_fd, $size); - } - - /** - * Returns the underlying stream file descriptor. - * - * @return resource - */ - public function getFileDescriptor() - { - return $this->_fd; - } - - /** - * Writes value up to length bytes to the stream. - * - * @param string $value The value to write to the stream. - * @param integer $length The number of bytes to write. Defaults to the - * length of the given value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public function write($value, $length = null) - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - if ($length === null) { - $length = strlen($value); - } - fwrite($this->_fd, $value, $length); - $this->_size += $length; - return $this; - } - - /** - * Writes an 8-bit integer as binary data to the stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt8($value) - { - return $this->write(pack('c*', $value)); - } - - /** - * Writes an unsigned 8-bit integer as binary data to the stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeUInt8($value) - { - return $this->write(pack('C*', $value)); - } - - /** - * Returns signed 16-bit integer as machine endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - private function _toInt16($value) - { - return pack('s*', $value); - } - - /** - * Writes a signed 16-bit integer as little-endian ordered binary data to - * the stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt16LE($value) - { - if ($this->_isLittleEndian()) { - return $this->write(strrev($this->_toInt16($value))); - } else { - return $this->write($this->_toInt16($value)); - } - } - - /** - * Returns signed 16-bit integer as big-endian ordered binary data to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt16BE($value) - { - if ($this->_isBigEndian()) { - return $this->write(strrev($this->_toInt16($value))); - } else { - return $this->write($this->_toInt16($value)); - } - } - - /** - * Writes unsigned 16-bit integer as little-endian ordered binary data - * to the stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeUInt16LE($value) - { - return $this->write(pack('v*', $value)); - } - - /** - * Writes unsigned 16-bit integer as big-endian ordered binary data to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeUInt16BE($value) - { - return $this->write(pack('n*', $value)); - } - - /** - * Returns signed 32-bit integer as machine-endian ordered binary data. - * - * @param integer $value The input value. - * @return string - */ - private final function _toInt32($value) - { - return pack('l*', $value); - } - - /** - * Writes signed 32-bit integer as little-endian ordered binary data to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt32LE($value) - { - if ($this->_isLittleEndian()) { - return $this->write(strrev($this->_toInt32($value))); - } else { - return $this->write($this->_toInt32($value)); - } - } - - /** - * Writes signed 32-bit integer as big-endian ordered binary data to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt32BE($value) - { - if ($this->_isBigEndian()) { - return $this->write(strrev($this->_toInt32($value))); - } else { - return $this->write($this->_toInt32($value)); - } - } - - /** - * Writes unsigned 32-bit integer as little-endian ordered binary data to - * the stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeUInt32LE($value) - { - return $this->write(pack('V*', $value)); - } - - /** - * Writes unsigned 32-bit integer as big-endian ordered binary data to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeUInt32BE($value) - { - return $this->write(pack('N*', $value)); - } - - /** - * Writes 64-bit float as little-endian ordered binary data string to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt64LE($value) - { - return $this->write - (pack('V*', $value & 0xffffffff, $value / (0xffffffff+1))); - } - - /** - * Writes 64-bit float as big-endian ordered binary data string to the - * stream. - * - * @param integer $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeInt64BE($value) - { - return $this->write - (pack('N*', $value / (0xffffffff+1), $value & 0xffffffff)); - } - - /** - * Returns a floating point number as machine endian ordered binary data. - * - * @param float $value The input value. - * @return string - */ - private function _toFloat($value) - { - return pack('f*', $value); - } - - /** - * Writes a floating point number as little-endian ordered binary data to - * the stream. - * - * @param float $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeFloatLE($value) - { - if ($this->_isLittleEndian()) { - return $this->write(strrev($this->_toFloat($value))); - } else { - return $this->write($this->_toFloat($value)); - } - } - - /** - * Writes a floating point number as big-endian ordered binary data to the - * stream. - * - * @param float $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeFloatBE($value) - { - if ($this->_isBigEndian()) { - return $this->write(strrev($this->_toFloat($value))); - } else { - return $this->write($this->_toFloat($value)); - } - } - - /** - * Writes string as binary data padded to given length with zeros. If - * length is smaller than the length of the string, it is - * considered as the length of the padding. - * - * @param string $value The input value. - * @param integer $length The length to which to pad the value. - * @param string $padding The padding character. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeString8($value, $length = null, $padding = "\0") - { - if ($length === null) { - $length = strlen($value); - } - if ($length < ($tmp = strlen($value))) { - $length = $tmp + $length; - } - return $this->write(str_pad($value, $length, $padding)); - } - - /** - * Writes the multibyte string as binary data with given byte order mark - * (BOM) and padded to given length with zeros. Length is given in unicode - * characters so each character adds two zeros to the string. If length is - * smaller than the length of the string, it is considered as the length of - * the padding. - * - * If byte order mark is null no mark is inserted to the binary - * data. - * - * @param string $value The input value. - * @param integer $order The byte order of the binary data string. - * @param integer $length The length to which to pad the value. - * @param string $padding The padding character. - * @return string - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeString16 - ($value, $order = null, $length = null, $padding = "\0") - { - if ($length === null) { - $length = (int)(strlen($value) / 2); - } - if ($length < ($tmp = strlen($value) / 2)) { - $length = $tmp + $length; - } - if ($order == self::BIG_ENDIAN_ORDER && - !(ord($value[0]) == 0xfe && ord($value[1]) == 0xff)) { - $value = 0xfeff . $value; - $length++; - } - if ($order == self::LITTLE_ENDIAN_ORDER && - !(ord($value[0]) == 0xff && ord($value[1]) == 0xfe)) { - $value = 0xfffe . $value; - $length++; - } - return $this->write(str_pad($value, $length * 2, $padding)); - } - - /** - * Writes hexadecimal string having high nibble first as binary data to the - * stream. - * - * @param string $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if length attribute is negative or - * if the stream is closed - */ - public final function writeHHex($value) - { - return $this->write(pack('H*', $value)); - } - - /** - * Writes hexadecimal string having low nibble first as binary data to the - * stream. - * - * @param string $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if length attribute is negative or - * if the stream is closed - */ - public final function writeLHex($value) - { - return $this->write(pack('h*', $value)); - } - - /** - * Writes big-endian ordered hexadecimal GUID string as little-endian - * ordered binary data string to the stream. - * - * @param string $value The input value. - * @return Zend_Io_Writer - * @throws Zend_Io_Exception if the stream is closed - */ - public final function writeGuid($value) - { - $string = ''; - $C = preg_split('/-/', $value); - return $this->write - (pack - ('V1v2N2', hexdec($C[0]), hexdec($C[1]), hexdec($C[2]), - hexdec($C[3] . substr($C[4], 0, 4)), hexdec(substr($C[4], 4)))); - } - - /** - * Forces write of all buffered output to the underlying resource. - * - * @return void - * @throws Zend_Io_Exception if the stream is closed - */ - public function flush() - { - if ($this->_fd === null) { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Cannot operate on a closed stream'); - } - fflush($this->_fd); - } - - /** - * Closes the stream. Once a stream has been closed, further calls to write - * methods will throw an exception. Closing a previously-closed stream, - * however, has no effect. - * - * @return void - * @throws Zend_Io_Exception if the stream is closed - */ - public function close() - { - if ($this->_fd !== null) { - @fclose($this->_fd); - $this->_fd = null; - } - } - - /** - * Returns the current machine endian order. - * - * @return integer - */ - private function _getEndianess() - { - if (self::$_endianess === 0) { - self::$_endianess = $this->_toInt32("\x01\x00\x00\x00") == 1 ? - self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; - } - return self::$_endianess; - } - - /** - * Returns whether the current machine endian order is little endian. - * - * @return boolean - */ - private function _isLittleEndian() - { - return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; - } - - /** - * Returns whether the current machine endian order is big endian. - * - * @return boolean - */ - private function _isBigEndian() - { - return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { - return call_user_func - (array($this, 'get' . ucfirst(strtolower($name)))); - } else { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { - call_user_func - (array($this, 'set' . ucfirst(strtolower($name))), $value); - } else { - require_once('Zend/Io/Exception.php'); - throw new Zend_Io_Exception('Unknown field: ' . $name); - } - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Writer.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Io_Writer +{ + const MACHINE_ENDIAN_ORDER = 0; + const LITTLE_ENDIAN_ORDER = 1; + const BIG_ENDIAN_ORDER = 2; + + /** + * The endianess of the current machine. + * + * @var integer + */ + private static $_endianess = 0; + + /** + * The resource identifier of the stream. + * + * @var resource + */ + protected $_fd = null; + + /** + * Size of the underlying stream. + * + * @var integer + */ + protected $_size = 0; + + /** + * Constructs the Zend_Io_Writer class with given open file descriptor. + * + * @param resource $fd The file descriptor. + * @throws Zend_Io_Exception if file descriptor is not valid + */ + public function __construct($fd) + { + if (!is_resource($fd) || + !in_array(get_resource_type($fd), array('stream'))) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception + ('Invalid resource type (only resources of type stream are supported)'); + } + + $this->_fd = $fd; + + $offset = $this->getOffset(); + fseek($this->_fd, 0, SEEK_END); + $this->_size = ftell($this->_fd); + fseek($this->_fd, $offset); + } + + /** + * Default destructor. + */ + public function __destruct() {} + + /** + * Returns the current point of operation. + * + * @return integer + * @throws Zend_Io_Exception if the stream is closed + */ + public function getOffset() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return ftell($this->_fd); + } + + /** + * Sets the point of operation, ie the cursor offset value. The offset may + * also be set to a negative value when it is interpreted as an offset from + * the end of the stream instead of the beginning. + * + * @param integer $offset The new point of operation. + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function setOffset($offset) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fseek($this->_fd, $offset < 0 ? $this->getSize() + $offset : $offset); + } + + /** + * Returns the stream size in bytes. + * + * @return integer + * @throws Zend_Io_Exception if the stream is closed + */ + public function getSize() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + return $this->_size; + } + + /** + * Sets the stream size in bytes, and truncates if required. + * + * @param integer $size The new size + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function setSize($size) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + ftruncate($this->_fd, $size); + } + + /** + * Returns the underlying stream file descriptor. + * + * @return resource + */ + public function getFileDescriptor() + { + return $this->_fd; + } + + /** + * Writes value up to length bytes to the stream. + * + * @param string $value The value to write to the stream. + * @param integer $length The number of bytes to write. Defaults to the + * length of the given value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public function write($value, $length = null) + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + if ($length === null) { + $length = strlen($value); + } + fwrite($this->_fd, $value, $length); + $this->_size += $length; + return $this; + } + + /** + * Writes an 8-bit integer as binary data to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt8($value) + { + return $this->write(pack('c*', $value)); + } + + /** + * Writes an unsigned 8-bit integer as binary data to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt8($value) + { + return $this->write(pack('C*', $value)); + } + + /** + * Returns signed 16-bit integer as machine endian ordered binary data. + * + * @param integer $value The input value. + * @return string + */ + private function _toInt16($value) + { + return pack('s*', $value); + } + + /** + * Writes a signed 16-bit integer as little-endian ordered binary data to + * the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt16LE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toInt16($value))); + } else { + return $this->write($this->_toInt16($value)); + } + } + + /** + * Returns signed 16-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt16BE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toInt16($value))); + } else { + return $this->write($this->_toInt16($value)); + } + } + + /** + * Writes unsigned 16-bit integer as little-endian ordered binary data + * to the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt16LE($value) + { + return $this->write(pack('v*', $value)); + } + + /** + * Writes unsigned 16-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt16BE($value) + { + return $this->write(pack('n*', $value)); + } + + /** + * Returns signed 32-bit integer as machine-endian ordered binary data. + * + * @param integer $value The input value. + * @return string + */ + private final function _toInt32($value) + { + return pack('l*', $value); + } + + /** + * Writes signed 32-bit integer as little-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt32LE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toInt32($value))); + } else { + return $this->write($this->_toInt32($value)); + } + } + + /** + * Writes signed 32-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt32BE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toInt32($value))); + } else { + return $this->write($this->_toInt32($value)); + } + } + + /** + * Writes unsigned 32-bit integer as little-endian ordered binary data to + * the stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt32LE($value) + { + return $this->write(pack('V*', $value)); + } + + /** + * Writes unsigned 32-bit integer as big-endian ordered binary data to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeUInt32BE($value) + { + return $this->write(pack('N*', $value)); + } + + /** + * Writes 64-bit float as little-endian ordered binary data string to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt64LE($value) + { + return $this->write + (pack('V*', $value & 0xffffffff, $value / (0xffffffff+1))); + } + + /** + * Writes 64-bit float as big-endian ordered binary data string to the + * stream. + * + * @param integer $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeInt64BE($value) + { + return $this->write + (pack('N*', $value / (0xffffffff+1), $value & 0xffffffff)); + } + + /** + * Returns a floating point number as machine endian ordered binary data. + * + * @param float $value The input value. + * @return string + */ + private function _toFloat($value) + { + return pack('f*', $value); + } + + /** + * Writes a floating point number as little-endian ordered binary data to + * the stream. + * + * @param float $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeFloatLE($value) + { + if ($this->_isLittleEndian()) { + return $this->write(strrev($this->_toFloat($value))); + } else { + return $this->write($this->_toFloat($value)); + } + } + + /** + * Writes a floating point number as big-endian ordered binary data to the + * stream. + * + * @param float $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeFloatBE($value) + { + if ($this->_isBigEndian()) { + return $this->write(strrev($this->_toFloat($value))); + } else { + return $this->write($this->_toFloat($value)); + } + } + + /** + * Writes string as binary data padded to given length with zeros. If + * length is smaller than the length of the string, it is + * considered as the length of the padding. + * + * @param string $value The input value. + * @param integer $length The length to which to pad the value. + * @param string $padding The padding character. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeString8($value, $length = null, $padding = "\0") + { + if ($length === null) { + $length = strlen($value); + } + if ($length < ($tmp = strlen($value))) { + $length = $tmp + $length; + } + return $this->write(str_pad($value, $length, $padding)); + } + + /** + * Writes the multibyte string as binary data with given byte order mark + * (BOM) and padded to given length with zeros. Length is given in unicode + * characters so each character adds two zeros to the string. If length is + * smaller than the length of the string, it is considered as the length of + * the padding. + * + * If byte order mark is null no mark is inserted to the binary + * data. + * + * @param string $value The input value. + * @param integer $order The byte order of the binary data string. + * @param integer $length The length to which to pad the value. + * @param string $padding The padding character. + * @return string + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeString16 + ($value, $order = null, $length = null, $padding = "\0") + { + if ($length === null) { + $length = (int)(strlen($value) / 2); + } + if ($length < ($tmp = strlen($value) / 2)) { + $length = $tmp + $length; + } + if ($order == self::BIG_ENDIAN_ORDER && + !(ord($value[0]) == 0xfe && ord($value[1]) == 0xff)) { + $value = 0xfeff . $value; + $length++; + } + if ($order == self::LITTLE_ENDIAN_ORDER && + !(ord($value[0]) == 0xff && ord($value[1]) == 0xfe)) { + $value = 0xfffe . $value; + $length++; + } + return $this->write(str_pad($value, $length * 2, $padding)); + } + + /** + * Writes hexadecimal string having high nibble first as binary data to the + * stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if length attribute is negative or + * if the stream is closed + */ + public final function writeHHex($value) + { + return $this->write(pack('H*', $value)); + } + + /** + * Writes hexadecimal string having low nibble first as binary data to the + * stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if length attribute is negative or + * if the stream is closed + */ + public final function writeLHex($value) + { + return $this->write(pack('h*', $value)); + } + + /** + * Writes big-endian ordered hexadecimal GUID string as little-endian + * ordered binary data string to the stream. + * + * @param string $value The input value. + * @return Zend_Io_Writer + * @throws Zend_Io_Exception if the stream is closed + */ + public final function writeGuid($value) + { + $string = ''; + $C = preg_split('/-/', $value); + return $this->write + (pack + ('V1v2N2', hexdec($C[0]), hexdec($C[1]), hexdec($C[2]), + hexdec($C[3] . substr($C[4], 0, 4)), hexdec(substr($C[4], 4)))); + } + + /** + * Forces write of all buffered output to the underlying resource. + * + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function flush() + { + if ($this->_fd === null) { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Cannot operate on a closed stream'); + } + fflush($this->_fd); + } + + /** + * Closes the stream. Once a stream has been closed, further calls to write + * methods will throw an exception. Closing a previously-closed stream, + * however, has no effect. + * + * @return void + * @throws Zend_Io_Exception if the stream is closed + */ + public function close() + { + if ($this->_fd !== null) { + @fclose($this->_fd); + $this->_fd = null; + } + } + + /** + * Returns the current machine endian order. + * + * @return integer + */ + private function _getEndianess() + { + if (self::$_endianess === 0) { + self::$_endianess = $this->_toInt32("\x01\x00\x00\x00") == 1 ? + self::LITTLE_ENDIAN_ORDER : self::BIG_ENDIAN_ORDER; + } + return self::$_endianess; + } + + /** + * Returns whether the current machine endian order is little endian. + * + * @return boolean + */ + private function _isLittleEndian() + { + return $this->_getEndianess() == self::LITTLE_ENDIAN_ORDER; + } + + /** + * Returns whether the current machine endian order is big endian. + * + * @return boolean + */ + private function _isBigEndian() + { + return $this->_getEndianess() == self::BIG_ENDIAN_ORDER; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func + (array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Io/Exception.php'); + throw new Zend_Io_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf.php b/app/libs/vendor/Zend/Media/Asf.php index 08659a24..aa147da4 100644 --- a/app/libs/vendor/Zend/Media/Asf.php +++ b/app/libs/vendor/Zend/Media/Asf.php @@ -1,222 +1,222 @@ - - * @author Elias Haapamäki - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Asf.php 272 2012-03-29 19:53:29Z svollbehr $ - */ -class Zend_Media_Asf extends Zend_Media_Asf_Object_Container -{ - /** @var string */ - private $_filename; - - /** - * Constructs the ASF class with given file and options. - * - * The following options are currently recognized: - * o encoding -- Indicates the encoding that all the texts are presented - * with. By default this is set to utf-8. See the documentation of iconv - * for accepted values. - * o readonly -- Indicates that the file is read from a temporary location - * or another source it cannot be written back to. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Asf_Exception($e->getMessage()); - } - if (is_string($filename) && !isset($options['readonly'])) { - $this->_filename = $filename; - } - } - $this->setOptions($options); - if ($this->getOption('encoding', null) === null) { - $this->setOption('encoding', 'utf-8'); - } - $this->setOffset(0); - $this->setSize($this->_reader->getSize()); - $this->constructObjects - (array - (self::HEADER => 'Header', - self::DATA => 'Data', - self::SIMPLE_INDEX => 'SimpleIndex', - self::INDEX => 'Index', - self::MEDIA_OBJECT_INDEX => 'MediaObjectIndex', - self::TIMECODE_INDEX => 'TimecodeIndex')); - } - - /** - * Returns the mandatory header object contained in this file. - * - * @return Zend_Media_Asf_Object_Header - */ - public function getHeader() - { - $header = $this->getObjectsByIdentifier(self::HEADER); - return $header[0]; - } - - /** - * Returns the mandatory data object contained in this file. - * - * @return Zend_Media_Asf_Object_Data - */ - public function getData() - { - $data = $this->getObjectsByIdentifier(self::DATA); - return $data[0]; - } - - /** - * Returns an array of index objects contained in this file. - * - * @return Array - */ - public function getIndices() - { - return $this->getObjectsByIdentifier - (self::SIMPLE_INDEX . '|' . self::INDEX . '|' . - self::MEDIA_OBJECT_INDEX . '|' . self::TIMECODE_INDEX); - } - - /** - * Writes the changes to given media file. All object offsets must be - * assumed to be invalid after the write operation. - * - * @param string $filename The optional path to the file, use null to save - * to the same file. - */ - public function write($filename) - { - if ($filename === null && ($filename = $this->_filename) === null) { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception - ('No file given to write to'); - } else if ($filename !== null && $this->_filename !== null && - realpath($filename) != realpath($this->_filename) && - !copy($this->_filename, $filename)) { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception - ('Unable to copy source to destination: ' . - realpath($this->_filename) . '->' . realpath($filename)); - } - - if (($fd = fopen - ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception - ('Unable to open file for writing: ' . $filename); - } - - $header = $this->getHeader(); - $headerLengthOld = $header->getSize(); - $header->removeObjectsByIdentifier(Zend_Media_Asf_Object::PADDING); - $header->headerExtension->removeObjectsByIdentifier - (Zend_Media_Asf_Object::PADDING); - - require_once 'Zend/Io/StringWriter.php'; - $buffer = new Zend_Io_StringWriter(); - $header->write($buffer); - $headerData = $buffer->toString(); - $headerLengthNew = $header->getSize(); - - // Fits right in - if ($headerLengthOld == $headerLengthNew) { - } - - // Fits with adjusted padding - else if ($headerLengthOld >= $headerLengthNew + 24 /* for header */) { - $header->headerExtension->padding->setSize - ($headerLengthOld - $headerLengthNew); - $buffer = new Zend_Io_StringWriter(); - $header->write($buffer); - $headerData = $buffer->toString(); - $headerLengthNew = $header->getSize(); - } - - // Must expand - else { - $header->headerExtension->padding->setSize(4096); - $buffer = new Zend_Io_StringWriter(); - $header->write($buffer); - $headerData = $buffer->toString(); - $headerLengthNew = $header->getSize(); - - fseek($fd, 0, SEEK_END); - $oldFileSize = ftell($fd); - ftruncate - ($fd, $newFileSize = $headerLengthNew - $headerLengthOld + - $oldFileSize); - for ($i = 1, $cur = $oldFileSize; $cur > 0; $cur -= 1024, $i++) { - if ($cur >= 1024) { - fseek($fd, -(($i * 1024) + - ($newFileSize - $oldFileSize)), SEEK_END); - $buffer = fread($fd, 1024); - fseek($fd, -($i * 1024), SEEK_END); - fwrite($fd, $buffer, 1024); - } else { - fseek($fd, 0); - $buffer = fread($fd, $cur); - fseek($fd, $newFileSize - $oldFileSize); - fwrite($fd, $buffer, $cur); - } - } - } - - fseek($fd, 0); - fwrite($fd, $headerData, $headerLengthNew); - fclose($fd); - } -} + + * @author Elias Haapamäki + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Asf.php 272 2012-03-29 19:53:29Z svollbehr $ + */ +class Zend_Media_Asf extends Zend_Media_Asf_Object_Container +{ + /** @var string */ + private $_filename; + + /** + * Constructs the ASF class with given file and options. + * + * The following options are currently recognized: + * o encoding -- Indicates the encoding that all the texts are presented + * with. By default this is set to utf-8. See the documentation of iconv + * for accepted values. + * o readonly -- Indicates that the file is read from a temporary location + * or another source it cannot be written back to. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Asf_Exception($e->getMessage()); + } + if (is_string($filename) && !isset($options['readonly'])) { + $this->_filename = $filename; + } + } + $this->setOptions($options); + if ($this->getOption('encoding', null) === null) { + $this->setOption('encoding', 'utf-8'); + } + $this->setOffset(0); + $this->setSize($this->_reader->getSize()); + $this->constructObjects + (array + (self::HEADER => 'Header', + self::DATA => 'Data', + self::SIMPLE_INDEX => 'SimpleIndex', + self::INDEX => 'Index', + self::MEDIA_OBJECT_INDEX => 'MediaObjectIndex', + self::TIMECODE_INDEX => 'TimecodeIndex')); + } + + /** + * Returns the mandatory header object contained in this file. + * + * @return Zend_Media_Asf_Object_Header + */ + public function getHeader() + { + $header = $this->getObjectsByIdentifier(self::HEADER); + return $header[0]; + } + + /** + * Returns the mandatory data object contained in this file. + * + * @return Zend_Media_Asf_Object_Data + */ + public function getData() + { + $data = $this->getObjectsByIdentifier(self::DATA); + return $data[0]; + } + + /** + * Returns an array of index objects contained in this file. + * + * @return Array + */ + public function getIndices() + { + return $this->getObjectsByIdentifier + (self::SIMPLE_INDEX . '|' . self::INDEX . '|' . + self::MEDIA_OBJECT_INDEX . '|' . self::TIMECODE_INDEX); + } + + /** + * Writes the changes to given media file. All object offsets must be + * assumed to be invalid after the write operation. + * + * @param string $filename The optional path to the file, use null to save + * to the same file. + */ + public function write($filename) + { + if ($filename === null && ($filename = $this->_filename) === null) { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception + ('No file given to write to'); + } else if ($filename !== null && $this->_filename !== null && + realpath($filename) != realpath($this->_filename) && + !copy($this->_filename, $filename)) { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception + ('Unable to copy source to destination: ' . + realpath($this->_filename) . '->' . realpath($filename)); + } + + if (($fd = fopen + ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception + ('Unable to open file for writing: ' . $filename); + } + + $header = $this->getHeader(); + $headerLengthOld = $header->getSize(); + $header->removeObjectsByIdentifier(Zend_Media_Asf_Object::PADDING); + $header->headerExtension->removeObjectsByIdentifier + (Zend_Media_Asf_Object::PADDING); + + require_once 'Zend/Io/StringWriter.php'; + $buffer = new Zend_Io_StringWriter(); + $header->write($buffer); + $headerData = $buffer->toString(); + $headerLengthNew = $header->getSize(); + + // Fits right in + if ($headerLengthOld == $headerLengthNew) { + } + + // Fits with adjusted padding + else if ($headerLengthOld >= $headerLengthNew + 24 /* for header */) { + $header->headerExtension->padding->setSize + ($headerLengthOld - $headerLengthNew); + $buffer = new Zend_Io_StringWriter(); + $header->write($buffer); + $headerData = $buffer->toString(); + $headerLengthNew = $header->getSize(); + } + + // Must expand + else { + $header->headerExtension->padding->setSize(4096); + $buffer = new Zend_Io_StringWriter(); + $header->write($buffer); + $headerData = $buffer->toString(); + $headerLengthNew = $header->getSize(); + + fseek($fd, 0, SEEK_END); + $oldFileSize = ftell($fd); + ftruncate + ($fd, $newFileSize = $headerLengthNew - $headerLengthOld + + $oldFileSize); + for ($i = 1, $cur = $oldFileSize; $cur > 0; $cur -= 1024, $i++) { + if ($cur >= 1024) { + fseek($fd, -(($i * 1024) + + ($newFileSize - $oldFileSize)), SEEK_END); + $buffer = fread($fd, 1024); + fseek($fd, -($i * 1024), SEEK_END); + fwrite($fd, $buffer, 1024); + } else { + fseek($fd, 0); + $buffer = fread($fd, $cur); + fseek($fd, $newFileSize - $oldFileSize); + fwrite($fd, $buffer, $cur); + } + } + } + + fseek($fd, 0); + fwrite($fd, $headerData, $headerLengthNew); + fclose($fd); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Exception.php b/app/libs/vendor/Zend/Media/Asf/Exception.php index a77b8e37..64038c00 100644 --- a/app/libs/vendor/Zend/Media/Asf/Exception.php +++ b/app/libs/vendor/Zend/Media/Asf/Exception.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Asf_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Asf_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Asf/Object.php b/app/libs/vendor/Zend/Media/Asf/Object.php index b8518cd1..d4e96549 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object.php +++ b/app/libs/vendor/Zend/Media/Asf/Object.php @@ -1,322 +1,322 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Asf_Object -{ - /* ASF Objects */ - const HEADER = '75b22630-668e-11cf-a6d9-00aa0062ce6c'; - const DATA = '75b22636-668e-11cf-a6d9-00aa0062ce6c'; - const SIMPLE_INDEX = '33000890-e5b1-11cf-89f4-00a0c90349cb'; - const INDEX = 'd6e229d3-35da-11d1-9034-00a0c90349be'; - const MEDIA_OBJECT_INDEX = 'feb103f8-12ad-4c64-840f-2a1d2f7ad48c'; - const TIMECODE_INDEX = '3cb73fd0-0c4a-4803-953d-edf7b6228f0c'; - - /* Header Objects */ - const FILE_PROPERTIES = '8cabdca1-a947-11cf-8ee4-00c00c205365'; - const STREAM_PROPERTIES = 'b7dc0791-a9b7-11cf-8ee6-00c00c205365'; - const HEADER_EXTENSION = '5fbf03b5-a92e-11cf-8ee3-00c00c205365'; - const CODEC_LIST = '86d15240-311d-11d0-a3a4-00a0c90348f6'; - const SCRIPT_COMMAND = '1efb1a30-0b62-11d0-a39b-00a0c90348f6'; - const MARKER = 'f487cd01-a951-11cf-8ee6-00c00c205365'; - const BITRATE_MUTUAL_EXCLUSION = 'd6e229dc-35da-11d1-9034-00a0c90349be'; - const ERROR_CORRECTION = '75b22635-668e-11cf-a6d9-00aa0062ce6c'; - const CONTENT_DESCRIPTION = '75b22633-668e-11cf-a6d9-00aa0062ce6c'; - const EXTENDED_CONTENT_DESCRIPTION = 'd2d0a440-e307-11d2-97f0-00a0c95ea850'; - const CONTENT_BRANDING = '2211b3fa-bd23-11d2-b4b7-00a0c955fc6e'; - const STREAM_BITRATE_PROPERTIES = '7bf875ce-468d-11d1-8d82-006097c9a2b2'; - const CONTENT_ENCRYPTION = '2211b3fb-bd23-11d2-b4b7-00a0c955fc6e'; - const EXTENDED_CONTENT_ENCRYPTION = '298ae614-2622-4c17-b935-dae07ee9289c'; - const DIGITAL_SIGNATURE = '2211b3fc-bd23-11d2-b4b7-00a0c955fc6e'; - const PADDING = '1806d474-cadf-4509-a4ba-9aabcb96aae8'; - - /* Header Extension Objects */ - const EXTENDED_STREAM_PROPERTIES = '14e6a5cb-c672-4332-8399-a96952065b5a'; - const ADVANCED_MUTUAL_EXCLUSION = 'a08649cf-4775-4670-8a16-6e35357566cd'; - const GROUP_MUTUAL_EXCLUSION = 'd1465a40-5a79-4338-b71b-e36b8fd6c249'; - const STREAM_PRIORITIZATION = 'd4fed15b-88d3-454f-81f0-ed5c45999e24'; - const BANDWIDTH_SHARING = 'a69609e6-517b-11d2-b6af-00c04fd908e9'; - const LANGUAGE_LIST = '7c4346a9-efe0-4bfc-b229-393ede415c85'; - const METADATA = 'c5f8cbea-5baf-4877-8467-aa8c44fa4cca'; - const METADATA_LIBRARY = '44231c94-9498-49d1-a141-1d134e457054'; - const INDEX_PARAMETERS = 'd6e229df-35da-11d1-9034-00a0c90349be'; - const MEDIA_OBJECT_INDEX_PARAMETERS = - '6b203bad-3f11-48e4-aca8-d7613de2cfa7'; - const TIMECODE_INDEX_PARAMETERS = 'f55e496d-9797-4b5d-8c8b-604dfe9bfb24'; - const COMPATIBILITY = '75b22630-668e-11cf-a6d9-00aa0062ce6c'; - const ADVANCED_CONTENT_ENCRYPTION = '43058533-6981-49e6-9b74-ad12cb86d58c'; - - /** - * The reader object. - * - * @var Zend_Io_Reader - */ - protected $_reader; - - /** - * The options array. - * - * @var Array - */ - protected $_options; - - /** @var integer */ - private $_offset = false; - - /** @var string */ - private $_identifier = false; - - /** @var integer */ - private $_size = false; - - /** @var Zend_Media_Asf_Object */ - private $_parent = null; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - $this->_reader = $reader; - $this->_options = &$options; - - if (($this->_reader = $reader) === null) { - if (defined($constant = 'self::' . strtoupper - (preg_replace - ('/(?<=[a-z])[A-Z]/', '_$0', substr(get_class($this), 22))))) { - $this->_identifier = constant($constant); - } else { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception - ('Object identifier could not be determined'); - } - } else { - $this->_offset = $this->_reader->getOffset(); - $this->_identifier = $this->_reader->readGuid(); - $this->_size = $this->_reader->readInt64LE(); - } - } - - /** - * Returns the options array. - * - * @return Array - */ - public final function &getOptions() - { - return $this->_options; - } - - /** - * Returns the given option value, or the default value if the option is not - * defined. - * - * @param string $option The name of the option. - * @param mixed $defaultValue The default value to be returned. - */ - public final function getOption($option, $defaultValue = null) - { - if (isset($this->_options[$option])) { - return $this->_options[$option]; - } - return $defaultValue; - } - - /** - * Sets the options array. See {@link Zend_Media_Asf} class for available - * options. - * - * @param Array $options The options array. - */ - public final function setOptions(&$options) - { - $this->_options = &$options; - } - - /** - * Sets the given option the given value. - * - * @param string $option The name of the option. - * @param mixed $value The value to set for the option. - */ - public final function setOption($option, $value) - { - $this->_options[$option] = $value; - } - - /** - * Clears the given option value. - * - * @param string $option The name of the option. - */ - public final function clearOption($option) - { - unset($this->_options[$option]); - } - - /** - * Returns the file offset to object start, or false if the - * object was created on heap. - * - * @return integer - */ - public final function getOffset() - { - return $this->_offset; - } - - /** - * Sets the file offset where the object starts. - * - * @param integer $offset The file offset to object start. - */ - public final function setOffset($offset) - { - $this->_offset = $offset; - } - - /** - * Returns the GUID of the ASF object. - * - * @return string - */ - public final function getIdentifier() - { - return $this->_identifier; - } - - /** - * Set the GUID of the ASF object. - * - * @param string $identifier The GUID - */ - public final function setIdentifier($identifier) - { - $this->_identifier = $identifier; - } - - /** - * Returns the object size in bytes, including the header. - * - * @return integer - */ - public final function getSize() - { - return $this->_size; - } - - /** - * Sets the object size. The size must include the 24 byte header. - * - * @param integer $size The object size. - */ - public final function setSize($size) - { - if ($this->_parent !== null) { - $this->_parent->setSize - (($this->_parent->getSize() > 0 ? - $this->_parent->getSize() : 0) + - $size - ($this->_size > 0 ? $this->_size : 0)); - } - $this->_size = $size; - } - - /** - * Returns the parent object containing this object. - * - * @return Zend_Media_Asf_Object - */ - public final function getParent() - { - return $this->_parent; - } - - /** - * Sets the parent containing object. - * - * @param Zend_Media_Asf_Object $parent The parent object. - */ - public final function setParent(&$parent) - { - $this->_parent = $parent; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - abstract public function write($writer); - - /** - * Magic function so that $obj->value will work. The method will attempt to - * invoke a getter method. If there are no getter methods with given name, - * an exception is thrown. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - if (method_exists($this, 'is' . ucfirst($name))) { - return call_user_func(array($this, 'is' . ucfirst($name))); - } - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Unknown field: ' . $name); - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } else { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Asf_Object +{ + /* ASF Objects */ + const HEADER = '75b22630-668e-11cf-a6d9-00aa0062ce6c'; + const DATA = '75b22636-668e-11cf-a6d9-00aa0062ce6c'; + const SIMPLE_INDEX = '33000890-e5b1-11cf-89f4-00a0c90349cb'; + const INDEX = 'd6e229d3-35da-11d1-9034-00a0c90349be'; + const MEDIA_OBJECT_INDEX = 'feb103f8-12ad-4c64-840f-2a1d2f7ad48c'; + const TIMECODE_INDEX = '3cb73fd0-0c4a-4803-953d-edf7b6228f0c'; + + /* Header Objects */ + const FILE_PROPERTIES = '8cabdca1-a947-11cf-8ee4-00c00c205365'; + const STREAM_PROPERTIES = 'b7dc0791-a9b7-11cf-8ee6-00c00c205365'; + const HEADER_EXTENSION = '5fbf03b5-a92e-11cf-8ee3-00c00c205365'; + const CODEC_LIST = '86d15240-311d-11d0-a3a4-00a0c90348f6'; + const SCRIPT_COMMAND = '1efb1a30-0b62-11d0-a39b-00a0c90348f6'; + const MARKER = 'f487cd01-a951-11cf-8ee6-00c00c205365'; + const BITRATE_MUTUAL_EXCLUSION = 'd6e229dc-35da-11d1-9034-00a0c90349be'; + const ERROR_CORRECTION = '75b22635-668e-11cf-a6d9-00aa0062ce6c'; + const CONTENT_DESCRIPTION = '75b22633-668e-11cf-a6d9-00aa0062ce6c'; + const EXTENDED_CONTENT_DESCRIPTION = 'd2d0a440-e307-11d2-97f0-00a0c95ea850'; + const CONTENT_BRANDING = '2211b3fa-bd23-11d2-b4b7-00a0c955fc6e'; + const STREAM_BITRATE_PROPERTIES = '7bf875ce-468d-11d1-8d82-006097c9a2b2'; + const CONTENT_ENCRYPTION = '2211b3fb-bd23-11d2-b4b7-00a0c955fc6e'; + const EXTENDED_CONTENT_ENCRYPTION = '298ae614-2622-4c17-b935-dae07ee9289c'; + const DIGITAL_SIGNATURE = '2211b3fc-bd23-11d2-b4b7-00a0c955fc6e'; + const PADDING = '1806d474-cadf-4509-a4ba-9aabcb96aae8'; + + /* Header Extension Objects */ + const EXTENDED_STREAM_PROPERTIES = '14e6a5cb-c672-4332-8399-a96952065b5a'; + const ADVANCED_MUTUAL_EXCLUSION = 'a08649cf-4775-4670-8a16-6e35357566cd'; + const GROUP_MUTUAL_EXCLUSION = 'd1465a40-5a79-4338-b71b-e36b8fd6c249'; + const STREAM_PRIORITIZATION = 'd4fed15b-88d3-454f-81f0-ed5c45999e24'; + const BANDWIDTH_SHARING = 'a69609e6-517b-11d2-b6af-00c04fd908e9'; + const LANGUAGE_LIST = '7c4346a9-efe0-4bfc-b229-393ede415c85'; + const METADATA = 'c5f8cbea-5baf-4877-8467-aa8c44fa4cca'; + const METADATA_LIBRARY = '44231c94-9498-49d1-a141-1d134e457054'; + const INDEX_PARAMETERS = 'd6e229df-35da-11d1-9034-00a0c90349be'; + const MEDIA_OBJECT_INDEX_PARAMETERS = + '6b203bad-3f11-48e4-aca8-d7613de2cfa7'; + const TIMECODE_INDEX_PARAMETERS = 'f55e496d-9797-4b5d-8c8b-604dfe9bfb24'; + const COMPATIBILITY = '75b22630-668e-11cf-a6d9-00aa0062ce6c'; + const ADVANCED_CONTENT_ENCRYPTION = '43058533-6981-49e6-9b74-ad12cb86d58c'; + + /** + * The reader object. + * + * @var Zend_Io_Reader + */ + protected $_reader; + + /** + * The options array. + * + * @var Array + */ + protected $_options; + + /** @var integer */ + private $_offset = false; + + /** @var string */ + private $_identifier = false; + + /** @var integer */ + private $_size = false; + + /** @var Zend_Media_Asf_Object */ + private $_parent = null; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + $this->_reader = $reader; + $this->_options = &$options; + + if (($this->_reader = $reader) === null) { + if (defined($constant = 'self::' . strtoupper + (preg_replace + ('/(?<=[a-z])[A-Z]/', '_$0', substr(get_class($this), 22))))) { + $this->_identifier = constant($constant); + } else { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception + ('Object identifier could not be determined'); + } + } else { + $this->_offset = $this->_reader->getOffset(); + $this->_identifier = $this->_reader->readGuid(); + $this->_size = $this->_reader->readInt64LE(); + } + } + + /** + * Returns the options array. + * + * @return Array + */ + public final function &getOptions() + { + return $this->_options; + } + + /** + * Returns the given option value, or the default value if the option is not + * defined. + * + * @param string $option The name of the option. + * @param mixed $defaultValue The default value to be returned. + */ + public final function getOption($option, $defaultValue = null) + { + if (isset($this->_options[$option])) { + return $this->_options[$option]; + } + return $defaultValue; + } + + /** + * Sets the options array. See {@link Zend_Media_Asf} class for available + * options. + * + * @param Array $options The options array. + */ + public final function setOptions(&$options) + { + $this->_options = &$options; + } + + /** + * Sets the given option the given value. + * + * @param string $option The name of the option. + * @param mixed $value The value to set for the option. + */ + public final function setOption($option, $value) + { + $this->_options[$option] = $value; + } + + /** + * Clears the given option value. + * + * @param string $option The name of the option. + */ + public final function clearOption($option) + { + unset($this->_options[$option]); + } + + /** + * Returns the file offset to object start, or false if the + * object was created on heap. + * + * @return integer + */ + public final function getOffset() + { + return $this->_offset; + } + + /** + * Sets the file offset where the object starts. + * + * @param integer $offset The file offset to object start. + */ + public final function setOffset($offset) + { + $this->_offset = $offset; + } + + /** + * Returns the GUID of the ASF object. + * + * @return string + */ + public final function getIdentifier() + { + return $this->_identifier; + } + + /** + * Set the GUID of the ASF object. + * + * @param string $identifier The GUID + */ + public final function setIdentifier($identifier) + { + $this->_identifier = $identifier; + } + + /** + * Returns the object size in bytes, including the header. + * + * @return integer + */ + public final function getSize() + { + return $this->_size; + } + + /** + * Sets the object size. The size must include the 24 byte header. + * + * @param integer $size The object size. + */ + public final function setSize($size) + { + if ($this->_parent !== null) { + $this->_parent->setSize + (($this->_parent->getSize() > 0 ? + $this->_parent->getSize() : 0) + + $size - ($this->_size > 0 ? $this->_size : 0)); + } + $this->_size = $size; + } + + /** + * Returns the parent object containing this object. + * + * @return Zend_Media_Asf_Object + */ + public final function getParent() + { + return $this->_parent; + } + + /** + * Sets the parent containing object. + * + * @param Zend_Media_Asf_Object $parent The parent object. + */ + public final function setParent(&$parent) + { + $this->_parent = $parent; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + abstract public function write($writer); + + /** + * Magic function so that $obj->value will work. The method will attempt to + * invoke a getter method. If there are no getter methods with given name, + * an exception is thrown. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + if (method_exists($this, 'is' . ucfirst($name))) { + return call_user_func(array($this, 'is' . ucfirst($name))); + } + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Unknown field: ' . $name); + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } else { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/AdvancedContentEncryption.php b/app/libs/vendor/Zend/Media/Asf/Object/AdvancedContentEncryption.php index 93157893..677a5c84 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/AdvancedContentEncryption.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/AdvancedContentEncryption.php @@ -1,168 +1,168 @@ -Advanced Content Encryption Object lets authors protect content by - * using Next Generation Windows Media Digital Rights Management for Network - * Devices. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: AdvancedContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_AdvancedContentEncryption - extends Zend_Media_Asf_Object -{ - const WINDOWS_MEDIA_DRM_NETWORK_DEVICES = - '7a079bb6-daa4-4e12-a5ca-91d3 8dc11a8d'; - - /** @var Array */ - private $_contentEncryptionRecords = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - $contentEncryptionRecordsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $contentEncryptionRecordsCount; $i++) { - $entry = array('systemId' => $this->_reader->readGuid(), - 'systemVersion' => $this->_reader->readUInt32LE(), - 'streamNumbers' => array()); - $encryptedObjectRecordCount = $this->_reader->readUInt16LE(); - for ($j = 0; $j < $encryptedObjectRecordCount; $j++) { - $this->_reader->skip(4); - $entry['streamNumbers'][] = $this->_reader->readUInt16LE(); - } - $dataCount = $this->_reader->readUInt32LE(); - $entry['data'] = $this->_reader->read($dataCount); - $this->_contentEncryptionRecords[] = $entry; - } - } - - /** - * Returns an array of content encryption records. Each record consists of - * the following keys. - * - * o systemId -- Specifies the unique identifier for the content - * encryption system. - * - * o systemVersion -- Specifies the version of the content encryption - * system. - * - * o streamNumbers -- An array of stream numbers a particular Content - * Encryption Record is associated with. A value of 0 in this field - * indicates that it applies to the whole file; otherwise, the entry - * applies only to the indicated stream number. - * - * o data -- The content protection data for this Content Encryption - * Record. - * - * @return Array - */ - public function getContentEncryptionRecords() - { - return $this->_contentEncryptionRecords; - } - - /** - * Sets the array of content encryption records. Each record must consist of - * the following keys. - * - * o systemId -- Specifies the unique identifier for the content - * encryption system. - * - * o systemVersion -- Specifies the version of the content encryption - * system. - * - * o streamNumbers -- An array of stream numbers a particular Content - * Encryption Record is associated with. A value of 0 in this field - * indicates that it applies to the whole file; otherwise, the entry - * applies only to the indicated stream number. - * - * o data -- The content protection data for this Content Encryption - * Record. - * - * @param Array $contentEncryptionRecords The array of content encryption - * records. - */ - public function setContentEncryptionRecords($contentEncryptionRecords) - { - $this->_contentEncryptionRecords = $contentEncryptionRecords; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $contentEncryptionRecordsCount = - count($this->_contentEncryptionRecords); - $contentEncryptionRecordsWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $contentEncryptionRecordsCount; $i++) { - $contentEncryptionRecordsWriter - ->writeGuid($this->_contentEncryptionRecords['systemId']) - ->writeUInt32LE - ($this->_contentEncryptionRecords['systemVersion']) - ->writeUInt16LE - ($encryptedObjectRecordCount = - $this->_contentEncryptionRecords['streamNumbers']); - for ($j = 0; $j < $encryptedObjectRecordCount; $j++) { - $contentEncryptionRecordsWriter - ->writeUInt16LE(1) - ->writeUInt16LE(2) - ->writeUInt16LE - ($this->_contentEncryptionRecords['streamNumbers'][$j]); - } - $contentEncryptionRecordsWriter - ->writeUInt32LE - (strlen($this->_contentEncryptionRecords['data'])) - ->write($this->_contentEncryptionRecords['data']); - } - - $this->setSize - (24 /* for header */ + 2 + - $contentEncryptionRecordsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($contentEncryptionRecordsCount) - ->write($contentEncryptionRecordsWriter->toString()); - } -} +Advanced Content Encryption Object lets authors protect content by + * using Next Generation Windows Media Digital Rights Management for Network + * Devices. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: AdvancedContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_AdvancedContentEncryption + extends Zend_Media_Asf_Object +{ + const WINDOWS_MEDIA_DRM_NETWORK_DEVICES = + '7a079bb6-daa4-4e12-a5ca-91d3 8dc11a8d'; + + /** @var Array */ + private $_contentEncryptionRecords = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + $contentEncryptionRecordsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $contentEncryptionRecordsCount; $i++) { + $entry = array('systemId' => $this->_reader->readGuid(), + 'systemVersion' => $this->_reader->readUInt32LE(), + 'streamNumbers' => array()); + $encryptedObjectRecordCount = $this->_reader->readUInt16LE(); + for ($j = 0; $j < $encryptedObjectRecordCount; $j++) { + $this->_reader->skip(4); + $entry['streamNumbers'][] = $this->_reader->readUInt16LE(); + } + $dataCount = $this->_reader->readUInt32LE(); + $entry['data'] = $this->_reader->read($dataCount); + $this->_contentEncryptionRecords[] = $entry; + } + } + + /** + * Returns an array of content encryption records. Each record consists of + * the following keys. + * + * o systemId -- Specifies the unique identifier for the content + * encryption system. + * + * o systemVersion -- Specifies the version of the content encryption + * system. + * + * o streamNumbers -- An array of stream numbers a particular Content + * Encryption Record is associated with. A value of 0 in this field + * indicates that it applies to the whole file; otherwise, the entry + * applies only to the indicated stream number. + * + * o data -- The content protection data for this Content Encryption + * Record. + * + * @return Array + */ + public function getContentEncryptionRecords() + { + return $this->_contentEncryptionRecords; + } + + /** + * Sets the array of content encryption records. Each record must consist of + * the following keys. + * + * o systemId -- Specifies the unique identifier for the content + * encryption system. + * + * o systemVersion -- Specifies the version of the content encryption + * system. + * + * o streamNumbers -- An array of stream numbers a particular Content + * Encryption Record is associated with. A value of 0 in this field + * indicates that it applies to the whole file; otherwise, the entry + * applies only to the indicated stream number. + * + * o data -- The content protection data for this Content Encryption + * Record. + * + * @param Array $contentEncryptionRecords The array of content encryption + * records. + */ + public function setContentEncryptionRecords($contentEncryptionRecords) + { + $this->_contentEncryptionRecords = $contentEncryptionRecords; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $contentEncryptionRecordsCount = + count($this->_contentEncryptionRecords); + $contentEncryptionRecordsWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $contentEncryptionRecordsCount; $i++) { + $contentEncryptionRecordsWriter + ->writeGuid($this->_contentEncryptionRecords['systemId']) + ->writeUInt32LE + ($this->_contentEncryptionRecords['systemVersion']) + ->writeUInt16LE + ($encryptedObjectRecordCount = + $this->_contentEncryptionRecords['streamNumbers']); + for ($j = 0; $j < $encryptedObjectRecordCount; $j++) { + $contentEncryptionRecordsWriter + ->writeUInt16LE(1) + ->writeUInt16LE(2) + ->writeUInt16LE + ($this->_contentEncryptionRecords['streamNumbers'][$j]); + } + $contentEncryptionRecordsWriter + ->writeUInt32LE + (strlen($this->_contentEncryptionRecords['data'])) + ->write($this->_contentEncryptionRecords['data']); + } + + $this->setSize + (24 /* for header */ + 2 + + $contentEncryptionRecordsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($contentEncryptionRecordsCount) + ->write($contentEncryptionRecordsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/AdvancedMutualExclusion.php b/app/libs/vendor/Zend/Media/Asf/Object/AdvancedMutualExclusion.php index 3c9d4cfa..c6e85239 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/AdvancedMutualExclusion.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/AdvancedMutualExclusion.php @@ -1,140 +1,140 @@ -Advanced Mutual Exclusion Object identifies streams that have a - * mutual exclusion relationship to each other (in other words, only one of the - * streams within such a relationship can be streamed—the rest are ignored). - * There should be one instance of this object for each set of objects that - * contain a mutual exclusion relationship. The exclusion type is used so that - * implementations can allow user selection of common choices, such as language. - * This object must be used if any of the streams in the mutual exclusion - * relationship are hidden. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: AdvancedMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_AdvancedMutualExclusion - extends Zend_Media_Asf_Object -{ - const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; - const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; - const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; - - /** @var string */ - private $_exclusionType; - - /** @var Array */ - private $_streamNumbers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_exclusionType = $this->_reader->readGuid(); - $streamNumbersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $this->_streamNumbers[] = $this->_reader->readUInt16LE(); - } - } - - /** - * Returns the nature of the mutual exclusion relationship. - * - * @return string - */ - public function getExclusionType() - { - return $this->_exclusionType; - } - - /** - * Returns the nature of the mutual exclusion relationship. - * - * @return string - */ - public function setExclusionType($exclusionType) - { - $this->_exclusionType = $exclusionType; - } - - /** - * Returns an array of stream numbers. - * - * @return Array - */ - public function getStreamNumbers() - { - return $this->_streamNumbers; - } - - /** - * Sets the array of stream numbers. - * - * @return Array - */ - public function setStreamNumbers($streamNumbers) - { - $this->_streamNumbers = $streamNumbers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $streamNumbersCount = count($this->_streamNumbers); - - $this->setSize(24 /* for header */ + 18 + $streamNumbersCount * 2); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_exclusionType) - ->writeUInt16LE($streamNumbersCount); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $writer->writeUInt16LE($this->_streamNumbers[$i]); - } - } -} +Advanced Mutual Exclusion Object identifies streams that have a + * mutual exclusion relationship to each other (in other words, only one of the + * streams within such a relationship can be streamed—the rest are ignored). + * There should be one instance of this object for each set of objects that + * contain a mutual exclusion relationship. The exclusion type is used so that + * implementations can allow user selection of common choices, such as language. + * This object must be used if any of the streams in the mutual exclusion + * relationship are hidden. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: AdvancedMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_AdvancedMutualExclusion + extends Zend_Media_Asf_Object +{ + const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; + const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; + const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; + + /** @var string */ + private $_exclusionType; + + /** @var Array */ + private $_streamNumbers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_exclusionType = $this->_reader->readGuid(); + $streamNumbersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $this->_streamNumbers[] = $this->_reader->readUInt16LE(); + } + } + + /** + * Returns the nature of the mutual exclusion relationship. + * + * @return string + */ + public function getExclusionType() + { + return $this->_exclusionType; + } + + /** + * Returns the nature of the mutual exclusion relationship. + * + * @return string + */ + public function setExclusionType($exclusionType) + { + $this->_exclusionType = $exclusionType; + } + + /** + * Returns an array of stream numbers. + * + * @return Array + */ + public function getStreamNumbers() + { + return $this->_streamNumbers; + } + + /** + * Sets the array of stream numbers. + * + * @return Array + */ + public function setStreamNumbers($streamNumbers) + { + $this->_streamNumbers = $streamNumbers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $streamNumbersCount = count($this->_streamNumbers); + + $this->setSize(24 /* for header */ + 18 + $streamNumbersCount * 2); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_exclusionType) + ->writeUInt16LE($streamNumbersCount); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $writer->writeUInt16LE($this->_streamNumbers[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/BandwidthSharing.php b/app/libs/vendor/Zend/Media/Asf/Object/BandwidthSharing.php index 31856356..4be78179 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/BandwidthSharing.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/BandwidthSharing.php @@ -1,217 +1,217 @@ -Bandwidth Sharing Object indicates streams that share bandwidth in - * such a way that the maximum bandwidth of the set of streams is less than the - * sum of the maximum bandwidths of the individual streams. There should be one - * instance of this object for each set of objects that share bandwidth. Whether - * or not this object can be used meaningfully is content-dependent. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: BandwidthSharing.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_BandwidthSharing extends Zend_Media_Asf_Object -{ - const SHARING_EXCLUSIVE = 'af6060aa-5197-11d2-b6af-00c04fd908e9'; - const SHARING_PARTIAL = 'af6060ab-5197-11d2-b6af-00c04fd908e9'; - - /** @var string */ - private $_sharingType; - - /** @var integer */ - private $_dataBitrate; - - /** @var integer */ - private $_bufferSize; - - /** @var Array */ - private $_streamNumbers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader = null, $options); - - if ($reader === null) { - return; - } - - $this->_sharingType = $this->_reader->readGuid(); - $this->_dataBitrate = $this->_reader->readUInt32LE(); - $this->_bufferSize = $this->_reader->readUInt32LE(); - $streamNumbersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $this->_streamNumbers[] = $this->_reader->readUInt16LE(); - } - } - - /** - * Returns the type of sharing relationship for this object. Two types are - * predefined: SHARING_PARTIAL, in which any number of the streams in the - * relationship may be streaming data at any given time; and - * SHARING_EXCLUSIVE, in which only one of the streams in the relationship - * may be streaming data at any given time. - * - * @return string - */ - public function getSharingType() - { - return $this->_sharingType; - } - - /** - * Sets the type of sharing relationship for this object. Two types are - * predefined: SHARING_PARTIAL, in which any number of the streams in the - * relationship may be streaming data at any given time; and - * SHARING_EXCLUSIVE, in which only one of the streams in the relationship - * may be streaming data at any given time. - * - * @return string - */ - public function setSharingType($sharingType) - { - $this->_sharingType = $sharingType; - } - - /** - * Returns the leak rate R, in bits per second, of a leaky bucket that - * contains the data portion of all of the streams, excluding all ASF Data - * Packet overhead, without overflowing. The size of the leaky bucket is - * specified by the value of the Buffer Size field. This value can be less - * than the sum of all of the data bit rates in the - * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream - * Properties} Objects for the streams contained in this bandwidth-sharing - * relationship. - * - * @return integer - */ - public function getDataBitrate() - { - return $this->_dataBitrate; - } - - /** - * Sets the leak rate R, in bits per second, of a leaky bucket that contains - * the data portion of all of the streams, excluding all ASF Data Packet - * overhead, without overflowing. The size of the leaky bucket is specified - * by the value of the Buffer Size field. This value can be less than the - * sum of all of the data bit rates in the - * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream - * Properties} Objects for the streams contained in this bandwidth-sharing - * relationship. - * - * @param integer $dataBitrate The data bitrate. - */ - public function setDataBitrate($dataBitrate) - { - $this->_dataBitrate = $dataBitrate; - } - - /** - * Specifies the size B, in bits, of the leaky bucket used in the Data - * Bitrate definition. This value can be less than the sum of all of the - * buffer sizes in the - * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream - * Properties} Objects for the streams contained in this bandwidth-sharing - * relationship. - * - * @return integer - */ - public function getBufferSize() - { - return $this->_bufferSize; - } - - /** - * Sets the size B, in bits, of the leaky bucket used in the Data Bitrate - * definition. This value can be less than the sum of all of the buffer - * sizes in the - * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream - * Properties} Objects for the streams contained in this bandwidth-sharing - * relationship. - * - * @param integer $bufferSize The buffer size. - */ - public function setBufferSize($bufferSize) - { - $this->_bufferSize = $bufferSize; - } - - /** - * Returns an array of stream numbers. - * - * @return Array - */ - public function getStreamNumbers() - { - return $this->_streamNumbers; - } - - /** - * Sets the array of stream numbers. - * - * @param Array $streamNumbers The array of stream numbers. - */ - public function setStreamNumbers($streamNumbers) - { - $this->_streamNumbers = $streamNumbers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $streamNumbersCount = count($this->_streamNumber); - - $this->setSize(24 /* for header */ + 28 + $streamNumbersCount * 2); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_sharingType) - ->writeUInt32LE($this->_dataBitrate) - ->writeUInt32LE($this->_bufferSize) - ->writeUInt16LE($streamNumbersCount); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $writer->writeUInt16LE($this->_streamNumbers[$i]); - } - } -} +Bandwidth Sharing Object indicates streams that share bandwidth in + * such a way that the maximum bandwidth of the set of streams is less than the + * sum of the maximum bandwidths of the individual streams. There should be one + * instance of this object for each set of objects that share bandwidth. Whether + * or not this object can be used meaningfully is content-dependent. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: BandwidthSharing.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_BandwidthSharing extends Zend_Media_Asf_Object +{ + const SHARING_EXCLUSIVE = 'af6060aa-5197-11d2-b6af-00c04fd908e9'; + const SHARING_PARTIAL = 'af6060ab-5197-11d2-b6af-00c04fd908e9'; + + /** @var string */ + private $_sharingType; + + /** @var integer */ + private $_dataBitrate; + + /** @var integer */ + private $_bufferSize; + + /** @var Array */ + private $_streamNumbers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader = null, $options); + + if ($reader === null) { + return; + } + + $this->_sharingType = $this->_reader->readGuid(); + $this->_dataBitrate = $this->_reader->readUInt32LE(); + $this->_bufferSize = $this->_reader->readUInt32LE(); + $streamNumbersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $this->_streamNumbers[] = $this->_reader->readUInt16LE(); + } + } + + /** + * Returns the type of sharing relationship for this object. Two types are + * predefined: SHARING_PARTIAL, in which any number of the streams in the + * relationship may be streaming data at any given time; and + * SHARING_EXCLUSIVE, in which only one of the streams in the relationship + * may be streaming data at any given time. + * + * @return string + */ + public function getSharingType() + { + return $this->_sharingType; + } + + /** + * Sets the type of sharing relationship for this object. Two types are + * predefined: SHARING_PARTIAL, in which any number of the streams in the + * relationship may be streaming data at any given time; and + * SHARING_EXCLUSIVE, in which only one of the streams in the relationship + * may be streaming data at any given time. + * + * @return string + */ + public function setSharingType($sharingType) + { + $this->_sharingType = $sharingType; + } + + /** + * Returns the leak rate R, in bits per second, of a leaky bucket that + * contains the data portion of all of the streams, excluding all ASF Data + * Packet overhead, without overflowing. The size of the leaky bucket is + * specified by the value of the Buffer Size field. This value can be less + * than the sum of all of the data bit rates in the + * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream + * Properties} Objects for the streams contained in this bandwidth-sharing + * relationship. + * + * @return integer + */ + public function getDataBitrate() + { + return $this->_dataBitrate; + } + + /** + * Sets the leak rate R, in bits per second, of a leaky bucket that contains + * the data portion of all of the streams, excluding all ASF Data Packet + * overhead, without overflowing. The size of the leaky bucket is specified + * by the value of the Buffer Size field. This value can be less than the + * sum of all of the data bit rates in the + * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream + * Properties} Objects for the streams contained in this bandwidth-sharing + * relationship. + * + * @param integer $dataBitrate The data bitrate. + */ + public function setDataBitrate($dataBitrate) + { + $this->_dataBitrate = $dataBitrate; + } + + /** + * Specifies the size B, in bits, of the leaky bucket used in the Data + * Bitrate definition. This value can be less than the sum of all of the + * buffer sizes in the + * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream + * Properties} Objects for the streams contained in this bandwidth-sharing + * relationship. + * + * @return integer + */ + public function getBufferSize() + { + return $this->_bufferSize; + } + + /** + * Sets the size B, in bits, of the leaky bucket used in the Data Bitrate + * definition. This value can be less than the sum of all of the buffer + * sizes in the + * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream + * Properties} Objects for the streams contained in this bandwidth-sharing + * relationship. + * + * @param integer $bufferSize The buffer size. + */ + public function setBufferSize($bufferSize) + { + $this->_bufferSize = $bufferSize; + } + + /** + * Returns an array of stream numbers. + * + * @return Array + */ + public function getStreamNumbers() + { + return $this->_streamNumbers; + } + + /** + * Sets the array of stream numbers. + * + * @param Array $streamNumbers The array of stream numbers. + */ + public function setStreamNumbers($streamNumbers) + { + $this->_streamNumbers = $streamNumbers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $streamNumbersCount = count($this->_streamNumber); + + $this->setSize(24 /* for header */ + 28 + $streamNumbersCount * 2); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_sharingType) + ->writeUInt32LE($this->_dataBitrate) + ->writeUInt32LE($this->_bufferSize) + ->writeUInt16LE($streamNumbersCount); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $writer->writeUInt16LE($this->_streamNumbers[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/BitrateMutualExclusion.php b/app/libs/vendor/Zend/Media/Asf/Object/BitrateMutualExclusion.php index 3c71d3e8..618a4139 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/BitrateMutualExclusion.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/BitrateMutualExclusion.php @@ -1,141 +1,141 @@ -Bitrate Mutual Exclusion Object identifies video streams that have - * a mutual exclusion relationship to each other (in other words, only one of - * the streams within such a relationship can be streamed at any given time and - * the rest are ignored). One instance of this object must be present for each - * set of objects that contains a mutual exclusion relationship. All video - * streams in this relationship must have the same frame size. The exclusion - * type is used so that implementations can allow user selection of common - * choices, such as bit rate. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: BitrateMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_BitrateMutualExclusion - extends Zend_Media_Asf_Object -{ - const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; - const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; - const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; - - /** @var string */ - private $_exclusionType; - - /** @var Array */ - private $_streamNumbers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_exclusionType = $this->_reader->readGuid(); - $streamNumbersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $this->_streamNumbers[] = $this->_reader->readUInt16LE(); - } - } - - /** - * Returns the nature of the mutual exclusion relationship. - * - * @return string - */ - public function getExclusionType() - { - return $this->_exclusionType; - } - - /** - * Sets the nature of the mutual exclusion relationship. - * - * @param string $exclusionType The nature of the mutual exclusion - * relationship. - */ - public function setExclusionType($exclusionType) - { - $this->_exclusionType = $exclusionType; - } - - /** - * Returns an array of stream numbers. - * - * @return Array - */ - public function getStreamNumbers() - { - return $this->_streamNumbers; - } - - /** - * Sets the array of stream numbers. - * - * @param Array $streamNumbers The array of stream numbers. - */ - public function setStreamNumbers($streamNumbers) - { - $this->_streamNumbers = $streamNumbers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $streamNumbersCount = count($this->_streamNumbers); - - $this->setSize(24 /* for header */ + 18 + $streamNumbersCount * 2); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_exclusionType) - ->writeUInt16LE($streamNumbersCount); - for ($i = 0; $i < $streamNumbersCount; $i++) { - $writer->writeUInt16LE($this->_streamNumbers[$i]); - } - } -} +Bitrate Mutual Exclusion Object identifies video streams that have + * a mutual exclusion relationship to each other (in other words, only one of + * the streams within such a relationship can be streamed at any given time and + * the rest are ignored). One instance of this object must be present for each + * set of objects that contains a mutual exclusion relationship. All video + * streams in this relationship must have the same frame size. The exclusion + * type is used so that implementations can allow user selection of common + * choices, such as bit rate. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: BitrateMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_BitrateMutualExclusion + extends Zend_Media_Asf_Object +{ + const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; + const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; + const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; + + /** @var string */ + private $_exclusionType; + + /** @var Array */ + private $_streamNumbers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_exclusionType = $this->_reader->readGuid(); + $streamNumbersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $this->_streamNumbers[] = $this->_reader->readUInt16LE(); + } + } + + /** + * Returns the nature of the mutual exclusion relationship. + * + * @return string + */ + public function getExclusionType() + { + return $this->_exclusionType; + } + + /** + * Sets the nature of the mutual exclusion relationship. + * + * @param string $exclusionType The nature of the mutual exclusion + * relationship. + */ + public function setExclusionType($exclusionType) + { + $this->_exclusionType = $exclusionType; + } + + /** + * Returns an array of stream numbers. + * + * @return Array + */ + public function getStreamNumbers() + { + return $this->_streamNumbers; + } + + /** + * Sets the array of stream numbers. + * + * @param Array $streamNumbers The array of stream numbers. + */ + public function setStreamNumbers($streamNumbers) + { + $this->_streamNumbers = $streamNumbers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $streamNumbersCount = count($this->_streamNumbers); + + $this->setSize(24 /* for header */ + 18 + $streamNumbersCount * 2); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_exclusionType) + ->writeUInt16LE($streamNumbersCount); + for ($i = 0; $i < $streamNumbersCount; $i++) { + $writer->writeUInt16LE($this->_streamNumbers[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/CodecList.php b/app/libs/vendor/Zend/Media/Asf/Object/CodecList.php index a39a17f1..0416c162 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/CodecList.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/CodecList.php @@ -1,165 +1,165 @@ -Codec List Object provides user-friendly information about the - * codecs and formats used to encode the content found in the ASF file. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: CodecList.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_CodecList extends Zend_Media_Asf_Object -{ - const VIDEO_CODEC = 0x1; - const AUDIO_CODEC = 0x2; - const UNKNOWN_CODEC = 0xffff; - - /** @var string */ - private $_reserved; - - /** @var Array */ - private $_entries = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_reserved = $this->_reader->readGuid(); - $codecEntriesCount = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $codecEntriesCount; $i++) { - $entry = array('type' => $this->_reader->readUInt16LE()); - $codecNameLength = $this->_reader->readUInt16LE() * 2; - $entry['codecName'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($codecNameLength)); - $codecDescriptionLength = $this->_reader->readUInt16LE() * 2; - $entry['codecDescription'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($codecDescriptionLength)); - $codecInformationLength = $this->_reader->readUInt16LE(); - $entry['codecInformation'] = - $this->_reader->read($codecInformationLength); - $this->_entries[] = $entry; - } - } - - /** - * Returns the array of codec entries. Each record consists of the following - * keys. - * - * o type -- Specifies the type of the codec used. Use one of the - * following values: VIDEO_CODEC, AUDIO_CODEC, or UNKNOWN_CODEC. - * - * o codecName -- Specifies the name of the codec used to create the - * content. - * - * o codecDescription -- Specifies the description of the format used to - * create the content. - * - * o codecInformation -- Specifies an opaque array of information bytes - * about the codec used to create the content. The meaning of these - * bytes is determined by the codec. - * - * @return Array - */ - public function getEntries() - { - return $this->_entries; - } - - /** - * Sets the array of codec entries. Each record must consist of the - * following keys. - * - * o codecName -- Specifies the name of the codec used to create the - * content. - * - * o codecDescription -- Specifies the description of the format used to - * create the content. - * - * o codecInformation -- Specifies an opaque array of information bytes - * about the codec used to create the content. The meaning of these - * bytes is determined by the codec. - * - * @param Array $entries The array of codec entries. - */ - public function setEntries($entries) - { - $this->_entries = $entries; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $codecEntriesCount = count($this->_entries); - $codecEntriesWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $codecEntriesCount; $i++) { - $codecEntriesWriter - ->writeUInt16LE($this->_entries[$i]['type']) - ->writeUInt16LE(strlen($codecName = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_entries[$i]['codecName']) . "\0\0") / 2) - ->writeString16($codecName) - ->writeUInt16LE(strlen($codecDescription = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_entries[$i]['codecDescription']) . "\0\0") / 2) - ->writeString16($codecDescription) - ->writeUInt16LE(strlen($this->_entries[$i]['codecInformation'])) - ->write($this->_entries[$i]['codecInformation']); - } - - $this->setSize - (24 /* for header */ + 20 + $codecEntriesWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_reserved) - ->writeUInt32LE($codecEntriesCount) - ->write($codecEntriesWriter->toString()); - } -} +Codec List Object provides user-friendly information about the + * codecs and formats used to encode the content found in the ASF file. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: CodecList.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_CodecList extends Zend_Media_Asf_Object +{ + const VIDEO_CODEC = 0x1; + const AUDIO_CODEC = 0x2; + const UNKNOWN_CODEC = 0xffff; + + /** @var string */ + private $_reserved; + + /** @var Array */ + private $_entries = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_reserved = $this->_reader->readGuid(); + $codecEntriesCount = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $codecEntriesCount; $i++) { + $entry = array('type' => $this->_reader->readUInt16LE()); + $codecNameLength = $this->_reader->readUInt16LE() * 2; + $entry['codecName'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($codecNameLength)); + $codecDescriptionLength = $this->_reader->readUInt16LE() * 2; + $entry['codecDescription'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($codecDescriptionLength)); + $codecInformationLength = $this->_reader->readUInt16LE(); + $entry['codecInformation'] = + $this->_reader->read($codecInformationLength); + $this->_entries[] = $entry; + } + } + + /** + * Returns the array of codec entries. Each record consists of the following + * keys. + * + * o type -- Specifies the type of the codec used. Use one of the + * following values: VIDEO_CODEC, AUDIO_CODEC, or UNKNOWN_CODEC. + * + * o codecName -- Specifies the name of the codec used to create the + * content. + * + * o codecDescription -- Specifies the description of the format used to + * create the content. + * + * o codecInformation -- Specifies an opaque array of information bytes + * about the codec used to create the content. The meaning of these + * bytes is determined by the codec. + * + * @return Array + */ + public function getEntries() + { + return $this->_entries; + } + + /** + * Sets the array of codec entries. Each record must consist of the + * following keys. + * + * o codecName -- Specifies the name of the codec used to create the + * content. + * + * o codecDescription -- Specifies the description of the format used to + * create the content. + * + * o codecInformation -- Specifies an opaque array of information bytes + * about the codec used to create the content. The meaning of these + * bytes is determined by the codec. + * + * @param Array $entries The array of codec entries. + */ + public function setEntries($entries) + { + $this->_entries = $entries; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $codecEntriesCount = count($this->_entries); + $codecEntriesWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $codecEntriesCount; $i++) { + $codecEntriesWriter + ->writeUInt16LE($this->_entries[$i]['type']) + ->writeUInt16LE(strlen($codecName = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_entries[$i]['codecName']) . "\0\0") / 2) + ->writeString16($codecName) + ->writeUInt16LE(strlen($codecDescription = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_entries[$i]['codecDescription']) . "\0\0") / 2) + ->writeString16($codecDescription) + ->writeUInt16LE(strlen($this->_entries[$i]['codecInformation'])) + ->write($this->_entries[$i]['codecInformation']); + } + + $this->setSize + (24 /* for header */ + 20 + $codecEntriesWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_reserved) + ->writeUInt32LE($codecEntriesCount) + ->write($codecEntriesWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Compatibility.php b/app/libs/vendor/Zend/Media/Asf/Object/Compatibility.php index d12d413f..fd20a124 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Compatibility.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Compatibility.php @@ -1,120 +1,120 @@ -Compatibility Object is reserved for future use. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Compatibility.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Compatibility extends Zend_Media_Asf_Object -{ - /** @var integer */ - private $_profile; - - /** @var integer */ - private $_mode; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_profile = $this->_reader->readUInt8(); - $this->_mode = $this->_reader->readUInt8(); - } - - /** - * Returns the profile field. This field is reserved and is set to 2. - * - * @return integer - */ - public function getProfile() - { - return $this->_profile; - } - - /** - * Returns the profile field. This field is reserved and is set to 2. - * - * @param integer $profile The profile. - */ - public function setProfile($profile) - { - $this->_profile = $profile; - } - - /** - * Returns the mode field. This field is reserved and is set to 1. - * - * @return integer - */ - public function getMode() - { - return $this->_mode; - } - - /** - * Sets the mode field. This field is reserved and is set to 1. - * - * @param integer $mode The mode. - */ - public function setMode($mode) - { - $this->_mode = $mode; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $this->setSize(24 /* for header */ + 2); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt8($this->_profile) - ->writeUInt8($this->_mode); - } -} +Compatibility Object is reserved for future use. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Compatibility.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Compatibility extends Zend_Media_Asf_Object +{ + /** @var integer */ + private $_profile; + + /** @var integer */ + private $_mode; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_profile = $this->_reader->readUInt8(); + $this->_mode = $this->_reader->readUInt8(); + } + + /** + * Returns the profile field. This field is reserved and is set to 2. + * + * @return integer + */ + public function getProfile() + { + return $this->_profile; + } + + /** + * Returns the profile field. This field is reserved and is set to 2. + * + * @param integer $profile The profile. + */ + public function setProfile($profile) + { + $this->_profile = $profile; + } + + /** + * Returns the mode field. This field is reserved and is set to 1. + * + * @return integer + */ + public function getMode() + { + return $this->_mode; + } + + /** + * Sets the mode field. This field is reserved and is set to 1. + * + * @param integer $mode The mode. + */ + public function setMode($mode) + { + $this->_mode = $mode; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $this->setSize(24 /* for header */ + 2); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt8($this->_profile) + ->writeUInt8($this->_mode); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Container.php b/app/libs/vendor/Zend/Media/Asf/Object/Container.php index 3a5ec59e..f0d140bd 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Container.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Container.php @@ -1,361 +1,361 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Container.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Asf_Object_Container extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_objects = array(); - - /** - * Reads and constructs the objects found within this object. - */ - protected final function constructObjects($defaultclassnames = array()) - { - while (true) { - $offset = $this->_reader->getOffset(); - if ($offset >= $this->getOffset() + $this->getSize()) { - break; - } - $guid = $this->_reader->readGuid(); - $size = $this->_reader->readInt64LE(); - - $this->_reader->setOffset($offset); - if (isset($defaultclassnames[$guid])) { - if (@fopen($filename = 'Zend/Media/Asf/Object/' . - $defaultclassnames[$guid] . '.php', - 'r', true) !== false) { - require_once($filename); - } - if (class_exists - ($classname = 'Zend_Media_Asf_Object_' . - $defaultclassnames[$guid])) { - $object = new $classname($this->_reader, $this->_options); - } else { - require_once 'Zend/Media/Asf/Object/Unknown.php'; - $object = new Zend_Media_Asf_Object_Unknown - ($this->_reader, $this->_options); - } - } else { - require_once 'Zend/Media/Asf/Object/Unknown.php'; - $object = new Zend_Media_Asf_Object_Unknown - ($this->_reader, $this->_options); - } - $object->setParent($this); - if (!$this->hasObject($object->getIdentifier())) { - $this->_objects[$object->getIdentifier()] = array(); - } - $this->_objects[$object->getIdentifier()][] = $object; - $this->_reader->setOffset($offset + $size); - } - } - - /** - * Checks whether the object with given identifier is present in the file. - * The identifier can either be the object GUID, or name of the constant - * containing the GUID, or the name of the object class. - * - * Returns true if one or more objects are present, - * false otherwise. - * - * @param string $identifier The object GUID, name of the GUID constant, or - * object class name. - * @return boolean - */ - public final function hasObject($identifier) - { - if (defined($constname = get_class($this) . '::' . strtoupper - (preg_replace('/[A-Z]/', '_$0', $identifier)))) { - $objects = $this->getObjectsByIdentifier(constant($constname)); - return isset($objects[0]); - } else { - return isset($this->_objects[$identifier]); - } - } - - /** - * Returns all the objects the file contains as an associate array. The - * object identifiers work as keys having an array of ASF objects as - * associated value. - * - * @return Array - */ - public final function getObjects() - { - return $this->_objects; - } - - /** - * Returns an array of objects matching the given object GUID or an empty - * array if no object matched the identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches - * any single character. - * - * @param string $identifier The object GUID. - * @return Array - */ - public final function getObjectsByIdentifier($identifier) - { - $matches = array(); - $searchPattern = '/^' . - str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; - foreach ($this->_objects as $identifier => $objects) { - if (preg_match($searchPattern, $identifier)) { - foreach ($objects as $object) { - $matches[] = $object; - } - } - } - return $matches; - } - - /** - * Returns an array of objects matching the given object constant name or an - * empty array if no object matched the name. - * - * The object constant name can be given in three forms; either using the - * full name of the constant, the name of the class or the shorthand style - * of the class name having its first letter in lower case. - * - * One may use the shorthand $obj->name to access the first box with the - * name given directly. Shorthands will not work with user defined uuid - * types. - * - * The name may not contain wildcard characters. - * - * @param string $name The object constant name or class name. - * @return Array - */ - public final function getObjectsByName($name) - { - if (defined($constname = get_class($this) . '::' . $name) || - defined($constname = get_class($this) . '::' . strtoupper - (preg_replace - ('/^_/', '', preg_replace('/[A-Z]/', '_$0', $name))))) { - return $this->getObjectsByIdentifier(constant($constname)); - } - return array(); - } - - /** - * Removes any objects matching the given object GUID. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches - * any single character. - * - * One may also use the shorthand unset($obj->name) to achieve the same - * result. Wildcards cannot be used with the shorthand method. - * - * @param string $identifier The object GUID. - */ - public final function removeObjectsByIdentifier($identifier) - { - $searchPattern = '/^' . - str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; - foreach ($this->_objects as $identifier => $objects) { - if (preg_match($searchPattern, $identifier)) { - unset($this->_objects[$identifier]); - } - } - } - - /** - * Removes any objects matching the given object name. - * - * The name can be given in three forms; either using the full name of the - * constant, the name of the class or the shorthand style of the class name - * having its first letter in lower case. - * - * One may also use the shorthand unset($obj->name) to achieve the same - * result. - * - * The name may not contain wildcard characters. - * - * @param string $name The object constant name or class name. - */ - public final function removeObjectsByName($name) - { - if (defined($constname = get_class($this) . '::' . strtoupper - (preg_replace('/[A-Z]/', '_$0', $name)))) { - unset($this->_objects[constant($constname)]); - } - } - - /** - * Adds a new object into the current object and returns it. - * - * @param Zend_Media_Asf_Object $object The object to add - * @return Zend_Media_Asf_Object - */ - public final function addObject($object) - { - $object->setParent($this); - $object->setOptions($this->_options); - if (!$this->hasObject($object->getIdentifier())) { - $this->_objects[$object->getIdentifier()] = array(); - } - return $this->_objects[$object->getIdentifier()][] = $object; - } - - /** - * Removes the object. - * - * @param Zend_Media_Asf_Object $object The object to remove - */ - public final function removeObject($object) - { - if ($this->hasObject($object->getIdentifier())) { - foreach ($this->_objects - [$object->getIdentifier()] as $key => $value) { - if ($object === $value) { - unset($this->_objects[$object->getIdentifier()][$key]); - } - } - } - } - - /** - * Returns the number of objects this container has. - * - * @return integer - */ - public final function getObjectCount() - { - return count($this->_objects); - } - - /** - * Override magic function so that $obj->value will work as expected. - * - * The method first attempts to call the appropriate getter method. If no - * field with given name is found, the method attempts to return the right - * object instead. In other words, calling $obj->value will attempt to - * return the first object returned by - * $this->getObjectsByIdentifier(self::value). If no object is found by the - * given value, a respective class name is tried to instantiate and add to - * the container. - * - * @param string $name The field or object name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - if (method_exists($this, 'is' . ucfirst($name))) { - return call_user_func(array($this, 'is' . ucfirst($name))); - } - if (defined($constname = get_class($this) . '::' . strtoupper - (preg_replace('/[A-Z]/', '_$0', $name)))) { - $objects = $this->getObjectsByIdentifier(constant($constname)); - if (isset($objects[0])) { - return $objects[0]; - } else { - if (@fopen($filename = 'Zend/Media/Asf/Object/' . - ucfirst($name) . '.php', 'r', true) !== false) { - require_once($filename); - } - if (class_exists - ($classname = 'Zend_Media_Asf_Object_' . ucfirst($name))) { - $obj = new $classname(); - $obj->setIdentifier(constant($constname)); - return $this->addObject($obj); - } - } - } - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Unknown field/object: ' . $name); - } - - /** - * Override magic function so that $obj->value will work as expected. - * - * The method first attempts to call the appropriate setter method. If no - * field with given name is found, the method attempts to set the right - * object instead. In other words, assigning to $obj->value will attempt to - * set the object with given value's identifier. - * - * Please note that using this method will override any prior objects having - * the same object identifier. - * - * @param string $name The field or object name. - * @param string $value The field value or object. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } - if (defined($constname = get_class($this) . '::' . strtoupper - (preg_replace('/[A-Z]/', '_$0', $name)))) { - $value->setOptions($this->_options); - $this->_objects[constant($constname)] = array($value); - } else { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception - ('Unknown field/object: ' . $name); - } - } - - /** - * Magic function so that isset($obj->value) will work. This method checks - * whether the object by given identifier or name is contained by this - * container. - * - * @param string $name The object identifier or logical name. - * @return boolean - */ - public function __isset($name) - { - return $this->hasObject($name); - } - - /** - * Magic function so that unset($obj->value) will work. This method removes - * all the objects with the given identifier or name. - * - * @param string $name The object identifier or logical name. - */ - public function __unset($name) - { - $this->removeObjectsByName($name); - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Container.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Asf_Object_Container extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_objects = array(); + + /** + * Reads and constructs the objects found within this object. + */ + protected final function constructObjects($defaultclassnames = array()) + { + while (true) { + $offset = $this->_reader->getOffset(); + if ($offset >= $this->getOffset() + $this->getSize()) { + break; + } + $guid = $this->_reader->readGuid(); + $size = $this->_reader->readInt64LE(); + + $this->_reader->setOffset($offset); + if (isset($defaultclassnames[$guid])) { + if (@fopen($filename = 'Zend/Media/Asf/Object/' . + $defaultclassnames[$guid] . '.php', + 'r', true) !== false) { + require_once($filename); + } + if (class_exists + ($classname = 'Zend_Media_Asf_Object_' . + $defaultclassnames[$guid])) { + $object = new $classname($this->_reader, $this->_options); + } else { + require_once 'Zend/Media/Asf/Object/Unknown.php'; + $object = new Zend_Media_Asf_Object_Unknown + ($this->_reader, $this->_options); + } + } else { + require_once 'Zend/Media/Asf/Object/Unknown.php'; + $object = new Zend_Media_Asf_Object_Unknown + ($this->_reader, $this->_options); + } + $object->setParent($this); + if (!$this->hasObject($object->getIdentifier())) { + $this->_objects[$object->getIdentifier()] = array(); + } + $this->_objects[$object->getIdentifier()][] = $object; + $this->_reader->setOffset($offset + $size); + } + } + + /** + * Checks whether the object with given identifier is present in the file. + * The identifier can either be the object GUID, or name of the constant + * containing the GUID, or the name of the object class. + * + * Returns true if one or more objects are present, + * false otherwise. + * + * @param string $identifier The object GUID, name of the GUID constant, or + * object class name. + * @return boolean + */ + public final function hasObject($identifier) + { + if (defined($constname = get_class($this) . '::' . strtoupper + (preg_replace('/[A-Z]/', '_$0', $identifier)))) { + $objects = $this->getObjectsByIdentifier(constant($constname)); + return isset($objects[0]); + } else { + return isset($this->_objects[$identifier]); + } + } + + /** + * Returns all the objects the file contains as an associate array. The + * object identifiers work as keys having an array of ASF objects as + * associated value. + * + * @return Array + */ + public final function getObjects() + { + return $this->_objects; + } + + /** + * Returns an array of objects matching the given object GUID or an empty + * array if no object matched the identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches + * any single character. + * + * @param string $identifier The object GUID. + * @return Array + */ + public final function getObjectsByIdentifier($identifier) + { + $matches = array(); + $searchPattern = '/^' . + str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; + foreach ($this->_objects as $identifier => $objects) { + if (preg_match($searchPattern, $identifier)) { + foreach ($objects as $object) { + $matches[] = $object; + } + } + } + return $matches; + } + + /** + * Returns an array of objects matching the given object constant name or an + * empty array if no object matched the name. + * + * The object constant name can be given in three forms; either using the + * full name of the constant, the name of the class or the shorthand style + * of the class name having its first letter in lower case. + * + * One may use the shorthand $obj->name to access the first box with the + * name given directly. Shorthands will not work with user defined uuid + * types. + * + * The name may not contain wildcard characters. + * + * @param string $name The object constant name or class name. + * @return Array + */ + public final function getObjectsByName($name) + { + if (defined($constname = get_class($this) . '::' . $name) || + defined($constname = get_class($this) . '::' . strtoupper + (preg_replace + ('/^_/', '', preg_replace('/[A-Z]/', '_$0', $name))))) { + return $this->getObjectsByIdentifier(constant($constname)); + } + return array(); + } + + /** + * Removes any objects matching the given object GUID. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches + * any single character. + * + * One may also use the shorthand unset($obj->name) to achieve the same + * result. Wildcards cannot be used with the shorthand method. + * + * @param string $identifier The object GUID. + */ + public final function removeObjectsByIdentifier($identifier) + { + $searchPattern = '/^' . + str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; + foreach ($this->_objects as $identifier => $objects) { + if (preg_match($searchPattern, $identifier)) { + unset($this->_objects[$identifier]); + } + } + } + + /** + * Removes any objects matching the given object name. + * + * The name can be given in three forms; either using the full name of the + * constant, the name of the class or the shorthand style of the class name + * having its first letter in lower case. + * + * One may also use the shorthand unset($obj->name) to achieve the same + * result. + * + * The name may not contain wildcard characters. + * + * @param string $name The object constant name or class name. + */ + public final function removeObjectsByName($name) + { + if (defined($constname = get_class($this) . '::' . strtoupper + (preg_replace('/[A-Z]/', '_$0', $name)))) { + unset($this->_objects[constant($constname)]); + } + } + + /** + * Adds a new object into the current object and returns it. + * + * @param Zend_Media_Asf_Object $object The object to add + * @return Zend_Media_Asf_Object + */ + public final function addObject($object) + { + $object->setParent($this); + $object->setOptions($this->_options); + if (!$this->hasObject($object->getIdentifier())) { + $this->_objects[$object->getIdentifier()] = array(); + } + return $this->_objects[$object->getIdentifier()][] = $object; + } + + /** + * Removes the object. + * + * @param Zend_Media_Asf_Object $object The object to remove + */ + public final function removeObject($object) + { + if ($this->hasObject($object->getIdentifier())) { + foreach ($this->_objects + [$object->getIdentifier()] as $key => $value) { + if ($object === $value) { + unset($this->_objects[$object->getIdentifier()][$key]); + } + } + } + } + + /** + * Returns the number of objects this container has. + * + * @return integer + */ + public final function getObjectCount() + { + return count($this->_objects); + } + + /** + * Override magic function so that $obj->value will work as expected. + * + * The method first attempts to call the appropriate getter method. If no + * field with given name is found, the method attempts to return the right + * object instead. In other words, calling $obj->value will attempt to + * return the first object returned by + * $this->getObjectsByIdentifier(self::value). If no object is found by the + * given value, a respective class name is tried to instantiate and add to + * the container. + * + * @param string $name The field or object name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + if (method_exists($this, 'is' . ucfirst($name))) { + return call_user_func(array($this, 'is' . ucfirst($name))); + } + if (defined($constname = get_class($this) . '::' . strtoupper + (preg_replace('/[A-Z]/', '_$0', $name)))) { + $objects = $this->getObjectsByIdentifier(constant($constname)); + if (isset($objects[0])) { + return $objects[0]; + } else { + if (@fopen($filename = 'Zend/Media/Asf/Object/' . + ucfirst($name) . '.php', 'r', true) !== false) { + require_once($filename); + } + if (class_exists + ($classname = 'Zend_Media_Asf_Object_' . ucfirst($name))) { + $obj = new $classname(); + $obj->setIdentifier(constant($constname)); + return $this->addObject($obj); + } + } + } + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Unknown field/object: ' . $name); + } + + /** + * Override magic function so that $obj->value will work as expected. + * + * The method first attempts to call the appropriate setter method. If no + * field with given name is found, the method attempts to set the right + * object instead. In other words, assigning to $obj->value will attempt to + * set the object with given value's identifier. + * + * Please note that using this method will override any prior objects having + * the same object identifier. + * + * @param string $name The field or object name. + * @param string $value The field value or object. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } + if (defined($constname = get_class($this) . '::' . strtoupper + (preg_replace('/[A-Z]/', '_$0', $name)))) { + $value->setOptions($this->_options); + $this->_objects[constant($constname)] = array($value); + } else { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception + ('Unknown field/object: ' . $name); + } + } + + /** + * Magic function so that isset($obj->value) will work. This method checks + * whether the object by given identifier or name is contained by this + * container. + * + * @param string $name The object identifier or logical name. + * @return boolean + */ + public function __isset($name) + { + return $this->hasObject($name); + } + + /** + * Magic function so that unset($obj->value) will work. This method removes + * all the objects with the given identifier or name. + * + * @param string $name The object identifier or logical name. + */ + public function __unset($name) + { + $this->removeObjectsByName($name); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ContentBranding.php b/app/libs/vendor/Zend/Media/Asf/Object/ContentBranding.php index cdc2597b..b73b370a 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ContentBranding.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ContentBranding.php @@ -1,203 +1,203 @@ -Content Branding Object stores branding data for an ASF file, - * including information about a banner image and copyright associated with the - * file. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ContentBranding.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ContentBranding extends Zend_Media_Asf_Object -{ - /** Indicates that there is no banner */ - const TYPE_NONE = 0; - - /** Indicates that the data represents a bitmap */ - const TYPE_BMP = 1; - - /** Indicates that the data represents a JPEG */ - const TYPE_JPEG = 2; - - /** Indicates that the data represents a GIF */ - const TYPE_GIF = 3; - - /** @var integer */ - private $_bannerImageType; - - /** @var string */ - private $_bannerImageData; - - /** @var string */ - private $_bannerImageUrl; - - /** @var string */ - private $_copyrightUrl; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_bannerImageType = $this->_reader->readUInt32LE(); - $bannerImageDataSize = $this->_reader->readUInt32LE(); - $this->_bannerImageData = $this->_reader->read($bannerImageDataSize); - $bannerImageUrlLength = $this->_reader->readUInt32LE(); - $this->_bannerImageUrl = $this->_reader->read($bannerImageUrlLength); - $copyrightUrlLength = $this->_reader->readUInt32LE(); - $this->_copyrightUrl = $this->_reader->read($copyrightUrlLength); - } - - /** - * Returns the type of data contained in the Banner Image Data. Valid - * values are 0 to indicate that there is no banner image data; 1 to - * indicate that the data represent a bitmap; 2 to indicate that the data - * represents a JPEG; and 3 to indicate that the data represents a GIF. If - * this value is set to 0, then the Banner Image Data Size field is set - * to 0, and the Banner Image Data field is empty. - * - * @return integer - */ - public function getBannerImageType() - { - return $this->_bannerImageType; - } - - /** - * Sets the type of data contained in the Banner Image Data. Valid - * values are 0 to indicate that there is no banner image data; 1 to - * indicate that the data represent a bitmap; 2 to indicate that the data - * represents a JPEG; and 3 to indicate that the data represents a GIF. If - * this value is set to 0, then the Banner Image Data Size field is set - * to 0, and the Banner Image Data field is empty. - * - * @param integer $bannerImageType The type of data. - */ - public function setBannerImageType($bannerImageType) - { - $this->_bannerImageType = $bannerImageType; - } - - /** - * Returns the entire banner image, including the header for the appropriate - * image format. - * - * @return string - */ - public function getBannerImageData() - { - return $this->_bannerImageData; - } - - /** - * Sets the entire banner image, including the header for the appropriate - * image format. - * - * @param string $bannerImageData The entire banner image. - */ - public function setBannerImageData($bannerImageData) - { - $this->_bannerImageData = $bannerImageData; - } - - /** - * Returns, if present, a link to more information about the banner image. - * - * @return string - */ - public function getBannerImageUrl() - { - return $this->_bannerImageUrl; - } - - /** - * Sets a link to more information about the banner image. - * - * @param string $bannerImageUrl The link. - */ - public function setBannerImageUrl($bannerImageUrl) - { - $this->_bannerImageUrl = $bannerImageUrl; - } - - /** - * Returns, if present, a link to more information about the copyright for - * the content. - * - * @return string - */ - public function getCopyrightUrl() - { - return $this->_copyrightUrl; - } - - /** - * Sets a link to more information about the copyright for the content. - * - * @param string $copyrightUrl The copyright link. - */ - public function setCopyrightUrl($copyrightUrl) - { - $this->_copyrightUrl = $copyrightUrl; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $buffer = new Zend_Io_StringWriter(); - $buffer->writeUInt32LE($this->_bannerImageType) - ->writeUInt32LE(count($this->_bannerImageData)) - ->write($this->_bannerImageData) - ->writeUInt32LE(count($this->_bannerImageUrl)) - ->write($this->_bannerImageUrl) - ->writeUInt32LE(count($this->_copyrightUrl)) - ->write($this->_copyrightUrl); - - $this->setSize(24 /* for header */ + $buffer->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->write($buffer->toString()); - } -} +Content Branding Object stores branding data for an ASF file, + * including information about a banner image and copyright associated with the + * file. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ContentBranding.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ContentBranding extends Zend_Media_Asf_Object +{ + /** Indicates that there is no banner */ + const TYPE_NONE = 0; + + /** Indicates that the data represents a bitmap */ + const TYPE_BMP = 1; + + /** Indicates that the data represents a JPEG */ + const TYPE_JPEG = 2; + + /** Indicates that the data represents a GIF */ + const TYPE_GIF = 3; + + /** @var integer */ + private $_bannerImageType; + + /** @var string */ + private $_bannerImageData; + + /** @var string */ + private $_bannerImageUrl; + + /** @var string */ + private $_copyrightUrl; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_bannerImageType = $this->_reader->readUInt32LE(); + $bannerImageDataSize = $this->_reader->readUInt32LE(); + $this->_bannerImageData = $this->_reader->read($bannerImageDataSize); + $bannerImageUrlLength = $this->_reader->readUInt32LE(); + $this->_bannerImageUrl = $this->_reader->read($bannerImageUrlLength); + $copyrightUrlLength = $this->_reader->readUInt32LE(); + $this->_copyrightUrl = $this->_reader->read($copyrightUrlLength); + } + + /** + * Returns the type of data contained in the Banner Image Data. Valid + * values are 0 to indicate that there is no banner image data; 1 to + * indicate that the data represent a bitmap; 2 to indicate that the data + * represents a JPEG; and 3 to indicate that the data represents a GIF. If + * this value is set to 0, then the Banner Image Data Size field is set + * to 0, and the Banner Image Data field is empty. + * + * @return integer + */ + public function getBannerImageType() + { + return $this->_bannerImageType; + } + + /** + * Sets the type of data contained in the Banner Image Data. Valid + * values are 0 to indicate that there is no banner image data; 1 to + * indicate that the data represent a bitmap; 2 to indicate that the data + * represents a JPEG; and 3 to indicate that the data represents a GIF. If + * this value is set to 0, then the Banner Image Data Size field is set + * to 0, and the Banner Image Data field is empty. + * + * @param integer $bannerImageType The type of data. + */ + public function setBannerImageType($bannerImageType) + { + $this->_bannerImageType = $bannerImageType; + } + + /** + * Returns the entire banner image, including the header for the appropriate + * image format. + * + * @return string + */ + public function getBannerImageData() + { + return $this->_bannerImageData; + } + + /** + * Sets the entire banner image, including the header for the appropriate + * image format. + * + * @param string $bannerImageData The entire banner image. + */ + public function setBannerImageData($bannerImageData) + { + $this->_bannerImageData = $bannerImageData; + } + + /** + * Returns, if present, a link to more information about the banner image. + * + * @return string + */ + public function getBannerImageUrl() + { + return $this->_bannerImageUrl; + } + + /** + * Sets a link to more information about the banner image. + * + * @param string $bannerImageUrl The link. + */ + public function setBannerImageUrl($bannerImageUrl) + { + $this->_bannerImageUrl = $bannerImageUrl; + } + + /** + * Returns, if present, a link to more information about the copyright for + * the content. + * + * @return string + */ + public function getCopyrightUrl() + { + return $this->_copyrightUrl; + } + + /** + * Sets a link to more information about the copyright for the content. + * + * @param string $copyrightUrl The copyright link. + */ + public function setCopyrightUrl($copyrightUrl) + { + $this->_copyrightUrl = $copyrightUrl; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $buffer = new Zend_Io_StringWriter(); + $buffer->writeUInt32LE($this->_bannerImageType) + ->writeUInt32LE(count($this->_bannerImageData)) + ->write($this->_bannerImageData) + ->writeUInt32LE(count($this->_bannerImageUrl)) + ->write($this->_bannerImageUrl) + ->writeUInt32LE(count($this->_copyrightUrl)) + ->write($this->_copyrightUrl); + + $this->setSize(24 /* for header */ + $buffer->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->write($buffer->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ContentDescription.php b/app/libs/vendor/Zend/Media/Asf/Object/ContentDescription.php index 31771be4..37cce7ed 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ContentDescription.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ContentDescription.php @@ -1,240 +1,240 @@ -Content Description Object lets authors record well-known data - * describing the file and its contents. This object is used to store standard - * bibliographic information such as title, author, copyright, description, and - * rating information. This information is pertinent to the entire file. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ContentDescription.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ContentDescription - extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_title; - - /** @var string */ - private $_author; - - /** @var string */ - private $_copyright; - - /** @var string */ - private $_description; - - /** @var string */ - private $_rating; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $titleLen = $this->_reader->readUInt16LE(); - $authorLen = $this->_reader->readUInt16LE(); - $copyrightLen = $this->_reader->readUInt16LE(); - $descriptionLen = $this->_reader->readUInt16LE(); - $ratingLen = $this->_reader->readUInt16LE(); - - $this->_title = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($titleLen)); - $this->_author = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($authorLen)); - $this->_copyright = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($copyrightLen)); - $this->_description = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($descriptionLen)); - $this->_rating = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($ratingLen)); - } - - /** - * Returns the title information. - * - * @return string - */ - public function getTitle() - { - return $this->_title; - } - - /** - * Sets the title information. - * - * @param string $title The title information. - */ - public function setTitle($title) - { - $this->_title = $title; - } - - /** - * Returns the author information. - * - * @return string - */ - public function getAuthor() - { - return $this->_author; - } - - /** - * Sets the author information. - * - * @param string $author The author information. - */ - public function setAuthor($author) - { - $this->_author = $author; - } - - /** - * Returns the copyright information. - * - * @return string - */ - public function getCopyright() - { - return $this->_copyright; - } - - /** - * Sets the copyright information. - * - * @param string $copyright The copyright information. - */ - public function setCopyright($copyright) - { - $this->_copyright = $copyright; - } - - /** - * Returns the description information. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the description information. - * - * @param string $description The description information. - */ - public function setDescription($description) - { - $this->_description = $description; - } - - /** - * Returns the rating information. - * - * @return string - */ - public function getRating() - { - return $this->_rating; - } - - /** - * Sets the rating information. - * - * @param string $rating The rating information. - */ - public function setRating($rating) - { - $this->_rating = $rating; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $title = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_title ? $this->_title . "\0" : ''); - $author = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_author ? $this->_author . "\0" : ''); - $copyright = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_copyright ? $this->_copyright . "\0" : ''); - $description = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_description ? $this->_description . "\0" : ''); - $rating = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_rating ? $this->_rating . "\0" : ''); - - require_once 'Zend/Io/StringWriter.php'; - $buffer = new Zend_Io_StringWriter(); - $buffer->writeUInt16LE(strlen($title)) - ->writeUInt16LE(strlen($author)) - ->writeUInt16LE(strlen($copyright)) - ->writeUInt16LE(strlen($description)) - ->writeUInt16LE(strlen($rating)) - ->writeString16($title) - ->writeString16($author) - ->writeString16($copyright) - ->writeString16($description) - ->writeString16($rating); - - $this->setSize(24 /* for header */ + $buffer->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->write($buffer->toString()); - } -} +Content Description Object lets authors record well-known data + * describing the file and its contents. This object is used to store standard + * bibliographic information such as title, author, copyright, description, and + * rating information. This information is pertinent to the entire file. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ContentDescription.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ContentDescription + extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_title; + + /** @var string */ + private $_author; + + /** @var string */ + private $_copyright; + + /** @var string */ + private $_description; + + /** @var string */ + private $_rating; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $titleLen = $this->_reader->readUInt16LE(); + $authorLen = $this->_reader->readUInt16LE(); + $copyrightLen = $this->_reader->readUInt16LE(); + $descriptionLen = $this->_reader->readUInt16LE(); + $ratingLen = $this->_reader->readUInt16LE(); + + $this->_title = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($titleLen)); + $this->_author = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($authorLen)); + $this->_copyright = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($copyrightLen)); + $this->_description = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($descriptionLen)); + $this->_rating = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($ratingLen)); + } + + /** + * Returns the title information. + * + * @return string + */ + public function getTitle() + { + return $this->_title; + } + + /** + * Sets the title information. + * + * @param string $title The title information. + */ + public function setTitle($title) + { + $this->_title = $title; + } + + /** + * Returns the author information. + * + * @return string + */ + public function getAuthor() + { + return $this->_author; + } + + /** + * Sets the author information. + * + * @param string $author The author information. + */ + public function setAuthor($author) + { + $this->_author = $author; + } + + /** + * Returns the copyright information. + * + * @return string + */ + public function getCopyright() + { + return $this->_copyright; + } + + /** + * Sets the copyright information. + * + * @param string $copyright The copyright information. + */ + public function setCopyright($copyright) + { + $this->_copyright = $copyright; + } + + /** + * Returns the description information. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the description information. + * + * @param string $description The description information. + */ + public function setDescription($description) + { + $this->_description = $description; + } + + /** + * Returns the rating information. + * + * @return string + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Sets the rating information. + * + * @param string $rating The rating information. + */ + public function setRating($rating) + { + $this->_rating = $rating; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $title = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_title ? $this->_title . "\0" : ''); + $author = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_author ? $this->_author . "\0" : ''); + $copyright = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_copyright ? $this->_copyright . "\0" : ''); + $description = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_description ? $this->_description . "\0" : ''); + $rating = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_rating ? $this->_rating . "\0" : ''); + + require_once 'Zend/Io/StringWriter.php'; + $buffer = new Zend_Io_StringWriter(); + $buffer->writeUInt16LE(strlen($title)) + ->writeUInt16LE(strlen($author)) + ->writeUInt16LE(strlen($copyright)) + ->writeUInt16LE(strlen($description)) + ->writeUInt16LE(strlen($rating)) + ->writeString16($title) + ->writeString16($author) + ->writeString16($copyright) + ->writeString16($description) + ->writeString16($rating); + + $this->setSize(24 /* for header */ + $buffer->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->write($buffer->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ContentEncryption.php b/app/libs/vendor/Zend/Media/Asf/Object/ContentEncryption.php index a767817f..c276a9f9 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ContentEncryption.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ContentEncryption.php @@ -1,189 +1,189 @@ -Content Encryption Object lets authors protect content by using - * Microsoft® Digital Rights Manager version 1. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ContentEncryption - extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_secretData; - - /** @var string */ - private $_protectionType; - - /** @var string */ - private $_keyId; - - /** @var string */ - private $_licenseUrl; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $secretDataLength = $this->_reader->readUInt32LE(); - $this->_secretData = $this->_reader->read($secretDataLength); - $protectionTypeLength = $this->_reader->readUInt32LE(); - $this->_protectionType = - $this->_reader->readString8($protectionTypeLength); - $keyIdLength = $this->_reader->readUInt32LE(); - $this->_keyId = $this->_reader->readString8($keyIdLength); - $licenseUrlLength = $this->_reader->readUInt32LE(); - $this->_licenseUrl = $this->_reader->readString8($licenseUrlLength); - } - - /** - * Returns the secret data. - * - * @return string - */ - public function getSecretData() - { - return $this->_secretData; - } - - /** - * Sets the secret data. - * - * @param string $secretData The secret data. - */ - public function setSecretData($secretData) - { - $this->_secretData = $secretData; - } - - /** - * Returns the type of protection mechanism used. The value of this field - * is set to 'DRM'. - * - * @return string - */ - public function getProtectionType() - { - return $this->_protectionType; - } - - /** - * Sets the type of protection mechanism used. The value of this field - * is to be set to 'DRM'. - * - * @param string $protectionType The protection mechanism used. - */ - public function setProtectionType($protectionType) - { - $this->_protectionType = $protectionType; - } - - /** - * Returns the key ID used. - * - * @return string - */ - public function getKeyId() - { - return $this->_keyId; - } - - /** - * Sets the key ID used. - * - * @param string $keyId The key ID used. - */ - public function setKeyId($keyId) - { - $this->_keyId = $keyId; - } - - /** - * Returns the URL from which a license to manipulate the content can be - * acquired. - * - * @return string - */ - public function getLicenseUrl() - { - return $this->_licenseUrl; - } - - /** - * Returns the URL from which a license to manipulate the content can be - * acquired. - * - * @param string $licenseUrl The URL from which a license can be acquired. - */ - public function setLicenseUrl($licenseUrl) - { - $this->_licenseUrl = $licenseUrl; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $buffer = new Zend_Io_StringWriter(); - $buffer->writeUInt32LE(strlen($this->_secretData)) - ->write($this->_secretData) - ->writeUInt32LE($len = strlen($this->_protectionType) + 1) - ->writeString8($this->_protectionType, $len) - ->writeUInt32LE($len = strlen($this->_keyId) + 1) - ->writeString8($this->_keyId, $len) - ->writeUInt32LE($len = strlen($this->_licenseUrl) + 1) - ->writeString8($this->_licenseUrl, $len); - - $this->setSize(24 /* for header */ + $buffer->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->write($buffer->toString()); - } -} +Content Encryption Object lets authors protect content by using + * Microsoft® Digital Rights Manager version 1. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ContentEncryption + extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_secretData; + + /** @var string */ + private $_protectionType; + + /** @var string */ + private $_keyId; + + /** @var string */ + private $_licenseUrl; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $secretDataLength = $this->_reader->readUInt32LE(); + $this->_secretData = $this->_reader->read($secretDataLength); + $protectionTypeLength = $this->_reader->readUInt32LE(); + $this->_protectionType = + $this->_reader->readString8($protectionTypeLength); + $keyIdLength = $this->_reader->readUInt32LE(); + $this->_keyId = $this->_reader->readString8($keyIdLength); + $licenseUrlLength = $this->_reader->readUInt32LE(); + $this->_licenseUrl = $this->_reader->readString8($licenseUrlLength); + } + + /** + * Returns the secret data. + * + * @return string + */ + public function getSecretData() + { + return $this->_secretData; + } + + /** + * Sets the secret data. + * + * @param string $secretData The secret data. + */ + public function setSecretData($secretData) + { + $this->_secretData = $secretData; + } + + /** + * Returns the type of protection mechanism used. The value of this field + * is set to 'DRM'. + * + * @return string + */ + public function getProtectionType() + { + return $this->_protectionType; + } + + /** + * Sets the type of protection mechanism used. The value of this field + * is to be set to 'DRM'. + * + * @param string $protectionType The protection mechanism used. + */ + public function setProtectionType($protectionType) + { + $this->_protectionType = $protectionType; + } + + /** + * Returns the key ID used. + * + * @return string + */ + public function getKeyId() + { + return $this->_keyId; + } + + /** + * Sets the key ID used. + * + * @param string $keyId The key ID used. + */ + public function setKeyId($keyId) + { + $this->_keyId = $keyId; + } + + /** + * Returns the URL from which a license to manipulate the content can be + * acquired. + * + * @return string + */ + public function getLicenseUrl() + { + return $this->_licenseUrl; + } + + /** + * Returns the URL from which a license to manipulate the content can be + * acquired. + * + * @param string $licenseUrl The URL from which a license can be acquired. + */ + public function setLicenseUrl($licenseUrl) + { + $this->_licenseUrl = $licenseUrl; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $buffer = new Zend_Io_StringWriter(); + $buffer->writeUInt32LE(strlen($this->_secretData)) + ->write($this->_secretData) + ->writeUInt32LE($len = strlen($this->_protectionType) + 1) + ->writeString8($this->_protectionType, $len) + ->writeUInt32LE($len = strlen($this->_keyId) + 1) + ->writeString8($this->_keyId, $len) + ->writeUInt32LE($len = strlen($this->_licenseUrl) + 1) + ->writeString8($this->_licenseUrl, $len); + + $this->setSize(24 /* for header */ + $buffer->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->write($buffer->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Data.php b/app/libs/vendor/Zend/Media/Asf/Object/Data.php index 3312fbc3..c5149c1a 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Data.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Data.php @@ -1,118 +1,118 @@ -Data Object contains all of the Data Packets for a file. - * These Data Packets are organized in terms of increasing send times. A Data - * Packet can contain interleaved data from several digital media streams. - * This data can consist of entire objects from one or more streams. - * Alternatively, it can consist of partial objects (fragmentation). - * - * Capabilities provided within the interleave packet definition include: - * o Single or multiple payload types per Data Packet - * o Fixed-size Data Packets - * o Error correction information (optional) - * o Clock information (optional) - * o Redundant sample information, such as presentation time stamp (optional) - * - * Please note that the data packets are not parsed. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Data.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Data extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_fileId; - - /** @var integer */ - private $_totalDataPackets; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_fileId = $this->_reader->readGuid(); - $this->_totalDataPackets = $this->_reader->readInt64LE(); - $this->_reader->skip(2); - -// No support for Data Packets as of yet (if ever) -// for ($i = 0; $i < $this->_totalDataPackets; $i++) -// $this->_dataPackets[] = -// new Zend_Media_Asf_Object_Data_Packet($reader); - } - - /** - * Returns the unique identifier for this ASF file. The value of this field - * is changed every time the file is modified in any way. The value of this - * field is identical to the value of the File ID field of the - * Header Object. - * - * @return string - */ - public function getFileId() - { - return $this->_fileId; - } - - /** - * Returns the number of ASF Data Packet entries that exist within the - * Data Object. It must be equal to the Data Packet Count - * field in the File Properties Object. The value of this field is - * invalid if the broadcast flag field of the File Properties Object - * is set to 1. - * - * @return integer - */ - public function getTotalDataPackets() - { - return $this->_totalDataPackets; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Data Object contains all of the Data Packets for a file. + * These Data Packets are organized in terms of increasing send times. A Data + * Packet can contain interleaved data from several digital media streams. + * This data can consist of entire objects from one or more streams. + * Alternatively, it can consist of partial objects (fragmentation). + * + * Capabilities provided within the interleave packet definition include: + * o Single or multiple payload types per Data Packet + * o Fixed-size Data Packets + * o Error correction information (optional) + * o Clock information (optional) + * o Redundant sample information, such as presentation time stamp (optional) + * + * Please note that the data packets are not parsed. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Data.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Data extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_fileId; + + /** @var integer */ + private $_totalDataPackets; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_fileId = $this->_reader->readGuid(); + $this->_totalDataPackets = $this->_reader->readInt64LE(); + $this->_reader->skip(2); + +// No support for Data Packets as of yet (if ever) +// for ($i = 0; $i < $this->_totalDataPackets; $i++) +// $this->_dataPackets[] = +// new Zend_Media_Asf_Object_Data_Packet($reader); + } + + /** + * Returns the unique identifier for this ASF file. The value of this field + * is changed every time the file is modified in any way. The value of this + * field is identical to the value of the File ID field of the + * Header Object. + * + * @return string + */ + public function getFileId() + { + return $this->_fileId; + } + + /** + * Returns the number of ASF Data Packet entries that exist within the + * Data Object. It must be equal to the Data Packet Count + * field in the File Properties Object. The value of this field is + * invalid if the broadcast flag field of the File Properties Object + * is set to 1. + * + * @return integer + */ + public function getTotalDataPackets() + { + return $this->_totalDataPackets; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/DigitalSignature.php b/app/libs/vendor/Zend/Media/Asf/Object/DigitalSignature.php index bd83ef0c..689762e2 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/DigitalSignature.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/DigitalSignature.php @@ -1,125 +1,125 @@ -Digital Signature Object lets authors sign the portion of their - * header that lies between the end of the File Properties Object and the - * beginning of the Digital Signature Object. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: DigitalSignature.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_DigitalSignature extends Zend_Media_Asf_Object -{ - /** @var integer */ - private $_type; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_type = $this->_reader->readUInt32LE(); - $dataLength = $this->_reader->readUInt32LE(); - $this->_data = $this->_reader->read($dataLength); - } - - /** - * Returns the type of digital signature used. This field is set to 2. - * - * @return integer - */ - public function getType() - { - return $this->_type; - } - - /** - * Sets the type of digital signature used. This field must be set to 2. - * - - * @param integer $type The type of digital signature used. - */ - public function setType($type) - { - $this->_type = $type; - } - - /** - * Returns the digital signature data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the digital signature data. - * - * @return string - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $this->setSize(24 /* for header */ + 8 + strlen($this->_data)); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt32LE($this->_type) - ->writeUInt32LE(strlen($this->_data)) - ->write($this->_data); - } -} +Digital Signature Object lets authors sign the portion of their + * header that lies between the end of the File Properties Object and the + * beginning of the Digital Signature Object. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: DigitalSignature.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_DigitalSignature extends Zend_Media_Asf_Object +{ + /** @var integer */ + private $_type; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_type = $this->_reader->readUInt32LE(); + $dataLength = $this->_reader->readUInt32LE(); + $this->_data = $this->_reader->read($dataLength); + } + + /** + * Returns the type of digital signature used. This field is set to 2. + * + * @return integer + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets the type of digital signature used. This field must be set to 2. + * + + * @param integer $type The type of digital signature used. + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Returns the digital signature data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the digital signature data. + * + * @return string + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $this->setSize(24 /* for header */ + 8 + strlen($this->_data)); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt32LE($this->_type) + ->writeUInt32LE(strlen($this->_data)) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ErrorCorrection.php b/app/libs/vendor/Zend/Media/Asf/Object/ErrorCorrection.php index 336e07be..248a129d 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ErrorCorrection.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ErrorCorrection.php @@ -1,136 +1,136 @@ -Error Correction Object defines the error correction method. This - * enables different error correction schemes to be used during content - * creation. The Error Correction Object contains provisions for opaque - * information needed by the error correction engine for recovery. For example, - * if the error correction scheme were a simple N+1 parity scheme, then the - * value of N would have to be available in this object. - * - - * Note that this does not refer to the same thing as the Error Correction - * Type field in the {@link Zend_Media_Asf_Object_StreamProperties Stream - * Properties Object}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ErrorCorrection.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ErrorCorrection extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_type; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_type = $this->_reader->readGuid(); - $dataLength = $this->_reader->readUInt32LE(); - $this->_data = $this->_reader->read($dataLength); - } - - /** - * Returns the type of error correction. - * - * @return string - */ - public function getType() - { - return $this->_type; - } - - /** - * Sets the type of error correction. - * - * @param string $type The type of error correction. - */ - public function setType($type) - { - $this->_type = $type; - } - - /** - * Returns the data specific to the error correction scheme. The structure - * for the Error Correction Data field is determined by the value - * stored in the Error Correction Type field. - * - * @return Array - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the data specific to the error correction scheme. The structure for - * the Error Correction Data field is determined by the value stored - * in the Error Correction Type field. - * - * @param Array $data The error correction specific data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $this->setSize(24 /* for header */ + 20 + strlen($this->_data)); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_type) - ->writeUInt32LE(strlen($this->_data)) - ->write($this->_data); - } -} +Error Correction Object defines the error correction method. This + * enables different error correction schemes to be used during content + * creation. The Error Correction Object contains provisions for opaque + * information needed by the error correction engine for recovery. For example, + * if the error correction scheme were a simple N+1 parity scheme, then the + * value of N would have to be available in this object. + * + + * Note that this does not refer to the same thing as the Error Correction + * Type field in the {@link Zend_Media_Asf_Object_StreamProperties Stream + * Properties Object}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ErrorCorrection.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ErrorCorrection extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_type; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_type = $this->_reader->readGuid(); + $dataLength = $this->_reader->readUInt32LE(); + $this->_data = $this->_reader->read($dataLength); + } + + /** + * Returns the type of error correction. + * + * @return string + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets the type of error correction. + * + * @param string $type The type of error correction. + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Returns the data specific to the error correction scheme. The structure + * for the Error Correction Data field is determined by the value + * stored in the Error Correction Type field. + * + * @return Array + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the data specific to the error correction scheme. The structure for + * the Error Correction Data field is determined by the value stored + * in the Error Correction Type field. + * + * @param Array $data The error correction specific data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $this->setSize(24 /* for header */ + 20 + strlen($this->_data)); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_type) + ->writeUInt32LE(strlen($this->_data)) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentDescription.php b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentDescription.php index b584dc3c..5e10a641 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentDescription.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentDescription.php @@ -1,230 +1,230 @@ -Extended Content Description Object object implementation. This - * object contains unlimited number of attribute fields giving more information - * about the file. - * - * @todo Implement better handling of various types of attributes - * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ExtendedContentDescription.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ExtendedContentDescription - extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_contentDescriptors = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $contentDescriptorsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $contentDescriptorsCount; $i++) { - $nameLen = $this->_reader->readUInt16LE(); - $name = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($nameLen)); - $valueDataType = $this->_reader->readUInt16LE(); - $valueLen = $this->_reader->readUInt16LE(); - - switch ($valueDataType) { - case 0: // string - $this->_contentDescriptors[$name] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($valueLen)); - break; - case 1: // byte array - $this->_contentDescriptors[$name] = - $this->_reader->read($valueLen); - break; - case 2: // bool - $this->_contentDescriptors[$name] = - $this->_reader->readUInt32LE() == 1 ? true : false; - break; - case 3: // 32-bit integer - $this->_contentDescriptors[$name] = - $this->_reader->readUInt32LE(); - break; - case 4: // 64-bit integer - $this->_contentDescriptors[$name] = - $this->_reader->readInt64LE(); - break; - case 5: // 16-bit integer - $this->_contentDescriptors[$name] = - $this->_reader->readUInt16LE(); - break; - default: - break; - } - } - } - - /** - * Returns the value of the specified descriptor or false if - * there is no such descriptor defined. - * - * @param string $name The name of the descriptor (ie the name of the - * field). - * @return string|false - */ - public function getDescriptor($name) - { - if (isset($this->_contentDescriptors[$name])) { - return $this->_contentDescriptors[$name]; - } - return false; - } - - /** - * Sets the given descriptor a new value. - * - * @param string $name The name of the descriptor. - * @param string $value The value of the field. - * @return string|false - */ - public function setDescriptor($name, $value) - { - $this->_contentDescriptors[$name] = $value; - } - - /** - * Returns an associate array of all the descriptors defined having the - * names of the descriptors as the keys. - * - * @return Array - */ - public function getDescriptors() - { - return $this->_contentDescriptors; - } - - /** - * Sets the content descriptor associate array having the descriptor names - * as array keys and their values as associated value. The descriptor names - * and all string values must be encoded in the default character encoding - * given as an option to {@link Zend_Media_Asf} class. - * - * @param Array $contentDescriptors The content descriptors - */ - public function setDescriptors($contentDescriptors) - { - $this->_contentDescriptors = $contentDescriptors; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $contentDescriptorsCount = count($this->_contentDescriptors); - $contentDescriptorsWriter = new Zend_Io_StringWriter(); - foreach ($this->_contentDescriptors as $name => $value) { - $descriptor = iconv - ($this->getOption('encoding'), 'utf-16le', - $name ? $name . "\0" : ''); - $contentDescriptorsWriter - ->writeUInt16LE(strlen($descriptor)) - ->writeString16($descriptor); - - if (is_string($value)) { - /* There is no way to distinguish byte arrays from unicode - * strings and hence the need for a list of fields of type - * byte array */ - static $byteArray = array ( - "W\0M\0/\0M\0C\0D\0I\0\0\0", - "W\0M\0/\0U\0s\0e\0r\0W\0e\0b\0U\0R\0L\0\0\0", - "W\0M\0/\0L\0y\0r\0i\0c\0s\0_\0S\0y\0n\0c\0h\0r\0o\0n\0i\0s\0e\0d\0\0\0", - "W\0M\0/\0P\0i\0c\0t\0u\0r\0e\0\0\0" - ); // TODO: Add to the list if you encounter one - - if (in_array($descriptor, $byteArray)) { - $contentDescriptorsWriter - ->writeUInt16LE(1) - ->writeUInt16LE(strlen($value)) - ->write($value); - } else { - $value = iconv - ($this->getOption('encoding'), 'utf-16le', $value) . - "\0\0"; - $contentDescriptorsWriter - ->writeUInt16LE(0) - ->writeUInt16LE(strlen($value)) - ->writeString16($value); - } - } else if (is_bool($value)) { - $contentDescriptorsWriter - ->writeUInt16LE(2) - ->writeUInt16LE(4) - ->writeUInt32LE($value ? 1 : 0); - } else if (is_int($value)) { - $contentDescriptorsWriter - ->writeUInt16LE(3) - ->writeUInt16LE(4) - ->writeUInt32LE($value); - } else if (is_float($value)) { - $contentDescriptorsWriter - ->writeUInt16LE(4) - ->writeUInt16LE(8) - ->writeInt64LE($value); - } else { - // Invalid value and there is nothing to be done - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Invalid data type'); - } - } - - $this->setSize - (24 /* for header */ + 2 + $contentDescriptorsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($contentDescriptorsCount) - ->write($contentDescriptorsWriter->toString()); - } -} +Extended Content Description Object object implementation. This + * object contains unlimited number of attribute fields giving more information + * about the file. + * + * @todo Implement better handling of various types of attributes + * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ExtendedContentDescription.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ExtendedContentDescription + extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_contentDescriptors = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $contentDescriptorsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $contentDescriptorsCount; $i++) { + $nameLen = $this->_reader->readUInt16LE(); + $name = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($nameLen)); + $valueDataType = $this->_reader->readUInt16LE(); + $valueLen = $this->_reader->readUInt16LE(); + + switch ($valueDataType) { + case 0: // string + $this->_contentDescriptors[$name] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($valueLen)); + break; + case 1: // byte array + $this->_contentDescriptors[$name] = + $this->_reader->read($valueLen); + break; + case 2: // bool + $this->_contentDescriptors[$name] = + $this->_reader->readUInt32LE() == 1 ? true : false; + break; + case 3: // 32-bit integer + $this->_contentDescriptors[$name] = + $this->_reader->readUInt32LE(); + break; + case 4: // 64-bit integer + $this->_contentDescriptors[$name] = + $this->_reader->readInt64LE(); + break; + case 5: // 16-bit integer + $this->_contentDescriptors[$name] = + $this->_reader->readUInt16LE(); + break; + default: + break; + } + } + } + + /** + * Returns the value of the specified descriptor or false if + * there is no such descriptor defined. + * + * @param string $name The name of the descriptor (ie the name of the + * field). + * @return string|false + */ + public function getDescriptor($name) + { + if (isset($this->_contentDescriptors[$name])) { + return $this->_contentDescriptors[$name]; + } + return false; + } + + /** + * Sets the given descriptor a new value. + * + * @param string $name The name of the descriptor. + * @param string $value The value of the field. + * @return string|false + */ + public function setDescriptor($name, $value) + { + $this->_contentDescriptors[$name] = $value; + } + + /** + * Returns an associate array of all the descriptors defined having the + * names of the descriptors as the keys. + * + * @return Array + */ + public function getDescriptors() + { + return $this->_contentDescriptors; + } + + /** + * Sets the content descriptor associate array having the descriptor names + * as array keys and their values as associated value. The descriptor names + * and all string values must be encoded in the default character encoding + * given as an option to {@link Zend_Media_Asf} class. + * + * @param Array $contentDescriptors The content descriptors + */ + public function setDescriptors($contentDescriptors) + { + $this->_contentDescriptors = $contentDescriptors; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $contentDescriptorsCount = count($this->_contentDescriptors); + $contentDescriptorsWriter = new Zend_Io_StringWriter(); + foreach ($this->_contentDescriptors as $name => $value) { + $descriptor = iconv + ($this->getOption('encoding'), 'utf-16le', + $name ? $name . "\0" : ''); + $contentDescriptorsWriter + ->writeUInt16LE(strlen($descriptor)) + ->writeString16($descriptor); + + if (is_string($value)) { + /* There is no way to distinguish byte arrays from unicode + * strings and hence the need for a list of fields of type + * byte array */ + static $byteArray = array ( + "W\0M\0/\0M\0C\0D\0I\0\0\0", + "W\0M\0/\0U\0s\0e\0r\0W\0e\0b\0U\0R\0L\0\0\0", + "W\0M\0/\0L\0y\0r\0i\0c\0s\0_\0S\0y\0n\0c\0h\0r\0o\0n\0i\0s\0e\0d\0\0\0", + "W\0M\0/\0P\0i\0c\0t\0u\0r\0e\0\0\0" + ); // TODO: Add to the list if you encounter one + + if (in_array($descriptor, $byteArray)) { + $contentDescriptorsWriter + ->writeUInt16LE(1) + ->writeUInt16LE(strlen($value)) + ->write($value); + } else { + $value = iconv + ($this->getOption('encoding'), 'utf-16le', $value) . + "\0\0"; + $contentDescriptorsWriter + ->writeUInt16LE(0) + ->writeUInt16LE(strlen($value)) + ->writeString16($value); + } + } else if (is_bool($value)) { + $contentDescriptorsWriter + ->writeUInt16LE(2) + ->writeUInt16LE(4) + ->writeUInt32LE($value ? 1 : 0); + } else if (is_int($value)) { + $contentDescriptorsWriter + ->writeUInt16LE(3) + ->writeUInt16LE(4) + ->writeUInt32LE($value); + } else if (is_float($value)) { + $contentDescriptorsWriter + ->writeUInt16LE(4) + ->writeUInt16LE(8) + ->writeInt64LE($value); + } else { + // Invalid value and there is nothing to be done + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Invalid data type'); + } + } + + $this->setSize + (24 /* for header */ + 2 + $contentDescriptorsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($contentDescriptorsCount) + ->write($contentDescriptorsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentEncryption.php b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentEncryption.php index cbb8cadd..9801db6b 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentEncryption.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedContentEncryption.php @@ -1,101 +1,101 @@ -Extended Content Encryption Object lets authors protect content by - * using the Windows Media Rights Manager 7 Software Development Kit (SDK). - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ExtendedContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ExtendedContentEncryption - extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $dataSize = $this->_reader->readUInt32LE(); - $this->_data = $this->_reader->read($dataSize); - } - - /** - * Returns the array of bytes required by the DRM client to manipulate the - * protected content. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the array of bytes required by the DRM client to manipulate the - * protected content. - * - * @param string $data The data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $this->setSize(24 /* for header */ + 4 + strlen($this->_data)); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt32LE(strlen($this->_data)) - ->write($this->_data); - } -} +Extended Content Encryption Object lets authors protect content by + * using the Windows Media Rights Manager 7 Software Development Kit (SDK). + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ExtendedContentEncryption.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ExtendedContentEncryption + extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $dataSize = $this->_reader->readUInt32LE(); + $this->_data = $this->_reader->read($dataSize); + } + + /** + * Returns the array of bytes required by the DRM client to manipulate the + * protected content. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the array of bytes required by the DRM client to manipulate the + * protected content. + * + * @param string $data The data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $this->setSize(24 /* for header */ + 4 + strlen($this->_data)); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt32LE(strlen($this->_data)) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedStreamProperties.php b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedStreamProperties.php index 6fb16069..7eaf1c55 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ExtendedStreamProperties.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ExtendedStreamProperties.php @@ -1,709 +1,709 @@ -Extended Stream Properties Object defines additional optional - * properties and characteristics of a digital media stream that are not - * described in the Stream Properties Object. - * - * Typically, the basic Stream Properties Object is present in the - * Header Object, and the Extended Stream Properties Object is - * present in the Header Extension Object. Sometimes, however, the - * Stream Properties Object for a stream may be embedded inside the - * Extended Stream Properties Object for that stream. This approach - * facilitates the creation of backward-compatible content. - * - * This object has an optional provision to include application-specific or - * implementation-specific data attached to the payloads of each digital media - * sample stored within a Data Packet. This data can be looked at as - * digital media sample properties and is stored in the Replicated Data - * field of a payload header. The Payload Extension Systems fields of the - * Extended Stream Properties Object describes what this data is and is - * necessary for that data to be parsed, if present. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ExtendedStreamProperties.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ExtendedStreamProperties - extends Zend_Media_Asf_Object -{ - /** - * Indicates, if set, that this digital media stream, if sent over a - * network, must be carried over a reliable data communications transport - * mechanism. This should be set for streams that cannot recover after a - * lost media object. - */ - const RELIABLE = 1; - - /** - * This flag should be set only if the stream is seekable, either by using - * an index object or by estimating according to bit rate (as can sometimes - * be done with audio). This flag pertains to this stream only rather than - * to the entire file. - */ - const SEEKABLE = 2; - - /** - * Indicates, if set, that the stream does not contain any cleanpoints. A - * cleanpoint is any point at which playback could begin without having seen - * the previous media objects. For streams that use key frames, the key - * frames would be the cleanpoints. - */ - const NO_CLEANPOINT = 4; - - /** - * Specifies, if set, that when a stream is joined in mid-transmission, all - * information from the most recent cleanpoint up to the current time should - * be sent before normal streaming begins at the current time. The default - * behavior (when this flag is not set) is to send only the data starting at - * the current time. This flag should only be set for streams that are - * coming from a live source. - */ - const RESEND_LIVE_CLEANPOINTS = 8; - - const AUDIO_MEDIA = 'f8699e40-5b4d-11cf-a8fd-00805f5c442b'; - const VIDEO_MEDIA = 'bc19efc0-5b4d-11cf-a8fd-00805f5c442b'; - const COMMAND_MEDIA = '59dacfc0-59e6-11d0-a3ac-00a0c90348f6'; - const JFIF_MEDIA = 'b61be100-5b4e-11cf-a8fD-00805f5c442b'; - const DEGRADABLE_JPEG_MEDIA = '35907dE0-e415-11cf-a917-00805f5c442b'; - const FILE_TRANSFER_MEDIA = '91bd222c-f21c-497a-8b6d-5aa86bfc0185'; - const BINARY_MEDIA = '3afb65e2-47ef-40f2-ac2c-70a90d71d343'; - - const NO_ERROR_CORRECTION = '20fb5700-5b55-11cf-a8fd-00805f5c442b'; - const AUDIO_SPREAD = 'bfc3cd50-618f-11cf-8bb2-00aa00b4e220'; - - const PAYLOAD_EXTENSION_SYSTEM_TIMECODE = - '399595ec-8667-4e2d-8fdb-98814ce76c1e'; - const PAYLOAD_EXTENSION_SYSTEM_FILE_NAME = - 'e165ec0e-19ed-45d7-b4a7-25cbd1e28e9b'; - const PAYLOAD_EXTENSION_SYSTEM_CONTENT_TYPE = - 'd590dc20-07bc-436c-9cf7-f3bbfbf1a4dc'; - const PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO = - '1b1ee554-f9ea-4bc8-821a-376b74e4c4b8'; - const PAYLOAD_EXTENSION_SYSTEM_SAMPLE_DURATION = - 'c6bd9450-867f-4907-83a3-c77921b733ad'; - const PAYLOAD_EXTENSION_SYSTEM_ENCRYPTION_SAMPLE_ID = - '6698b84e-0afa-4330-aeb2-1c0a98d7a44d'; - - /** @var integer */ - private $_startTime; - - /** @var integer */ - private $_endTime; - - /** @var integer */ - private $_dataBitrate; - - /** @var integer */ - private $_bufferSize; - - /** @var integer */ - private $_initialBufferFullness; - - /** @var integer */ - private $_alternateDataBitrate; - - /** @var integer */ - private $_alternateBufferSize; - - /** @var integer */ - private $_alternateInitialBufferFullness; - - /** @var integer */ - private $_maximumObjectSize; - - /** @var integer */ - private $_flags; - - /** @var integer */ - private $_streamNumber; - - /** @var integer */ - private $_streamLanguageIndex; - - /** @var integer */ - private $_averageTimePerFrame; - - /** @var Array */ - private $_streamNames = array(); - - /** @var Array */ - private $_payloadExtensionSystems = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_startTime = $this->_reader->readInt64LE(); - $this->_endTime = $this->_reader->readInt64LE(); - $this->_dataBitrate = $this->_reader->readUInt32LE(); - $this->_bufferSize = $this->_reader->readUInt32LE(); - $this->_initialBufferFullness = $this->_reader->readUInt32LE(); - $this->_alternateDataBitrate = $this->_reader->readUInt32LE(); - $this->_alternateBufferSize = $this->_reader->readUInt32LE(); - $this->_alternateInitialBufferFullness = $this->_reader->readUInt32LE(); - $this->_maximumObjectSize = $this->_reader->readUInt32LE(); - $this->_flags = $this->_reader->readUInt32LE(); - $this->_streamNumber = $this->_reader->readUInt16LE(); - $this->_streamLanguageIndex = $this->_reader->readUInt16LE(); - $this->_averageTimePerFrame = $this->_reader->readInt64LE(); - $streamNameCount = $this->_reader->readUInt16LE(); - $payloadExtensionSystemCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $streamNameCount; $i++) { - $streamName = - array('languageIndex' => $this->_reader->readUInt16LE()); - $streamNameLength = $this->_reader->readUInt16LE(); - $streamName['streamName'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($streamNameLength)); - $this->_streamNames[] = $streamName; - } - for ($i = 0; $i < $payloadExtensionSystemCount; $i++) { - $payloadExtensionSystem = array - ('extensionSystemId' => $this->_reader->readGuid(), - 'extensionDataSize' => $this->_reader->readUInt16LE()); - $extensionSystemInfoLength = $this->_reader->readUInt32LE(); - $payloadExtensionSystem['extensionSystemInfo'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($extensionSystemInfoLength)); - $this->_payloadExtensionSystems[] = $payloadExtensionSystem; - } - } - - /** - * Returns the presentation time of the first object, indicating where this - * digital media stream starts within the context of the timeline of the ASF - * file as a whole. This time value corresponds to presentation times as - * they appear in the data packets (adjusted by the preroll). This field is - * given in units of milliseconds and can optionally be set to 0, in which - * case it will be ignored. - * - * @return integer - */ - public function getStartTime() - { - return $this->_startTime; - } - - /** - * Sets the presentation time of the first object, indicating where this - * digital media stream starts within the context of the timeline of the ASF - * file as a whole. This time value corresponds to presentation times as - * they appear in the data packets (adjusted by the preroll). - * - * The given value must be in units of milliseconds or optionally be set to - * 0, in which case the field will be ignored. - * - * @param integer $startTime The presentation time of the first object. - */ - public function setStartTime($startTime) - { - $this->_startTime = $startTime; - } - - /** - * Returns the presentation time of the last object plus the duration of - * play, indicating where this digital media stream ends within the context - * of the timeline of the ASF file as a whole. This time value corresponds - * to presentation times as they appear in the data packets (adjusted by the - * preroll). This field is given in units of milliseconds and can optionally - * be set to 0, in which case it will be ignored. - * - * @return integer - */ - public function getEndTime() - { - return $this->_endTime; - } - - /** - * Sets the presentation time of the last object plus the duration of play, - * indicating where this digital media stream ends within the context of the - * timeline of the ASF file as a whole. This time value corresponds to - * presentation times as they appear in the data packets (adjusted by the - * preroll). - * - * The given value must be given in units of milliseconds or optionally be - * set to 0, in which case the field will be ignored. - * - * @param integer $endTime The presentation time of the last object plus the - * duration of play. - */ - public function setEndTime($endTime) - { - $this->_endTime = $endTime; - } - - /** - * Returns the leak rate R, in bits per second, of a leaky bucket that - * contains the data portion of the stream without overflowing, excluding - * all ASF Data Packet overhead. The size of the leaky bucket is specified - * by the value of the Buffer Size field. This field has a non-zero - * value. - * - * @return integer - */ - public function getDataBitrate() - { - return $this->_dataBitrate; - } - - /** - * Sets the leak rate R, in bits per second, of a leaky bucket that - * contains the data portion of the stream without overflowing, excluding - * all ASF Data Packet overhead. The size of the leaky bucket is specified - * by the value of the Buffer Size field. - * - * This field must be given a non-zero value. - * - * @param integer $dataBitrate The leak rate. - */ - public function setDataBitrate($dataBitrate) - { - $this->_dataBitrate = $dataBitrate; - } - - /** - * Returns the size B, in milliseconds, of the leaky bucket used in the - * Data Bitrate definition. - * - * @return integer - */ - public function getBufferSize() - { - return $this->_bufferSize; - } - - /** - * Sets the size B, in milliseconds, of the leaky bucket used in the - * Data Bitrate definition. - * - * @param integer $bufferSize The size. - */ - public function setBufferSize($bufferSize) - { - $this->_bufferSize = $bufferSize; - } - - /** - * Returns the initial fullness, in milliseconds, of the leaky bucket used - * in the Data Bitrate definition. This is the fullness of the buffer - * at the instant before the first bit in the stream is dumped into the - * bucket. Typically, this value is set to 0. This value shall not exceed - * the value in the Buffer Size field. - * - * @return integer - */ - public function getInitialBufferFullness() - { - return $this->_initialBufferFullness; - } - - /** - * Sets the initial fullness, in milliseconds, of the leaky bucket used in - * the Data Bitrate definition. This is the fullness of the buffer at - * the instant before the first bit in the stream is dumped into the bucket. - * Typically, this value is set to 0. This value shall not exceed the value - * in the Buffer Size field. - * - * @param integer $initialBufferFullness The initial fullness. - */ - public function setInitialBufferFullness($initialBufferFullness) - { - $this->_initialBufferFullness = $initialBufferFullness; - } - - /** - * Returns the leak rate RAlt, in bits per second, of a leaky bucket that - * contains the data portion of the stream without overflowing, excluding - * all ASF Data Packet overhead. The size of the leaky bucket is - * specified by the value of the Alternate Buffer Size field. This - * value is relevant in most scenarios where the bit rate is not exactly - * constant, but it is especially useful for streams that have highly - * variable bit rates. This field can optionally be set to the same value - * as the Data Bitrate field. - * - * @return integer - */ - public function getAlternateDataBitrate() - { - return $this->_alternateDataBitrate; - } - - /** - * Sets the leak rate RAlt, in bits per second, of a leaky bucket that - * contains the data portion of the stream without overflowing, excluding - * all ASF Data Packet overhead. The size of the leaky bucket is - * specified by the value of the Alternate Buffer Size field. This - * value is relevant in most scenarios where the bit rate is not exactly - * constant, but it is especially useful for streams that have highly - * variable bit rates. This field can optionally be set to the same value - * as the Data Bitrate field. - * - * @param integer $alternateDataBitrate The alternate leak rate. - */ - public function setAlternateDataBitrate($alternateDataBitrate) - { - $this->_alternateDataBitrate = $alternateDataBitrate; - } - - /** - * Returns the size BAlt, in milliseconds, of the leaky bucket used in the - * Alternate Data Bitrate definition. This value is relevant in most - * scenarios where the bit rate is not exactly constant, but it is - * especially useful for streams that have highly variable bit rates. This - * field can optionally be set to the same value as the Buffer Size - * field. - * - * @return integer - */ - public function getAlternateBufferSize() - { - return $this->_alternateBufferSize; - } - - /** - * Sets the size BAlt, in milliseconds, of the leaky bucket used in the - * Alternate Data Bitrate definition. This value is relevant in most - * scenarios where the bit rate is not exactly constant, but it is - * especially useful for streams that have highly variable bit rates. This - * field can optionally be set to the same value as the Buffer Size - * field. - * - * @param integer $alternateBufferSize - */ - public function setAlternateBufferSize($alternateBufferSize) - { - $this->_alternateBufferSize = $alternateBufferSize; - } - - /** - * Returns the initial fullness, in milliseconds, of the leaky bucket used - * in the Alternate Data Bitrate definition. This is the fullness of - * the buffer at the instant before the first bit in the stream is dumped - * into the bucket. Typically, this value is set to 0. This value does not - * exceed the value of the Alternate Buffer Size field. - * - * @return integer - */ - public function getAlternateInitialBufferFullness() - { - return $this->_alternateInitialBufferFullness; - } - - /** - * Sets the initial fullness, in milliseconds, of the leaky bucket used in - * the Alternate Data Bitrate definition. This is the fullness of the - * buffer at the instant before the first bit in the stream is dumped into - * the bucket. Typically, this value is set to 0. This value does not exceed - * the value of the Alternate Buffer Size field. - * - * @param integer $alternateInitialBufferFullness The alternate initial - * fullness. - */ - public function setAlternateInitialBufferFullness - ($alternateInitialBufferFullness) - { - $this->_alternateInitialBufferFullness = - $alternateInitialBufferFullness; - } - - /** - * Returns the maximum size of the largest sample stored in the data packets - * for a stream. A value of 0 means unknown. - * - * @return integer - */ - public function getMaximumObjectSize() - { - return $this->_maximumObjectSize; - } - - /** - * Sets the maximum size of the largest sample stored in the data packets - * for a stream. A value of 0 means unknown. - * - * @param integer $maximumObjectSize The maximum size of the largest sample. - */ - public function setMaximumObjectSize($maximumObjectSize) - { - $this->_maximumObjectSize = $maximumObjectSize; - } - - /** - * Returns the average time duration, measured in 100-nanosecond units, of - * each frame. This number should be rounded to the nearest integer. This - * field can optionally be set to 0 if the average time per frame is unknown - * or unimportant. It is recommended that this field be set for video. - * - * @return integer - */ - public function getAverageTimePerFrame() - { - return $this->_averageTimePerFrame; - } - - /** - * Sets the average time duration, measured in 100-nanosecond units, of - * each frame. This number should be rounded to the nearest integer. This - * field can optionally be set to 0 if the average time per frame is unknown - * or unimportant. It is recommended that this field be set for video. - * - * @param integer $averageTimePerFrame The average time duration. - */ - public function setAverageTimePerFrame($averageTimePerFrame) - { - $this->_averageTimePerFrame = $averageTimePerFrame; - } - - /** - * Returns the number of this stream. 0 is an invalid stream number (that - * is, other Header Objects use stream number 0 to refer to the - * entire file as a whole rather than to a specific media stream within the - * file). Valid values are between 1 and 127. - * - * @return integer - */ - public function getStreamNumber() - { - return $this->_streamNumber; - } - - /** - * Sets the number of this stream. 0 is an invalid stream number (that is, - * other Header Objects use stream number 0 to refer to the entire - * file as a whole rather than to a specific media stream within the file). - * Valid values are between 1 and 127. - * - * @param integer $streamNumber The number of this stream. - */ - public function setStreamNumber($streamNumber) - { - $this->_streamNumber = $streamNumber; - } - - /** - * Returns the language, if any, which the content of the stream uses or - * assumes. Refer to the {@link LanguageList Language List Object} - * description for the details concerning how the Stream Language - * Index and Language Index fields should be used. Note that this - * is an index into the languages listed in the Language List Object - * rather than a language identifier. - * - * @return integer - */ - public function getStreamLanguageIndex() - { - return $this->_streamLanguageIndex; - } - - /** - * Sets the language, if any, which the content of the stream uses or - * assumes. Refer to the {@link LanguageList Language List Object} - * description for the details concerning how the Stream Language - * Index and Language Index fields should be used. Note that this - * is an index into the languages listed in the Language List Object - * rather than a language identifier. - * - * @param integer $streamLanguageIndex The language index. - */ - public function setStreamLanguageIndex($streamLanguageIndex) - { - $this->_streamLanguageIndex = $streamLanguageIndex; - } - - /** - * Returns an array of Stream Names. Each stream name instance is - * potentially localized into a specific language. The Language Index - * field indicates the language in which the Stream Name has been - * written. - * - * The array entry contains the following keys: - * o languageIndex -- The language index - * o streamName -- The localized stream name - * - * @return Array - */ - public function getStreamNames() - { - return $this->_streamNames; - } - - /** - * Sets the array of stream names. Each stream name instance is potentially - * localized into a specific language. The Language Index field - * indicates the language in which the Stream Name has been written. - * - * The array entries are to contain the following keys: - * o languageIndex -- The language index - * o streamName -- The localized stream name - * - * @param Array $streamNames The array of stream names - */ - public function setStreamNames($streamNames) - { - $this->_streamNames = $streamNames; - } - - /** - * Returns an array of payload extension systems. Payload extensions provide - * a way for content creators to specify kinds of data that will appear in - * the payload header for every payload from this stream. This system is - * used when stream properties must be conveyed at the media object level. - * The Replicated Data bytes in the payload header will contain these - * properties in the order in which the Payload Extension Systems - * appear in this object. A Payload Extension System must appear in - * the Extended Stream Properties Object for each type of - * per-media-object properties that will appear with the payloads for this - * stream. - * - * The array entry contains the following keys: - * o extensionSystemId -- Specifies a unique identifier for the extension - * system. - * o extensionDataSize -- Specifies the fixed size of the extension data - * for this system that will appear in the replicated data alongside - * every payload for this stream. If this extension system uses - * variable-size data, then this should be set to 0xffff. Note, however, - * that replicated data length is limited to 255 bytes, which limits the - * total size of all extension systems for a particular stream. - * o extensionSystemInfo -- Specifies additional information to describe - * this extension system (optional). - * - * @return Array - */ - public function getPayloadExtensionSystems() - { - return $this->_payloadExtensionSystems; - } - - /** - * Sets an array of payload extension systems. Payload extensions provide a - * way for content creators to specify kinds of data that will appear in the - * payload header for every payload from this stream. This system is used - * when stream properties must be conveyed at the media object level. The - * Replicated Data bytes in the payload header will contain these - * properties in the order in which the Payload Extension Systems - * appear in this object. A Payload Extension System must appear in - * the Extended Stream Properties Object for each type of - * per-media-object properties that will appear with the payloads for this - * stream. - * - * The array enties are to contain the following keys: - * o extensionSystemId -- Specifies a unique identifier for the extension - * system. - * o extensionDataSize -- Specifies the fixed size of the extension data - * for this system that will appear in the replicated data alongside - * every payload for this stream. If this extension system uses - * variable-size data, then this should be set to 0xffff. Note, however, - * that replicated data length is limited to 255 bytes, which limits the - * total size of all extension systems for a particular stream. - * o extensionSystemInfo -- Specifies additional information to describe - * this extension system (optional). - * - * @param Array $payloadExtensionSystems The array of payload extension - * systems. - */ - public function setPayloadExtensionSystems($payloadExtensionSystems) - { - $this->_payloadExtensionSystems = $payloadExtensionSystems; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - - $streamNameCount = count($this->_streamNames); - $streamNameWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $streamNameCount; $i++) { - $streamNameWriter - ->writeUInt16LE($this->_streamNames['languageIndex']) - ->writeUInt16LE(strlen($streamName = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_streamNames['streamName']) . "\0\0")) - ->writeString16($streamName); - } - - $payloadExtensionSystemCount = count($this->_payloadExtensionSystems); - $payloadExtensionSystemWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $payloadExtensionSystemCount; $i++) { - $payloadExtensionSystemWriter - ->writeGuid($this->_streamNames['extensionSystemId']) - ->writeUInt16LE($this->_streamNames['extensionDataSize']) - ->writeUInt16LE(strlen($extensionSystemInfo = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_streamNames['extensionSystemInfo']) . "\0\0")) - ->writeString16($extensionSystemInfo); - } - - - $this->setSize - (24 /* for header */ + 64 + $streamNameWriter->getSize() + - $payloadExtensionSystemWriter->getSize()); - - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeInt64LE($this->_startTime) - ->writeInt64LE($this->_endTime) - ->writeUInt32LE($this->_dataBitrate) - ->writeUInt32LE($this->_bufferSize) - ->writeUInt32LE($this->_initialBufferFullness) - ->writeUInt32LE($this->_alternateDataBitrate) - ->writeUInt32LE($this->_alternateBufferSize) - ->writeUInt32LE($this->_alternateInitialBufferFullness) - ->writeUInt32LE($this->_maximumObjectSize) - ->writeUInt32LE($this->_flags) - ->writeUInt16LE($this->_streamNumber) - ->writeUInt16LE($this->_streamLanguageIndex) - ->writeInt64LE($this->_averageTimePerFrame) - ->writeUInt16LE($streamNameCount) - ->writeUInt16LE($payloadExtensionSystemCount) - ->write($streamNameWriter->toString()) - ->write($payloadExtensionSystemWriter->toString()); - } -} +Extended Stream Properties Object defines additional optional + * properties and characteristics of a digital media stream that are not + * described in the Stream Properties Object. + * + * Typically, the basic Stream Properties Object is present in the + * Header Object, and the Extended Stream Properties Object is + * present in the Header Extension Object. Sometimes, however, the + * Stream Properties Object for a stream may be embedded inside the + * Extended Stream Properties Object for that stream. This approach + * facilitates the creation of backward-compatible content. + * + * This object has an optional provision to include application-specific or + * implementation-specific data attached to the payloads of each digital media + * sample stored within a Data Packet. This data can be looked at as + * digital media sample properties and is stored in the Replicated Data + * field of a payload header. The Payload Extension Systems fields of the + * Extended Stream Properties Object describes what this data is and is + * necessary for that data to be parsed, if present. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ExtendedStreamProperties.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ExtendedStreamProperties + extends Zend_Media_Asf_Object +{ + /** + * Indicates, if set, that this digital media stream, if sent over a + * network, must be carried over a reliable data communications transport + * mechanism. This should be set for streams that cannot recover after a + * lost media object. + */ + const RELIABLE = 1; + + /** + * This flag should be set only if the stream is seekable, either by using + * an index object or by estimating according to bit rate (as can sometimes + * be done with audio). This flag pertains to this stream only rather than + * to the entire file. + */ + const SEEKABLE = 2; + + /** + * Indicates, if set, that the stream does not contain any cleanpoints. A + * cleanpoint is any point at which playback could begin without having seen + * the previous media objects. For streams that use key frames, the key + * frames would be the cleanpoints. + */ + const NO_CLEANPOINT = 4; + + /** + * Specifies, if set, that when a stream is joined in mid-transmission, all + * information from the most recent cleanpoint up to the current time should + * be sent before normal streaming begins at the current time. The default + * behavior (when this flag is not set) is to send only the data starting at + * the current time. This flag should only be set for streams that are + * coming from a live source. + */ + const RESEND_LIVE_CLEANPOINTS = 8; + + const AUDIO_MEDIA = 'f8699e40-5b4d-11cf-a8fd-00805f5c442b'; + const VIDEO_MEDIA = 'bc19efc0-5b4d-11cf-a8fd-00805f5c442b'; + const COMMAND_MEDIA = '59dacfc0-59e6-11d0-a3ac-00a0c90348f6'; + const JFIF_MEDIA = 'b61be100-5b4e-11cf-a8fD-00805f5c442b'; + const DEGRADABLE_JPEG_MEDIA = '35907dE0-e415-11cf-a917-00805f5c442b'; + const FILE_TRANSFER_MEDIA = '91bd222c-f21c-497a-8b6d-5aa86bfc0185'; + const BINARY_MEDIA = '3afb65e2-47ef-40f2-ac2c-70a90d71d343'; + + const NO_ERROR_CORRECTION = '20fb5700-5b55-11cf-a8fd-00805f5c442b'; + const AUDIO_SPREAD = 'bfc3cd50-618f-11cf-8bb2-00aa00b4e220'; + + const PAYLOAD_EXTENSION_SYSTEM_TIMECODE = + '399595ec-8667-4e2d-8fdb-98814ce76c1e'; + const PAYLOAD_EXTENSION_SYSTEM_FILE_NAME = + 'e165ec0e-19ed-45d7-b4a7-25cbd1e28e9b'; + const PAYLOAD_EXTENSION_SYSTEM_CONTENT_TYPE = + 'd590dc20-07bc-436c-9cf7-f3bbfbf1a4dc'; + const PAYLOAD_EXTENSION_SYSTEM_PIXEL_ASPECT_RATIO = + '1b1ee554-f9ea-4bc8-821a-376b74e4c4b8'; + const PAYLOAD_EXTENSION_SYSTEM_SAMPLE_DURATION = + 'c6bd9450-867f-4907-83a3-c77921b733ad'; + const PAYLOAD_EXTENSION_SYSTEM_ENCRYPTION_SAMPLE_ID = + '6698b84e-0afa-4330-aeb2-1c0a98d7a44d'; + + /** @var integer */ + private $_startTime; + + /** @var integer */ + private $_endTime; + + /** @var integer */ + private $_dataBitrate; + + /** @var integer */ + private $_bufferSize; + + /** @var integer */ + private $_initialBufferFullness; + + /** @var integer */ + private $_alternateDataBitrate; + + /** @var integer */ + private $_alternateBufferSize; + + /** @var integer */ + private $_alternateInitialBufferFullness; + + /** @var integer */ + private $_maximumObjectSize; + + /** @var integer */ + private $_flags; + + /** @var integer */ + private $_streamNumber; + + /** @var integer */ + private $_streamLanguageIndex; + + /** @var integer */ + private $_averageTimePerFrame; + + /** @var Array */ + private $_streamNames = array(); + + /** @var Array */ + private $_payloadExtensionSystems = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_startTime = $this->_reader->readInt64LE(); + $this->_endTime = $this->_reader->readInt64LE(); + $this->_dataBitrate = $this->_reader->readUInt32LE(); + $this->_bufferSize = $this->_reader->readUInt32LE(); + $this->_initialBufferFullness = $this->_reader->readUInt32LE(); + $this->_alternateDataBitrate = $this->_reader->readUInt32LE(); + $this->_alternateBufferSize = $this->_reader->readUInt32LE(); + $this->_alternateInitialBufferFullness = $this->_reader->readUInt32LE(); + $this->_maximumObjectSize = $this->_reader->readUInt32LE(); + $this->_flags = $this->_reader->readUInt32LE(); + $this->_streamNumber = $this->_reader->readUInt16LE(); + $this->_streamLanguageIndex = $this->_reader->readUInt16LE(); + $this->_averageTimePerFrame = $this->_reader->readInt64LE(); + $streamNameCount = $this->_reader->readUInt16LE(); + $payloadExtensionSystemCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $streamNameCount; $i++) { + $streamName = + array('languageIndex' => $this->_reader->readUInt16LE()); + $streamNameLength = $this->_reader->readUInt16LE(); + $streamName['streamName'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($streamNameLength)); + $this->_streamNames[] = $streamName; + } + for ($i = 0; $i < $payloadExtensionSystemCount; $i++) { + $payloadExtensionSystem = array + ('extensionSystemId' => $this->_reader->readGuid(), + 'extensionDataSize' => $this->_reader->readUInt16LE()); + $extensionSystemInfoLength = $this->_reader->readUInt32LE(); + $payloadExtensionSystem['extensionSystemInfo'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($extensionSystemInfoLength)); + $this->_payloadExtensionSystems[] = $payloadExtensionSystem; + } + } + + /** + * Returns the presentation time of the first object, indicating where this + * digital media stream starts within the context of the timeline of the ASF + * file as a whole. This time value corresponds to presentation times as + * they appear in the data packets (adjusted by the preroll). This field is + * given in units of milliseconds and can optionally be set to 0, in which + * case it will be ignored. + * + * @return integer + */ + public function getStartTime() + { + return $this->_startTime; + } + + /** + * Sets the presentation time of the first object, indicating where this + * digital media stream starts within the context of the timeline of the ASF + * file as a whole. This time value corresponds to presentation times as + * they appear in the data packets (adjusted by the preroll). + * + * The given value must be in units of milliseconds or optionally be set to + * 0, in which case the field will be ignored. + * + * @param integer $startTime The presentation time of the first object. + */ + public function setStartTime($startTime) + { + $this->_startTime = $startTime; + } + + /** + * Returns the presentation time of the last object plus the duration of + * play, indicating where this digital media stream ends within the context + * of the timeline of the ASF file as a whole. This time value corresponds + * to presentation times as they appear in the data packets (adjusted by the + * preroll). This field is given in units of milliseconds and can optionally + * be set to 0, in which case it will be ignored. + * + * @return integer + */ + public function getEndTime() + { + return $this->_endTime; + } + + /** + * Sets the presentation time of the last object plus the duration of play, + * indicating where this digital media stream ends within the context of the + * timeline of the ASF file as a whole. This time value corresponds to + * presentation times as they appear in the data packets (adjusted by the + * preroll). + * + * The given value must be given in units of milliseconds or optionally be + * set to 0, in which case the field will be ignored. + * + * @param integer $endTime The presentation time of the last object plus the + * duration of play. + */ + public function setEndTime($endTime) + { + $this->_endTime = $endTime; + } + + /** + * Returns the leak rate R, in bits per second, of a leaky bucket that + * contains the data portion of the stream without overflowing, excluding + * all ASF Data Packet overhead. The size of the leaky bucket is specified + * by the value of the Buffer Size field. This field has a non-zero + * value. + * + * @return integer + */ + public function getDataBitrate() + { + return $this->_dataBitrate; + } + + /** + * Sets the leak rate R, in bits per second, of a leaky bucket that + * contains the data portion of the stream without overflowing, excluding + * all ASF Data Packet overhead. The size of the leaky bucket is specified + * by the value of the Buffer Size field. + * + * This field must be given a non-zero value. + * + * @param integer $dataBitrate The leak rate. + */ + public function setDataBitrate($dataBitrate) + { + $this->_dataBitrate = $dataBitrate; + } + + /** + * Returns the size B, in milliseconds, of the leaky bucket used in the + * Data Bitrate definition. + * + * @return integer + */ + public function getBufferSize() + { + return $this->_bufferSize; + } + + /** + * Sets the size B, in milliseconds, of the leaky bucket used in the + * Data Bitrate definition. + * + * @param integer $bufferSize The size. + */ + public function setBufferSize($bufferSize) + { + $this->_bufferSize = $bufferSize; + } + + /** + * Returns the initial fullness, in milliseconds, of the leaky bucket used + * in the Data Bitrate definition. This is the fullness of the buffer + * at the instant before the first bit in the stream is dumped into the + * bucket. Typically, this value is set to 0. This value shall not exceed + * the value in the Buffer Size field. + * + * @return integer + */ + public function getInitialBufferFullness() + { + return $this->_initialBufferFullness; + } + + /** + * Sets the initial fullness, in milliseconds, of the leaky bucket used in + * the Data Bitrate definition. This is the fullness of the buffer at + * the instant before the first bit in the stream is dumped into the bucket. + * Typically, this value is set to 0. This value shall not exceed the value + * in the Buffer Size field. + * + * @param integer $initialBufferFullness The initial fullness. + */ + public function setInitialBufferFullness($initialBufferFullness) + { + $this->_initialBufferFullness = $initialBufferFullness; + } + + /** + * Returns the leak rate RAlt, in bits per second, of a leaky bucket that + * contains the data portion of the stream without overflowing, excluding + * all ASF Data Packet overhead. The size of the leaky bucket is + * specified by the value of the Alternate Buffer Size field. This + * value is relevant in most scenarios where the bit rate is not exactly + * constant, but it is especially useful for streams that have highly + * variable bit rates. This field can optionally be set to the same value + * as the Data Bitrate field. + * + * @return integer + */ + public function getAlternateDataBitrate() + { + return $this->_alternateDataBitrate; + } + + /** + * Sets the leak rate RAlt, in bits per second, of a leaky bucket that + * contains the data portion of the stream without overflowing, excluding + * all ASF Data Packet overhead. The size of the leaky bucket is + * specified by the value of the Alternate Buffer Size field. This + * value is relevant in most scenarios where the bit rate is not exactly + * constant, but it is especially useful for streams that have highly + * variable bit rates. This field can optionally be set to the same value + * as the Data Bitrate field. + * + * @param integer $alternateDataBitrate The alternate leak rate. + */ + public function setAlternateDataBitrate($alternateDataBitrate) + { + $this->_alternateDataBitrate = $alternateDataBitrate; + } + + /** + * Returns the size BAlt, in milliseconds, of the leaky bucket used in the + * Alternate Data Bitrate definition. This value is relevant in most + * scenarios where the bit rate is not exactly constant, but it is + * especially useful for streams that have highly variable bit rates. This + * field can optionally be set to the same value as the Buffer Size + * field. + * + * @return integer + */ + public function getAlternateBufferSize() + { + return $this->_alternateBufferSize; + } + + /** + * Sets the size BAlt, in milliseconds, of the leaky bucket used in the + * Alternate Data Bitrate definition. This value is relevant in most + * scenarios where the bit rate is not exactly constant, but it is + * especially useful for streams that have highly variable bit rates. This + * field can optionally be set to the same value as the Buffer Size + * field. + * + * @param integer $alternateBufferSize + */ + public function setAlternateBufferSize($alternateBufferSize) + { + $this->_alternateBufferSize = $alternateBufferSize; + } + + /** + * Returns the initial fullness, in milliseconds, of the leaky bucket used + * in the Alternate Data Bitrate definition. This is the fullness of + * the buffer at the instant before the first bit in the stream is dumped + * into the bucket. Typically, this value is set to 0. This value does not + * exceed the value of the Alternate Buffer Size field. + * + * @return integer + */ + public function getAlternateInitialBufferFullness() + { + return $this->_alternateInitialBufferFullness; + } + + /** + * Sets the initial fullness, in milliseconds, of the leaky bucket used in + * the Alternate Data Bitrate definition. This is the fullness of the + * buffer at the instant before the first bit in the stream is dumped into + * the bucket. Typically, this value is set to 0. This value does not exceed + * the value of the Alternate Buffer Size field. + * + * @param integer $alternateInitialBufferFullness The alternate initial + * fullness. + */ + public function setAlternateInitialBufferFullness + ($alternateInitialBufferFullness) + { + $this->_alternateInitialBufferFullness = + $alternateInitialBufferFullness; + } + + /** + * Returns the maximum size of the largest sample stored in the data packets + * for a stream. A value of 0 means unknown. + * + * @return integer + */ + public function getMaximumObjectSize() + { + return $this->_maximumObjectSize; + } + + /** + * Sets the maximum size of the largest sample stored in the data packets + * for a stream. A value of 0 means unknown. + * + * @param integer $maximumObjectSize The maximum size of the largest sample. + */ + public function setMaximumObjectSize($maximumObjectSize) + { + $this->_maximumObjectSize = $maximumObjectSize; + } + + /** + * Returns the average time duration, measured in 100-nanosecond units, of + * each frame. This number should be rounded to the nearest integer. This + * field can optionally be set to 0 if the average time per frame is unknown + * or unimportant. It is recommended that this field be set for video. + * + * @return integer + */ + public function getAverageTimePerFrame() + { + return $this->_averageTimePerFrame; + } + + /** + * Sets the average time duration, measured in 100-nanosecond units, of + * each frame. This number should be rounded to the nearest integer. This + * field can optionally be set to 0 if the average time per frame is unknown + * or unimportant. It is recommended that this field be set for video. + * + * @param integer $averageTimePerFrame The average time duration. + */ + public function setAverageTimePerFrame($averageTimePerFrame) + { + $this->_averageTimePerFrame = $averageTimePerFrame; + } + + /** + * Returns the number of this stream. 0 is an invalid stream number (that + * is, other Header Objects use stream number 0 to refer to the + * entire file as a whole rather than to a specific media stream within the + * file). Valid values are between 1 and 127. + * + * @return integer + */ + public function getStreamNumber() + { + return $this->_streamNumber; + } + + /** + * Sets the number of this stream. 0 is an invalid stream number (that is, + * other Header Objects use stream number 0 to refer to the entire + * file as a whole rather than to a specific media stream within the file). + * Valid values are between 1 and 127. + * + * @param integer $streamNumber The number of this stream. + */ + public function setStreamNumber($streamNumber) + { + $this->_streamNumber = $streamNumber; + } + + /** + * Returns the language, if any, which the content of the stream uses or + * assumes. Refer to the {@link LanguageList Language List Object} + * description for the details concerning how the Stream Language + * Index and Language Index fields should be used. Note that this + * is an index into the languages listed in the Language List Object + * rather than a language identifier. + * + * @return integer + */ + public function getStreamLanguageIndex() + { + return $this->_streamLanguageIndex; + } + + /** + * Sets the language, if any, which the content of the stream uses or + * assumes. Refer to the {@link LanguageList Language List Object} + * description for the details concerning how the Stream Language + * Index and Language Index fields should be used. Note that this + * is an index into the languages listed in the Language List Object + * rather than a language identifier. + * + * @param integer $streamLanguageIndex The language index. + */ + public function setStreamLanguageIndex($streamLanguageIndex) + { + $this->_streamLanguageIndex = $streamLanguageIndex; + } + + /** + * Returns an array of Stream Names. Each stream name instance is + * potentially localized into a specific language. The Language Index + * field indicates the language in which the Stream Name has been + * written. + * + * The array entry contains the following keys: + * o languageIndex -- The language index + * o streamName -- The localized stream name + * + * @return Array + */ + public function getStreamNames() + { + return $this->_streamNames; + } + + /** + * Sets the array of stream names. Each stream name instance is potentially + * localized into a specific language. The Language Index field + * indicates the language in which the Stream Name has been written. + * + * The array entries are to contain the following keys: + * o languageIndex -- The language index + * o streamName -- The localized stream name + * + * @param Array $streamNames The array of stream names + */ + public function setStreamNames($streamNames) + { + $this->_streamNames = $streamNames; + } + + /** + * Returns an array of payload extension systems. Payload extensions provide + * a way for content creators to specify kinds of data that will appear in + * the payload header for every payload from this stream. This system is + * used when stream properties must be conveyed at the media object level. + * The Replicated Data bytes in the payload header will contain these + * properties in the order in which the Payload Extension Systems + * appear in this object. A Payload Extension System must appear in + * the Extended Stream Properties Object for each type of + * per-media-object properties that will appear with the payloads for this + * stream. + * + * The array entry contains the following keys: + * o extensionSystemId -- Specifies a unique identifier for the extension + * system. + * o extensionDataSize -- Specifies the fixed size of the extension data + * for this system that will appear in the replicated data alongside + * every payload for this stream. If this extension system uses + * variable-size data, then this should be set to 0xffff. Note, however, + * that replicated data length is limited to 255 bytes, which limits the + * total size of all extension systems for a particular stream. + * o extensionSystemInfo -- Specifies additional information to describe + * this extension system (optional). + * + * @return Array + */ + public function getPayloadExtensionSystems() + { + return $this->_payloadExtensionSystems; + } + + /** + * Sets an array of payload extension systems. Payload extensions provide a + * way for content creators to specify kinds of data that will appear in the + * payload header for every payload from this stream. This system is used + * when stream properties must be conveyed at the media object level. The + * Replicated Data bytes in the payload header will contain these + * properties in the order in which the Payload Extension Systems + * appear in this object. A Payload Extension System must appear in + * the Extended Stream Properties Object for each type of + * per-media-object properties that will appear with the payloads for this + * stream. + * + * The array enties are to contain the following keys: + * o extensionSystemId -- Specifies a unique identifier for the extension + * system. + * o extensionDataSize -- Specifies the fixed size of the extension data + * for this system that will appear in the replicated data alongside + * every payload for this stream. If this extension system uses + * variable-size data, then this should be set to 0xffff. Note, however, + * that replicated data length is limited to 255 bytes, which limits the + * total size of all extension systems for a particular stream. + * o extensionSystemInfo -- Specifies additional information to describe + * this extension system (optional). + * + * @param Array $payloadExtensionSystems The array of payload extension + * systems. + */ + public function setPayloadExtensionSystems($payloadExtensionSystems) + { + $this->_payloadExtensionSystems = $payloadExtensionSystems; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + + $streamNameCount = count($this->_streamNames); + $streamNameWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $streamNameCount; $i++) { + $streamNameWriter + ->writeUInt16LE($this->_streamNames['languageIndex']) + ->writeUInt16LE(strlen($streamName = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_streamNames['streamName']) . "\0\0")) + ->writeString16($streamName); + } + + $payloadExtensionSystemCount = count($this->_payloadExtensionSystems); + $payloadExtensionSystemWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $payloadExtensionSystemCount; $i++) { + $payloadExtensionSystemWriter + ->writeGuid($this->_streamNames['extensionSystemId']) + ->writeUInt16LE($this->_streamNames['extensionDataSize']) + ->writeUInt16LE(strlen($extensionSystemInfo = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_streamNames['extensionSystemInfo']) . "\0\0")) + ->writeString16($extensionSystemInfo); + } + + + $this->setSize + (24 /* for header */ + 64 + $streamNameWriter->getSize() + + $payloadExtensionSystemWriter->getSize()); + + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeInt64LE($this->_startTime) + ->writeInt64LE($this->_endTime) + ->writeUInt32LE($this->_dataBitrate) + ->writeUInt32LE($this->_bufferSize) + ->writeUInt32LE($this->_initialBufferFullness) + ->writeUInt32LE($this->_alternateDataBitrate) + ->writeUInt32LE($this->_alternateBufferSize) + ->writeUInt32LE($this->_alternateInitialBufferFullness) + ->writeUInt32LE($this->_maximumObjectSize) + ->writeUInt32LE($this->_flags) + ->writeUInt16LE($this->_streamNumber) + ->writeUInt16LE($this->_streamLanguageIndex) + ->writeInt64LE($this->_averageTimePerFrame) + ->writeUInt16LE($streamNameCount) + ->writeUInt16LE($payloadExtensionSystemCount) + ->write($streamNameWriter->toString()) + ->write($payloadExtensionSystemWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/FileProperties.php b/app/libs/vendor/Zend/Media/Asf/Object/FileProperties.php index 8fb0da01..85ddddf1 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/FileProperties.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/FileProperties.php @@ -1,440 +1,440 @@ -File Properties Object defines the global characteristics of the - * combined digital media streams found within the Data Object. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FileProperties.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_FileProperties extends Zend_Media_Asf_Object -{ - /** - * Indicates, if set, that a file is in the process of being created (for - * example, for recording applications), and thus that various values stored - * in the header objects are invalid. It is highly recommended that - * post-processing be performed to remove this condition at the earliest - * opportunity. - */ - const BROADCAST = 1; - - /** - * Indicates, if set, that a file is seekable. Note that for files - * containing a single audio stream and a Minimum Data Packet Size - * field equal to the Maximum Data Packet Size field, this flag shall - * always be set to 1. For files containing a single audio stream and a - * video stream or mutually exclusive video streams, this flag is only set - * to 1 if the file contains a matching Simple Index Object for each - * regular video stream. - */ - const SEEKABLE = 2; - - /** @var string */ - private $_fileId; - - /** @var integer */ - private $_fileSize; - - /** @var integer */ - private $_creationDate; - - /** @var integer */ - private $_dataPacketsCount; - - /** @var integer */ - private $_playDuration; - - /** @var integer */ - private $_sendDuration; - - /** @var integer */ - private $_preroll; - - /** @var integer */ - private $_flags; - - /** @var integer */ - private $_minimumDataPacketSize; - - /** @var integer */ - private $_maximumDataPacketSize; - - /** @var integer */ - private $_maximumBitrate; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_fileId = $this->_reader->readGuid(); - $this->_fileSize = $this->_reader->readInt64LE(); - $this->_creationDate = $this->_reader->readInt64LE(); - $this->_dataPacketsCount = $this->_reader->readInt64LE(); - $this->_playDuration = $this->_reader->readInt64LE(); - $this->_sendDuration = $this->_reader->readInt64LE(); - $this->_preroll = $this->_reader->readInt64LE(); - $this->_flags = $this->_reader->readUInt32LE(); - $this->_minimumDataPacketSize = $this->_reader->readUInt32LE(); - $this->_maximumDataPacketSize = $this->_reader->readUInt32LE(); - $this->_maximumBitrate = $this->_reader->readUInt32LE(); - } - - /** - * Returns the file id field. - * - * @return integer - */ - public function getFileId() - { - return $this->_fileId; - } - - /** - * Sets the file id field. - * - * @param GUID $fileId The new file id. - */ - public function setFileId($fileId) - { - $this->_fileId = $fileId; - } - - /** - * Returns the size, in bytes, of the entire file. The value of this field - * is invalid if the broadcast flag bit in the flags field is set to 1. - * - * @return integer - */ - public function getFileSize() - { - return $this->_fileSize; - } - - /** - * Sets the size, in bytes, of the entire file. The value of this field is - * invalid if the broadcast flag bit in the flags field is set to 1. - * - * @param integer $fileSize The size of the entire file. - */ - public function setFileSize($fileSize) - { - $this->_fileSize = $fileSize; - } - - /** - * Returns the date and time of the initial creation of the file. The value - * is given as the number of 100-nanosecond intervals since January 1, 1601, - * according to Coordinated Universal Time (Greenwich Mean Time). The value - * of this field may be invalid if the broadcast flag bit in the flags field - * is set to 1. - * - * @return integer - */ - public function getCreationDate() - { - return $this->_creationDate; - } - - /** - * Sets the date and time of the initial creation of the file. The value is - * given as the number of 100-nanosecond intervals since January 1, 1601, - * according to Coordinated Universal Time (Greenwich Mean Time). The value - * of this field may be invalid if the broadcast flag bit in the flags field - * is set to 1. - * - * @param integer $creationDate The date and time of the initial creation of - * the file. - */ - public function setCreationDate($creationDate) - { - $this->_creationDate = $creationDate; - } - - /** - * Returns the number of Data Packet entries that exist within the - * {@link Zend_Media_Asf_Object_Data Data Object}. The value of this field - * is invalid if the broadcast flag bit in the flags field is set to 1. - * - * @return integer - */ - public function getDataPacketsCount() - { - return $this->_dataPacketsCount; - } - - /** - * Sets the number of Data Packet entries that exist within the - * {@link Zend_Media_Asf_Object_Data Data Object}. The value of this field - * is invalid if the broadcast flag bit in the flags field is set to 1. - * - * @param integer $dataPacketsCount The number of Data Packet entries. - */ - public function setDataPacketsCount($dataPacketsCount) - { - $this->_dataPacketsCount = $dataPacketsCount; - } - - /** - * Returns the time needed to play the file in 100-nanosecond units. This - * value should include the duration (estimated, if an exact value is - * unavailable) of the the last media object in the presentation. The value - * of this field is invalid if the broadcast flag bit in the flags field is - * set to 1. - * - * @return integer - */ - public function getPlayDuration() - { - return $this->_playDuration; - } - - /** - * Sets the time needed to play the file in 100-nanosecond units. This - * value should include the duration (estimated, if an exact value is - * unavailable) of the the last media object in the presentation. The value - * of this field is invalid if the broadcast flag bit in the flags field is - * set to 1. - * - * @param integer $playDuration The time needed to play the file. - */ - public function setPlayDuration($playDuration) - { - $this->_playDuration = $playDuration; - } - - /** - * Returns the time needed to send the file in 100-nanosecond units. This - * value should include the duration of the last packet in the content. The - * value of this field is invalid if the broadcast flag bit in the flags - * field is set to 1. - * - * @return integer - */ - public function getSendDuration() - { - return $this->_sendDuration; - } - - /** - * Sets the time needed to send the file in 100-nanosecond units. This - * value should include the duration of the last packet in the content. The - * value of this field is invalid if the broadcast flag bit in the flags - * field is set to 1. - * - * @param integer $sendDuration The time needed to send the file. - */ - public function setSendDuration($sendDuration) - { - $this->_sendDuration = $sendDuration; - } - - /** - * Returns the amount of time to buffer data before starting to play the - * file, in millisecond units. If this value is nonzero, the Play - * Duration field and all of the payload Presentation Time fields - * have been offset by this amount. Therefore, player software must subtract - * the value in the preroll field from the play duration and presentation - * times to calculate their actual values. - * - * @return integer - */ - public function getPreroll() - { - return $this->_preroll; - } - - /** - * Sets the amount of time to buffer data before starting to play the file, - * in millisecond units. If this value is nonzero, the Play Duration - * field and all of the payload Presentation Time fields have been - * offset by this amount. Therefore, player software must subtract the value - * in the preroll field from the play duration and presentation times to - * calculate their actual values. - * - * @param integer $preroll The amount of time to buffer data. - */ - public function setPreroll($preroll) - { - $this->_preroll = $preroll; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the flags field. - * - * @return integer - */ - public function getFlags() - { - return $this->_flags; - } - - /** - * Sets the flags field. - * - * @param integer $flags The flags field. - */ - public function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Returns the minimum Data Packet size in bytes. In general, the - * value of this field is invalid if the broadcast flag bit in the flags - * field is set to 1. However, the values for the Minimum Data Packet - * Size and Maximum Data Packet Size fields shall be set to the - * same value, and this value should be set to the packet size, even when - * the broadcast flag in the flags field is set to 1. - * - * @return integer - */ - public function getMinimumDataPacketSize() - { - return $this->_minimumDataPacketSize; - } - - /** - * Sets the minimum Data Packet size in bytes. In general, the value - * of this field is invalid if the broadcast flag bit in the flags field is - * set to 1. However, the values for the Minimum Data Packet Size and - * Maximum Data Packet Size fields shall be set to the same value, - * and this value should be set to the packet size, even when the broadcast - * flag in the flags field is set to 1. - * - * @param integer $minimumDataPacketSize The minimum Data Packet size - * in bytes. - */ - public function setMinimumDataPacketSize($minimumDataPacketSize) - { - $this->_minimumDataPacketSize = $minimumDataPacketSize; - } - - /** - * Returns the maximum Data Packet size in bytes. In general, the - * value of this field is invalid if the broadcast flag bit in the flags - * field is set to 1. However, the values for the Minimum Data Packet - * Size and Maximum Data Packet Size fields shall be set to the - * same value, and this value should be set to the packet size, even when - * the broadcast flag in the flags field is set to 1. - * - * @return integer - */ - public function getMaximumDataPacketSize() - { - return $this->_maximumDataPacketSize; - } - - /** - * Sets the maximum Data Packet size in bytes. In general, the value - * of this field is invalid if the broadcast flag bit in the flags field is - * set to 1. However, the values for the Minimum Data Packet Size and - * Maximum Data Packet Size fields shall be set to the same value, - * and this value should be set to the packet size, even when the broadcast - * flag in the flags field is set to 1. - * - * @param integer $maximumDataPacketSize The maximum Data Packet size - * in bytes - */ - public function setMaximumDataPacketSize($maximumDataPacketSize) - { - $this->_maximumDataPacketSize = $maximumDataPacketSize; - } - - /** - * Returns the maximum instantaneous bit rate in bits per second for the - * entire file. This is equal the sum of the bit rates of the individual - * digital media streams. - * - * @return integer - */ - public function getMaximumBitrate() - { - return $this->_maximumBitrate; - } - - /** - * Sets the maximum instantaneous bit rate in bits per second for the - * entire file. This is equal the sum of the bit rates of the individual - * digital media streams. - * - * @param integer $maximumBitrate The maximum instantaneous bit rate in bits - * per second. - */ - public function setMaximumBitrate($maximumBitrate) - { - $this->_maximumBitrate = $maximumBitrate; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $this->setSize(24 /* for header */ + 80); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_fileId) - ->writeInt64LE($this->_fileSize) - ->writeInt64LE($this->_creationDate) - ->writeInt64LE($this->_dataPacketsCount) - ->writeInt64LE($this->_playDuration) - ->writeInt64LE($this->_sendDuration) - ->writeInt64LE($this->_preroll) - ->writeUInt32LE($this->_flags) - ->writeUInt32LE($this->_minimumDataPacketSize) - ->writeUInt32LE($this->_maximumDataPacketSize) - ->writeUInt32LE($this->_maximumBitrate); - } -} +File Properties Object defines the global characteristics of the + * combined digital media streams found within the Data Object. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: FileProperties.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_FileProperties extends Zend_Media_Asf_Object +{ + /** + * Indicates, if set, that a file is in the process of being created (for + * example, for recording applications), and thus that various values stored + * in the header objects are invalid. It is highly recommended that + * post-processing be performed to remove this condition at the earliest + * opportunity. + */ + const BROADCAST = 1; + + /** + * Indicates, if set, that a file is seekable. Note that for files + * containing a single audio stream and a Minimum Data Packet Size + * field equal to the Maximum Data Packet Size field, this flag shall + * always be set to 1. For files containing a single audio stream and a + * video stream or mutually exclusive video streams, this flag is only set + * to 1 if the file contains a matching Simple Index Object for each + * regular video stream. + */ + const SEEKABLE = 2; + + /** @var string */ + private $_fileId; + + /** @var integer */ + private $_fileSize; + + /** @var integer */ + private $_creationDate; + + /** @var integer */ + private $_dataPacketsCount; + + /** @var integer */ + private $_playDuration; + + /** @var integer */ + private $_sendDuration; + + /** @var integer */ + private $_preroll; + + /** @var integer */ + private $_flags; + + /** @var integer */ + private $_minimumDataPacketSize; + + /** @var integer */ + private $_maximumDataPacketSize; + + /** @var integer */ + private $_maximumBitrate; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_fileId = $this->_reader->readGuid(); + $this->_fileSize = $this->_reader->readInt64LE(); + $this->_creationDate = $this->_reader->readInt64LE(); + $this->_dataPacketsCount = $this->_reader->readInt64LE(); + $this->_playDuration = $this->_reader->readInt64LE(); + $this->_sendDuration = $this->_reader->readInt64LE(); + $this->_preroll = $this->_reader->readInt64LE(); + $this->_flags = $this->_reader->readUInt32LE(); + $this->_minimumDataPacketSize = $this->_reader->readUInt32LE(); + $this->_maximumDataPacketSize = $this->_reader->readUInt32LE(); + $this->_maximumBitrate = $this->_reader->readUInt32LE(); + } + + /** + * Returns the file id field. + * + * @return integer + */ + public function getFileId() + { + return $this->_fileId; + } + + /** + * Sets the file id field. + * + * @param GUID $fileId The new file id. + */ + public function setFileId($fileId) + { + $this->_fileId = $fileId; + } + + /** + * Returns the size, in bytes, of the entire file. The value of this field + * is invalid if the broadcast flag bit in the flags field is set to 1. + * + * @return integer + */ + public function getFileSize() + { + return $this->_fileSize; + } + + /** + * Sets the size, in bytes, of the entire file. The value of this field is + * invalid if the broadcast flag bit in the flags field is set to 1. + * + * @param integer $fileSize The size of the entire file. + */ + public function setFileSize($fileSize) + { + $this->_fileSize = $fileSize; + } + + /** + * Returns the date and time of the initial creation of the file. The value + * is given as the number of 100-nanosecond intervals since January 1, 1601, + * according to Coordinated Universal Time (Greenwich Mean Time). The value + * of this field may be invalid if the broadcast flag bit in the flags field + * is set to 1. + * + * @return integer + */ + public function getCreationDate() + { + return $this->_creationDate; + } + + /** + * Sets the date and time of the initial creation of the file. The value is + * given as the number of 100-nanosecond intervals since January 1, 1601, + * according to Coordinated Universal Time (Greenwich Mean Time). The value + * of this field may be invalid if the broadcast flag bit in the flags field + * is set to 1. + * + * @param integer $creationDate The date and time of the initial creation of + * the file. + */ + public function setCreationDate($creationDate) + { + $this->_creationDate = $creationDate; + } + + /** + * Returns the number of Data Packet entries that exist within the + * {@link Zend_Media_Asf_Object_Data Data Object}. The value of this field + * is invalid if the broadcast flag bit in the flags field is set to 1. + * + * @return integer + */ + public function getDataPacketsCount() + { + return $this->_dataPacketsCount; + } + + /** + * Sets the number of Data Packet entries that exist within the + * {@link Zend_Media_Asf_Object_Data Data Object}. The value of this field + * is invalid if the broadcast flag bit in the flags field is set to 1. + * + * @param integer $dataPacketsCount The number of Data Packet entries. + */ + public function setDataPacketsCount($dataPacketsCount) + { + $this->_dataPacketsCount = $dataPacketsCount; + } + + /** + * Returns the time needed to play the file in 100-nanosecond units. This + * value should include the duration (estimated, if an exact value is + * unavailable) of the the last media object in the presentation. The value + * of this field is invalid if the broadcast flag bit in the flags field is + * set to 1. + * + * @return integer + */ + public function getPlayDuration() + { + return $this->_playDuration; + } + + /** + * Sets the time needed to play the file in 100-nanosecond units. This + * value should include the duration (estimated, if an exact value is + * unavailable) of the the last media object in the presentation. The value + * of this field is invalid if the broadcast flag bit in the flags field is + * set to 1. + * + * @param integer $playDuration The time needed to play the file. + */ + public function setPlayDuration($playDuration) + { + $this->_playDuration = $playDuration; + } + + /** + * Returns the time needed to send the file in 100-nanosecond units. This + * value should include the duration of the last packet in the content. The + * value of this field is invalid if the broadcast flag bit in the flags + * field is set to 1. + * + * @return integer + */ + public function getSendDuration() + { + return $this->_sendDuration; + } + + /** + * Sets the time needed to send the file in 100-nanosecond units. This + * value should include the duration of the last packet in the content. The + * value of this field is invalid if the broadcast flag bit in the flags + * field is set to 1. + * + * @param integer $sendDuration The time needed to send the file. + */ + public function setSendDuration($sendDuration) + { + $this->_sendDuration = $sendDuration; + } + + /** + * Returns the amount of time to buffer data before starting to play the + * file, in millisecond units. If this value is nonzero, the Play + * Duration field and all of the payload Presentation Time fields + * have been offset by this amount. Therefore, player software must subtract + * the value in the preroll field from the play duration and presentation + * times to calculate their actual values. + * + * @return integer + */ + public function getPreroll() + { + return $this->_preroll; + } + + /** + * Sets the amount of time to buffer data before starting to play the file, + * in millisecond units. If this value is nonzero, the Play Duration + * field and all of the payload Presentation Time fields have been + * offset by this amount. Therefore, player software must subtract the value + * in the preroll field from the play duration and presentation times to + * calculate their actual values. + * + * @param integer $preroll The amount of time to buffer data. + */ + public function setPreroll($preroll) + { + $this->_preroll = $preroll; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the flags field. + * + * @return integer + */ + public function getFlags() + { + return $this->_flags; + } + + /** + * Sets the flags field. + * + * @param integer $flags The flags field. + */ + public function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Returns the minimum Data Packet size in bytes. In general, the + * value of this field is invalid if the broadcast flag bit in the flags + * field is set to 1. However, the values for the Minimum Data Packet + * Size and Maximum Data Packet Size fields shall be set to the + * same value, and this value should be set to the packet size, even when + * the broadcast flag in the flags field is set to 1. + * + * @return integer + */ + public function getMinimumDataPacketSize() + { + return $this->_minimumDataPacketSize; + } + + /** + * Sets the minimum Data Packet size in bytes. In general, the value + * of this field is invalid if the broadcast flag bit in the flags field is + * set to 1. However, the values for the Minimum Data Packet Size and + * Maximum Data Packet Size fields shall be set to the same value, + * and this value should be set to the packet size, even when the broadcast + * flag in the flags field is set to 1. + * + * @param integer $minimumDataPacketSize The minimum Data Packet size + * in bytes. + */ + public function setMinimumDataPacketSize($minimumDataPacketSize) + { + $this->_minimumDataPacketSize = $minimumDataPacketSize; + } + + /** + * Returns the maximum Data Packet size in bytes. In general, the + * value of this field is invalid if the broadcast flag bit in the flags + * field is set to 1. However, the values for the Minimum Data Packet + * Size and Maximum Data Packet Size fields shall be set to the + * same value, and this value should be set to the packet size, even when + * the broadcast flag in the flags field is set to 1. + * + * @return integer + */ + public function getMaximumDataPacketSize() + { + return $this->_maximumDataPacketSize; + } + + /** + * Sets the maximum Data Packet size in bytes. In general, the value + * of this field is invalid if the broadcast flag bit in the flags field is + * set to 1. However, the values for the Minimum Data Packet Size and + * Maximum Data Packet Size fields shall be set to the same value, + * and this value should be set to the packet size, even when the broadcast + * flag in the flags field is set to 1. + * + * @param integer $maximumDataPacketSize The maximum Data Packet size + * in bytes + */ + public function setMaximumDataPacketSize($maximumDataPacketSize) + { + $this->_maximumDataPacketSize = $maximumDataPacketSize; + } + + /** + * Returns the maximum instantaneous bit rate in bits per second for the + * entire file. This is equal the sum of the bit rates of the individual + * digital media streams. + * + * @return integer + */ + public function getMaximumBitrate() + { + return $this->_maximumBitrate; + } + + /** + * Sets the maximum instantaneous bit rate in bits per second for the + * entire file. This is equal the sum of the bit rates of the individual + * digital media streams. + * + * @param integer $maximumBitrate The maximum instantaneous bit rate in bits + * per second. + */ + public function setMaximumBitrate($maximumBitrate) + { + $this->_maximumBitrate = $maximumBitrate; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $this->setSize(24 /* for header */ + 80); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_fileId) + ->writeInt64LE($this->_fileSize) + ->writeInt64LE($this->_creationDate) + ->writeInt64LE($this->_dataPacketsCount) + ->writeInt64LE($this->_playDuration) + ->writeInt64LE($this->_sendDuration) + ->writeInt64LE($this->_preroll) + ->writeUInt32LE($this->_flags) + ->writeUInt32LE($this->_minimumDataPacketSize) + ->writeUInt32LE($this->_maximumDataPacketSize) + ->writeUInt32LE($this->_maximumBitrate); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/GroupMutualExclusion.php b/app/libs/vendor/Zend/Media/Asf/Object/GroupMutualExclusion.php index 20907b6f..7e070cd9 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/GroupMutualExclusion.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/GroupMutualExclusion.php @@ -1,162 +1,162 @@ -Group Mutual Exclusion Object is used to describe mutual exclusion - * relationships between groups of streams. This object is organized in terms of - * records, each containing one or more streams, where a stream in record N - * cannot coexist with a stream in record M for N != M (however, streams in the - * same record can coexist). This mutual exclusion object would be used - * typically for the purpose of language mutual exclusion, and a record would - * consist of all streams for a particular language. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: GroupMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_GroupMutualExclusion - extends Zend_Media_Asf_Object -{ - const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; - const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; - const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; - - /** @var string */ - private $_exclusionType; - - /** @var Array */ - private $_records = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_exclusionType = $this->_reader->readGuid(); - $recordCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $recordCount; $i++) { - $streamNumbersCount = $this->_reader->readUInt16LE(); - $streamNumbers = array(); - for ($j = 0; $j < $streamNumbersCount; $j++) { - $streamNumbers[] = array - ('streamNumbers' => $this->_reader->readUInt16LE()); - } - $this->_records[] = $streamNumbers; - } - } - - /** - * Returns the nature of the mutual exclusion relationship. - * - * @return string - */ - public function getExclusionType() - { - return $this->_exclusionType; - } - - /** - * Sets the nature of the mutual exclusion relationship. - * - * @param string $exclusionType The exclusion type. - */ - public function setExclusionType($exclusionType) - { - $this->_exclusionType = $exclusionType; - } - - /** - * Returns an array of records. Each record consists of the following keys. - * - * o streamNumbers -- Specifies the stream numbers for this record. Valid - * values are between 1 and 127. - * - * @return Array - */ - public function getRecords() - { - return $this->_records; - } - - /** - * Sets an array of records. Each record is to consist of the following - * keys. - * - * o streamNumbers -- Specifies the stream numbers for this record. Valid - * values are between 1 and 127. - * - * @param Array $records The array of records - */ - public function setRecords($records) - { - $this->_records = $records; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - - $recordCount = count($this->_records); - $recordWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $recordCount; $i++) { - $recordWriter - ->writeUInt16LE - ($streamNumbersCount = count($this->_records[$i])); - for ($j = 0; $j < $streamNumbersCount; $j++) { - $recordWriter->writeUInt16LE - ($this->_records[$i][$j]['streamNumbers']); - } - } - - $this->setSize(24 /* for header */ + $recordWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_exclusionType) - ->writeUInt16LE($recordCount) - ->write($recordWriter->toString()); - } -} +Group Mutual Exclusion Object is used to describe mutual exclusion + * relationships between groups of streams. This object is organized in terms of + * records, each containing one or more streams, where a stream in record N + * cannot coexist with a stream in record M for N != M (however, streams in the + * same record can coexist). This mutual exclusion object would be used + * typically for the purpose of language mutual exclusion, and a record would + * consist of all streams for a particular language. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: GroupMutualExclusion.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_GroupMutualExclusion + extends Zend_Media_Asf_Object +{ + const MUTEX_LANGUAGE = 'd6e22a00-35da-11d1-9034-00a0c90349be'; + const MUTEX_BITRATE = 'd6e22a01-35da-11d1-9034-00a0c90349be'; + const MUTEX_UNKNOWN = 'd6e22a02-35da-11d1-9034-00a0c90349be'; + + /** @var string */ + private $_exclusionType; + + /** @var Array */ + private $_records = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_exclusionType = $this->_reader->readGuid(); + $recordCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $recordCount; $i++) { + $streamNumbersCount = $this->_reader->readUInt16LE(); + $streamNumbers = array(); + for ($j = 0; $j < $streamNumbersCount; $j++) { + $streamNumbers[] = array + ('streamNumbers' => $this->_reader->readUInt16LE()); + } + $this->_records[] = $streamNumbers; + } + } + + /** + * Returns the nature of the mutual exclusion relationship. + * + * @return string + */ + public function getExclusionType() + { + return $this->_exclusionType; + } + + /** + * Sets the nature of the mutual exclusion relationship. + * + * @param string $exclusionType The exclusion type. + */ + public function setExclusionType($exclusionType) + { + $this->_exclusionType = $exclusionType; + } + + /** + * Returns an array of records. Each record consists of the following keys. + * + * o streamNumbers -- Specifies the stream numbers for this record. Valid + * values are between 1 and 127. + * + * @return Array + */ + public function getRecords() + { + return $this->_records; + } + + /** + * Sets an array of records. Each record is to consist of the following + * keys. + * + * o streamNumbers -- Specifies the stream numbers for this record. Valid + * values are between 1 and 127. + * + * @param Array $records The array of records + */ + public function setRecords($records) + { + $this->_records = $records; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + + $recordCount = count($this->_records); + $recordWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $recordCount; $i++) { + $recordWriter + ->writeUInt16LE + ($streamNumbersCount = count($this->_records[$i])); + for ($j = 0; $j < $streamNumbersCount; $j++) { + $recordWriter->writeUInt16LE + ($this->_records[$i][$j]['streamNumbers']); + } + } + + $this->setSize(24 /* for header */ + $recordWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_exclusionType) + ->writeUInt16LE($recordCount) + ->write($recordWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Header.php b/app/libs/vendor/Zend/Media/Asf/Object/Header.php index f0eab7bc..7a5d4ea0 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Header.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Header.php @@ -1,131 +1,131 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Header.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Header extends Zend_Media_Asf_Object_Container -{ - /** @var integer */ - private $_reserved1; - - /** @var integer */ - private $_reserved2; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_reader->skip(4); - $this->_reserved1 = $this->_reader->readInt8(); - $this->_reserved2 = $this->_reader->readInt8(); - $this->constructObjects - (array - (self::FILE_PROPERTIES => 'FileProperties', - self::STREAM_PROPERTIES => 'StreamProperties', - self::HEADER_EXTENSION => 'HeaderExtension', - self::CODEC_LIST => 'CodecList', - self::SCRIPT_COMMAND => 'ScriptCommand', - self::MARKER => 'Marker', - self::BITRATE_MUTUAL_EXCLUSION => 'BitrateMutualExclusion', - self::ERROR_CORRECTION => 'ErrorCorrection', - self::CONTENT_DESCRIPTION => 'ContentDescription', - self::EXTENDED_CONTENT_DESCRIPTION => - 'ExtendedContentDescription', - self::CONTENT_BRANDING => 'ContentBranding', - self::STREAM_BITRATE_PROPERTIES => 'StreamBitrateProperties', - self::CONTENT_ENCRYPTION => 'ContentEncryption', - self::EXTENDED_CONTENT_ENCRYPTION => - 'ExtendedContentEncryption', - self::DIGITAL_SIGNATURE => 'DigitalSignature', - self::PADDING => 'Padding')); - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $objectsWriter = new Zend_Io_StringWriter(); - foreach ($this->getObjects() as $objects) { - foreach ($objects as $object) { - $object->write($objectsWriter); - } - } - - $this->setSize - (24 /* for header */ + 6 + $objectsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt32LE($this->getObjectCount()) - ->writeInt8($this->_reserved1) - ->writeInt8($this->_reserved2) - ->write($objectsWriter->toString()); - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Header.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Header extends Zend_Media_Asf_Object_Container +{ + /** @var integer */ + private $_reserved1; + + /** @var integer */ + private $_reserved2; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_reader->skip(4); + $this->_reserved1 = $this->_reader->readInt8(); + $this->_reserved2 = $this->_reader->readInt8(); + $this->constructObjects + (array + (self::FILE_PROPERTIES => 'FileProperties', + self::STREAM_PROPERTIES => 'StreamProperties', + self::HEADER_EXTENSION => 'HeaderExtension', + self::CODEC_LIST => 'CodecList', + self::SCRIPT_COMMAND => 'ScriptCommand', + self::MARKER => 'Marker', + self::BITRATE_MUTUAL_EXCLUSION => 'BitrateMutualExclusion', + self::ERROR_CORRECTION => 'ErrorCorrection', + self::CONTENT_DESCRIPTION => 'ContentDescription', + self::EXTENDED_CONTENT_DESCRIPTION => + 'ExtendedContentDescription', + self::CONTENT_BRANDING => 'ContentBranding', + self::STREAM_BITRATE_PROPERTIES => 'StreamBitrateProperties', + self::CONTENT_ENCRYPTION => 'ContentEncryption', + self::EXTENDED_CONTENT_ENCRYPTION => + 'ExtendedContentEncryption', + self::DIGITAL_SIGNATURE => 'DigitalSignature', + self::PADDING => 'Padding')); + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $objectsWriter = new Zend_Io_StringWriter(); + foreach ($this->getObjects() as $objects) { + foreach ($objects as $object) { + $object->write($objectsWriter); + } + } + + $this->setSize + (24 /* for header */ + 6 + $objectsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt32LE($this->getObjectCount()) + ->writeInt8($this->_reserved1) + ->writeInt8($this->_reserved2) + ->write($objectsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/HeaderExtension.php b/app/libs/vendor/Zend/Media/Asf/Object/HeaderExtension.php index 21532be7..8137c218 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/HeaderExtension.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/HeaderExtension.php @@ -1,110 +1,110 @@ -Header Extension Object allows additional functionality to be - * added to an ASF file while maintaining backward compatibility. The Header - * Extension Object is a container containing zero or more additional extended - * header objects. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: HeaderExtension.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_HeaderExtension - extends Zend_Media_Asf_Object_Container -{ - /** @var string */ - private $_reserved1; - - /** @var integer */ - private $_reserved2; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_reserved1 = $this->_reader->readGuid(); - $this->_reserved2 = $this->_reader->readUInt16LE(); - $this->_reader->skip(4); - $this->constructObjects - (array - (self::EXTENDED_STREAM_PROPERTIES => 'ExtendedStreamProperties', - self::ADVANCED_MUTUAL_EXCLUSION => 'AdvancedMutualExclusion', - self::GROUP_MUTUAL_EXCLUSION => 'GroupMutualExclusion', - self::STREAM_PRIORITIZATION => 'StreamPrioritization', - self::BANDWIDTH_SHARING => 'BandwidthSharing', - self::LANGUAGE_LIST => 'LanguageList', - self::METADATA => 'Metadata', - self::METADATA_LIBRARY => 'MetadataLibrary', - self::INDEX_PARAMETERS => 'IndexParameters', - self::MEDIA_OBJECT_INDEX_PARAMETERS => - 'MediaObjectIndexParameters', - self::TIMECODE_INDEX_PARAMETERS => 'TimecodeIndexParameters', - self::COMPATIBILITY => 'Compatibility', - self::ADVANCED_CONTENT_ENCRYPTION => - 'AdvancedContentEncryption', - self::PADDING => 'Padding')); - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $objectsWriter = new Zend_Io_StringWriter(); - foreach ($this->getObjects() as $objects) { - foreach ($objects as $object) { - $object->write($objectsWriter); - } - } - - $this->setSize - (24 /* for header */ + 22 + $objectsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_reserved1) - ->writeUInt16LE($this->_reserved2) - ->writeUInt32LE($objectsWriter->getSize()) - ->write($objectsWriter->toString()); - } -} +Header Extension Object allows additional functionality to be + * added to an ASF file while maintaining backward compatibility. The Header + * Extension Object is a container containing zero or more additional extended + * header objects. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: HeaderExtension.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_HeaderExtension + extends Zend_Media_Asf_Object_Container +{ + /** @var string */ + private $_reserved1; + + /** @var integer */ + private $_reserved2; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_reserved1 = $this->_reader->readGuid(); + $this->_reserved2 = $this->_reader->readUInt16LE(); + $this->_reader->skip(4); + $this->constructObjects + (array + (self::EXTENDED_STREAM_PROPERTIES => 'ExtendedStreamProperties', + self::ADVANCED_MUTUAL_EXCLUSION => 'AdvancedMutualExclusion', + self::GROUP_MUTUAL_EXCLUSION => 'GroupMutualExclusion', + self::STREAM_PRIORITIZATION => 'StreamPrioritization', + self::BANDWIDTH_SHARING => 'BandwidthSharing', + self::LANGUAGE_LIST => 'LanguageList', + self::METADATA => 'Metadata', + self::METADATA_LIBRARY => 'MetadataLibrary', + self::INDEX_PARAMETERS => 'IndexParameters', + self::MEDIA_OBJECT_INDEX_PARAMETERS => + 'MediaObjectIndexParameters', + self::TIMECODE_INDEX_PARAMETERS => 'TimecodeIndexParameters', + self::COMPATIBILITY => 'Compatibility', + self::ADVANCED_CONTENT_ENCRYPTION => + 'AdvancedContentEncryption', + self::PADDING => 'Padding')); + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $objectsWriter = new Zend_Io_StringWriter(); + foreach ($this->getObjects() as $objects) { + foreach ($objects as $object) { + $object->write($objectsWriter); + } + } + + $this->setSize + (24 /* for header */ + 22 + $objectsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_reserved1) + ->writeUInt16LE($this->_reserved2) + ->writeUInt32LE($objectsWriter->getSize()) + ->write($objectsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Index.php b/app/libs/vendor/Zend/Media/Asf/Object/Index.php index 0f0b4664..9373ac55 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Index.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Index.php @@ -1,193 +1,193 @@ -Index Object are in terms of presentation times. The - * corresponding Offset field values of the Index Entry byte - * offsets that, when combined with the Block Position value of the - * Index Block, indicate the starting location in bytes of an ASF Data - * Packet relative to the start of the first ASF Data Packet in the file. - * - * An offset value of 0xFFFFFFFF is used to indicate an invalid offset value. - * Invalid offsets signify that this particular index entry does not identify a - * valid indexible point. Invalid offsets may occur for the initial index - * entries of a digital media stream whose first ASF Data Packet has a non-zero - * send time. Invalid offsets may also occur in the case where a digital media - * stream has a large gap in the presentation time of successive objects. - * - * The Index Object is not recommended for use with files where the - * Send Time of the first Data Packet within the Data - * Object has a Send Time value significantly greater than zero - * (otherwise the index itself will be sparse and inefficient). - * - * Any ASF file containing an Index Object does also contain an Index - * Parameters Object in its {@link Zend_Media_Asf_Object_Header ASF Header}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Index.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Index extends Zend_Media_Asf_Object -{ - /** - * Indicates that the index type is Nearest Past Data Packet. The Nearest - * Past Data Packet indexes point to the data packet whose presentation time - * is closest to the index entry time. - */ - const NEAREST_PAST_DATA_PACKET = 1; - - /** - * Indicates that the index type is Nearest Past Media. The Nearest Past - * Object indexes point to the closest data packet containing an entire - * object or first fragment of an object. - */ - const NEAREST_PAST_MEDIA = 2; - - /** - * Indicates that the index type is Nearest Past Cleanpoint. The Nearest - * Past Cleanpoint indexes point to the closest data packet containing an - * entire object (or first fragment of an object) that has the Cleanpoint - * Flag set. - * - * Nearest Past Cleanpoint is the most common type of index. - */ - const NEAREST_PAST_CLEANPOINT = 3; - - /** @var integer */ - private $_indexEntryTimeInterval; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** @var Array */ - private $_indexBlocks = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_indexEntryTimeInterval = $this->_reader->readUInt32LE(); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - $indexBlocksCount = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - for ($i = 0; $i < $indexBlocksCount; $i++) { - $indexEntryCount = $this->_reader->readUInt32LE(); - $blockPositions = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $blockPositions[] = $this->_reader->readInt64LE(); - } - $offsets = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $offsets[] = $this->_reader->readUInt32LE(); - } - $this->_indexBlocks[] = array - ('blockPositions' => $blockPositions, - 'indexEntryOffsets' => $offsets); - } - } - - /** - * Returns the time interval between each index entry in ms. - * - * @return integer - */ - public function getIndexEntryTimeInterval() - { - return $this->_indexEntryTimeInterval; - } - - /** - * Returns an array of index specifiers. Each entry consists of the - * following keys. - * - * o streamNumber -- Specifies the stream number that the Index - * Specifiers refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o blockPositions -- Specifies a list of byte offsets of the beginnings - * of the blocks relative to the beginning of the first Data Packet (for - * example, the beginning of the Data Object + 50 bytes). - * - * o indexEntryOffsets -- Specifies the offset. An offset value of - * 0xffffffff indicates an invalid offset value. - * - * @return Array - */ - public function getIndexBlocks() - { - return $this->_indexBlocks; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Index Object are in terms of presentation times. The + * corresponding Offset field values of the Index Entry byte + * offsets that, when combined with the Block Position value of the + * Index Block, indicate the starting location in bytes of an ASF Data + * Packet relative to the start of the first ASF Data Packet in the file. + * + * An offset value of 0xFFFFFFFF is used to indicate an invalid offset value. + * Invalid offsets signify that this particular index entry does not identify a + * valid indexible point. Invalid offsets may occur for the initial index + * entries of a digital media stream whose first ASF Data Packet has a non-zero + * send time. Invalid offsets may also occur in the case where a digital media + * stream has a large gap in the presentation time of successive objects. + * + * The Index Object is not recommended for use with files where the + * Send Time of the first Data Packet within the Data + * Object has a Send Time value significantly greater than zero + * (otherwise the index itself will be sparse and inefficient). + * + * Any ASF file containing an Index Object does also contain an Index + * Parameters Object in its {@link Zend_Media_Asf_Object_Header ASF Header}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Index.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Index extends Zend_Media_Asf_Object +{ + /** + * Indicates that the index type is Nearest Past Data Packet. The Nearest + * Past Data Packet indexes point to the data packet whose presentation time + * is closest to the index entry time. + */ + const NEAREST_PAST_DATA_PACKET = 1; + + /** + * Indicates that the index type is Nearest Past Media. The Nearest Past + * Object indexes point to the closest data packet containing an entire + * object or first fragment of an object. + */ + const NEAREST_PAST_MEDIA = 2; + + /** + * Indicates that the index type is Nearest Past Cleanpoint. The Nearest + * Past Cleanpoint indexes point to the closest data packet containing an + * entire object (or first fragment of an object) that has the Cleanpoint + * Flag set. + * + * Nearest Past Cleanpoint is the most common type of index. + */ + const NEAREST_PAST_CLEANPOINT = 3; + + /** @var integer */ + private $_indexEntryTimeInterval; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** @var Array */ + private $_indexBlocks = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_indexEntryTimeInterval = $this->_reader->readUInt32LE(); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + $indexBlocksCount = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + for ($i = 0; $i < $indexBlocksCount; $i++) { + $indexEntryCount = $this->_reader->readUInt32LE(); + $blockPositions = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $blockPositions[] = $this->_reader->readInt64LE(); + } + $offsets = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $offsets[] = $this->_reader->readUInt32LE(); + } + $this->_indexBlocks[] = array + ('blockPositions' => $blockPositions, + 'indexEntryOffsets' => $offsets); + } + } + + /** + * Returns the time interval between each index entry in ms. + * + * @return integer + */ + public function getIndexEntryTimeInterval() + { + return $this->_indexEntryTimeInterval; + } + + /** + * Returns an array of index specifiers. Each entry consists of the + * following keys. + * + * o streamNumber -- Specifies the stream number that the Index + * Specifiers refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o blockPositions -- Specifies a list of byte offsets of the beginnings + * of the blocks relative to the beginning of the first Data Packet (for + * example, the beginning of the Data Object + 50 bytes). + * + * o indexEntryOffsets -- Specifies the offset. An offset value of + * 0xffffffff indicates an invalid offset value. + * + * @return Array + */ + public function getIndexBlocks() + { + return $this->_indexBlocks; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/IndexParameters.php b/app/libs/vendor/Zend/Media/Asf/Object/IndexParameters.php index 60582f95..b83af812 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/IndexParameters.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/IndexParameters.php @@ -1,125 +1,125 @@ -Index Parameters Object supplies information about those streams - * that are actually indexed (there must be at least one stream in an index) by - * the {@link Zend_Media_Asf_Object_Index Index Object} and how they are being - * indexed. This object shall be present in the - * {@link Zend_Media_Asf_Object_Header Header Object} if there is an - * {@link Zend_Media_Asf_Object_Index Index Object} present in the file. - * - - * An Index Specifier is required for each stream that will be indexed by the - * {@link Zend_Media_Asf_Object_Index Index Object}. These specifiers must - * exactly match those in the {@link Zend_Media_Asf_Object_Index Index Object}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: IndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_IndexParameters extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_indexEntryTimeInterval; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_indexEntryTimeInterval = $this->_reader->readUInt32LE(); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - } - - /** - * Returns the time interval between index entries in milliseconds. This - * value cannot be 0. - * - * @return integer - */ - public function getIndexEntryTimeInterval() - { - return $this->_indexEntryTimeInterval; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o streamNumber -- Specifies the stream number that the Index Specifiers - * refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. Values are as follows: - * 1 = Nearest Past Data Packet, - * 2 = Nearest Past Media Object, and - * 3 = Nearest Past Cleanpoint. - * The Nearest Past Data Packet indexes point to the data packet whose - * presentation time is closest to the index entry time. The Nearest - * Past Object indexes point to the closest data packet containing an - * entire object or first fragment of an object. The Nearest Past - * Cleanpoint indexes point to the closest data packet containing an - * entire object (or first fragment of an object) that has the - * Cleanpoint Flag set. Nearest Past Cleanpoint is the most common type - * of index. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Index Parameters Object supplies information about those streams + * that are actually indexed (there must be at least one stream in an index) by + * the {@link Zend_Media_Asf_Object_Index Index Object} and how they are being + * indexed. This object shall be present in the + * {@link Zend_Media_Asf_Object_Header Header Object} if there is an + * {@link Zend_Media_Asf_Object_Index Index Object} present in the file. + * + + * An Index Specifier is required for each stream that will be indexed by the + * {@link Zend_Media_Asf_Object_Index Index Object}. These specifiers must + * exactly match those in the {@link Zend_Media_Asf_Object_Index Index Object}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: IndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_IndexParameters extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_indexEntryTimeInterval; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_indexEntryTimeInterval = $this->_reader->readUInt32LE(); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + } + + /** + * Returns the time interval between index entries in milliseconds. This + * value cannot be 0. + * + * @return integer + */ + public function getIndexEntryTimeInterval() + { + return $this->_indexEntryTimeInterval; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o streamNumber -- Specifies the stream number that the Index Specifiers + * refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. Values are as follows: + * 1 = Nearest Past Data Packet, + * 2 = Nearest Past Media Object, and + * 3 = Nearest Past Cleanpoint. + * The Nearest Past Data Packet indexes point to the data packet whose + * presentation time is closest to the index entry time. The Nearest + * Past Object indexes point to the closest data packet containing an + * entire object or first fragment of an object. The Nearest Past + * Cleanpoint indexes point to the closest data packet containing an + * entire object (or first fragment of an object) that has the + * Cleanpoint Flag set. Nearest Past Cleanpoint is the most common type + * of index. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/LanguageList.php b/app/libs/vendor/Zend/Media/Asf/Object/LanguageList.php index f96bd9e2..22111def 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/LanguageList.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/LanguageList.php @@ -1,116 +1,116 @@ -Language List Object contains an array of Unicode-based language - * IDs. All other header objects refer to languages through zero-based positions - * in this array. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: LanguageList.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_LanguageList extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_languages = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $languageIdRecordsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $languageIdRecordsCount; $i++) { - $languageIdLength = $this->_reader->readInt8(); - $languageId = $this->_reader->readString16($languageIdLength); - $this->_languages[] = iconv - ('utf-16le', $this->getOption('encoding'), $languageId); - } - } - - /** - * Returns the array of language ids. - * - * @return Array - */ - public function getLanguages() - { - return $this->_languages; - } - - /** - * Sets the array of language ids. - * - * @param Array $languages The array of language ids. - */ - public function setLanguages($languages) - { - $this->_languages = $languages; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $languageIdRecordsCount = count($this->_languages); - $languageIdRecordsWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $languageIdRecordsCount; $i++) { - $languageIdRecordsWriter - ->writeInt8(strlen($languageId = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_languages[$i]) . "\0\0")) - ->writeString16($languageId); - } - - $this->setSize - (24 /* for header */ + 2 + $languageIdRecordsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($languageIdRecordsCount) - ->write($languageIdRecordsWriter->toString()); - } -} +Language List Object contains an array of Unicode-based language + * IDs. All other header objects refer to languages through zero-based positions + * in this array. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: LanguageList.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_LanguageList extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_languages = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $languageIdRecordsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $languageIdRecordsCount; $i++) { + $languageIdLength = $this->_reader->readInt8(); + $languageId = $this->_reader->readString16($languageIdLength); + $this->_languages[] = iconv + ('utf-16le', $this->getOption('encoding'), $languageId); + } + } + + /** + * Returns the array of language ids. + * + * @return Array + */ + public function getLanguages() + { + return $this->_languages; + } + + /** + * Sets the array of language ids. + * + * @param Array $languages The array of language ids. + */ + public function setLanguages($languages) + { + $this->_languages = $languages; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $languageIdRecordsCount = count($this->_languages); + $languageIdRecordsWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $languageIdRecordsCount; $i++) { + $languageIdRecordsWriter + ->writeInt8(strlen($languageId = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_languages[$i]) . "\0\0")) + ->writeString16($languageId); + } + + $this->setSize + (24 /* for header */ + 2 + $languageIdRecordsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($languageIdRecordsCount) + ->write($languageIdRecordsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Marker.php b/app/libs/vendor/Zend/Media/Asf/Object/Marker.php index fcaef4c6..c807ef38 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Marker.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Marker.php @@ -1,197 +1,197 @@ -Marker Object class. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Marker.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Marker extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_reserved1; - - /** @var integer */ - private $_reserved2; - - /** @var string */ - private $_name; - - /** @var Array */ - private $_markers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_reserved1 = $this->_reader->readGuid(); - $markersCount = $this->_reader->readUInt32LE(); - $this->_reserved2 = $this->_reader->readUInt16LE(); - $nameLength = $this->_reader->readUInt16LE(); - $this->_name = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($nameLength)); - for ($i = 0; $i < $markersCount; $i++) { - $marker = array - ('offset' => $this->_reader->readInt64LE(), - 'presentationTime' => $this->_reader->readInt64LE()); - $this->_reader->skip(2); - $marker['sendTime'] = $this->_reader->readUInt32LE(); - $marker['flags'] = $this->_reader->readUInt32LE(); - $descriptionLength = $this->_reader->readUInt32LE(); - $marker['description'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($descriptionLength)); - $this->_markers[] = $marker; - } - } - - /** - * Returns the name of the Marker Object. - * - * @return Array - */ - public function getName() - { - return $this->_name; - } - - /** - * Returns the name of the Marker Object. - * - * @param string $name The name. - */ - public function setName($name) - { - $this->_name = $name; - } - - /** - * Returns an array of markers. Each entry consists of the following keys. - * - * o offset -- Specifies a byte offset into the Data Object to the - * actual position of the marker in the Data Object. ASF parsers - * must seek to this position to properly display data at the specified - * marker Presentation Time. - * - * o presentationTime -- Specifies the presentation time of the marker, in - * 100-nanosecond units. - * - * o sendTime -- Specifies the send time of the marker entry, in - * milliseconds. - * - * o flags -- Flags are reserved and should be set to 0. - * - * o description -- Specifies a description of the marker entry. - * - * @return Array - */ - public function getMarkers() - { - return $this->_markers; - } - - /** - * Sets the array of markers. Each entry is to consist of the following - * keys. - * - * o offset -- Specifies a byte offset into the Data Object to the - * actual position of the marker in the Data Object. ASF parsers - * must seek to this position to properly display data at the specified - * marker Presentation Time. - * - * o presentationTime -- Specifies the presentation time of the marker, in - * 100-nanosecond units. - * - * o sendTime -- Specifies the send time of the marker entry, in - * milliseconds. - * - * o flags -- Flags are reserved and should be set to 0. - * - * o description -- Specifies a description of the marker entry. - * - * @param Array $markers The array of markers. - */ - public function setMarkers($markers) - { - $this->_markers = $markers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - - $name = iconv - ($this->getOption('encoding'), 'utf-16le', $this->_name) . "\0\0"; - $markersCount = count($this->_markers); - $markersWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $markersCount; $i++) { - $markersWriter - ->writeInt64LE($this->_markers[$i]['offset']) - ->writeInt64LE($this->_markers[$i]['presentationTime']) - ->writeUInt16LE - (12 + ($descriptionLength = strlen($description = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_markers[$i]['description']) . "\0\0"))) - ->writeUInt32LE($this->_markers[$i]['sendTime']) - ->writeUInt32LE($this->_markers[$i]['flags']) - ->writeUInt32LE($descriptionLength) - ->writeString16($description); - } - - $this->setSize - (24 /* for header */ + 24 + strlen($name) + - $markersWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_reserved1) - ->writeUInt32LE($markersCount) - ->writeUInt16LE($this->_reserved2) - ->writeUInt16LE(strlen($name)) - ->writeString16($name) - ->write($markersWriter->toString()); - } -} +Marker Object class. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Marker.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Marker extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_reserved1; + + /** @var integer */ + private $_reserved2; + + /** @var string */ + private $_name; + + /** @var Array */ + private $_markers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_reserved1 = $this->_reader->readGuid(); + $markersCount = $this->_reader->readUInt32LE(); + $this->_reserved2 = $this->_reader->readUInt16LE(); + $nameLength = $this->_reader->readUInt16LE(); + $this->_name = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($nameLength)); + for ($i = 0; $i < $markersCount; $i++) { + $marker = array + ('offset' => $this->_reader->readInt64LE(), + 'presentationTime' => $this->_reader->readInt64LE()); + $this->_reader->skip(2); + $marker['sendTime'] = $this->_reader->readUInt32LE(); + $marker['flags'] = $this->_reader->readUInt32LE(); + $descriptionLength = $this->_reader->readUInt32LE(); + $marker['description'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($descriptionLength)); + $this->_markers[] = $marker; + } + } + + /** + * Returns the name of the Marker Object. + * + * @return Array + */ + public function getName() + { + return $this->_name; + } + + /** + * Returns the name of the Marker Object. + * + * @param string $name The name. + */ + public function setName($name) + { + $this->_name = $name; + } + + /** + * Returns an array of markers. Each entry consists of the following keys. + * + * o offset -- Specifies a byte offset into the Data Object to the + * actual position of the marker in the Data Object. ASF parsers + * must seek to this position to properly display data at the specified + * marker Presentation Time. + * + * o presentationTime -- Specifies the presentation time of the marker, in + * 100-nanosecond units. + * + * o sendTime -- Specifies the send time of the marker entry, in + * milliseconds. + * + * o flags -- Flags are reserved and should be set to 0. + * + * o description -- Specifies a description of the marker entry. + * + * @return Array + */ + public function getMarkers() + { + return $this->_markers; + } + + /** + * Sets the array of markers. Each entry is to consist of the following + * keys. + * + * o offset -- Specifies a byte offset into the Data Object to the + * actual position of the marker in the Data Object. ASF parsers + * must seek to this position to properly display data at the specified + * marker Presentation Time. + * + * o presentationTime -- Specifies the presentation time of the marker, in + * 100-nanosecond units. + * + * o sendTime -- Specifies the send time of the marker entry, in + * milliseconds. + * + * o flags -- Flags are reserved and should be set to 0. + * + * o description -- Specifies a description of the marker entry. + * + * @param Array $markers The array of markers. + */ + public function setMarkers($markers) + { + $this->_markers = $markers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + + $name = iconv + ($this->getOption('encoding'), 'utf-16le', $this->_name) . "\0\0"; + $markersCount = count($this->_markers); + $markersWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $markersCount; $i++) { + $markersWriter + ->writeInt64LE($this->_markers[$i]['offset']) + ->writeInt64LE($this->_markers[$i]['presentationTime']) + ->writeUInt16LE + (12 + ($descriptionLength = strlen($description = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_markers[$i]['description']) . "\0\0"))) + ->writeUInt32LE($this->_markers[$i]['sendTime']) + ->writeUInt32LE($this->_markers[$i]['flags']) + ->writeUInt32LE($descriptionLength) + ->writeString16($description); + } + + $this->setSize + (24 /* for header */ + 24 + strlen($name) + + $markersWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_reserved1) + ->writeUInt32LE($markersCount) + ->writeUInt16LE($this->_reserved2) + ->writeUInt16LE(strlen($name)) + ->writeString16($name) + ->write($markersWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndex.php b/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndex.php index bf23137c..b9b2bf54 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndex.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndex.php @@ -1,186 +1,186 @@ -Media Object Index Object are in terms of media - * object numbers, with the first frame for a given stream in the ASF file - * corresponding to entry 0 in the Media Object Index Object. The - * corresponding Offset field values of the Index Entry are byte - * offsets that, when combined with the Block Position value of the - * Index Block, indicate the starting location in bytes of an ASF Data Packet - * relative to the start of the first ASF Data Packet in the file. - * - - * Any ASF file containing a Media Object Index Object shall also contain - * a Media Object Index Parameters Object in its - * {@link Zend_Media_Asf_Object_Header ASF Header}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: MediaObjectIndex.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_MediaObjectIndex extends Zend_Media_Asf_Object -{ - /** - * Indicates that the index type is Nearest Past Data Packet. The Nearest - * Past Data Packet indexes point to the data packet whose presentation time - * is closest to the index entry time. - */ - const NEAREST_PAST_DATA_PACKET = 1; - - /** - * Indicates that the index type is Nearest Past Media. The Nearest Past - * Object indexes point to the closest data packet containing an entire - * object or first fragment of an object. - */ - const NEAREST_PAST_MEDIA = 2; - - /** - * Indicates that the index type is Nearest Past Cleanpoint. The Nearest - * Past Cleanpoint indexes point to the closest data packet containing an - * entire object (or first fragment of an object) that has the Cleanpoint - * Flag set. - * - * Nearest Past Cleanpoint is the most common type of index. - */ - const NEAREST_PAST_CLEANPOINT = 3; - - /** @var integer */ - private $_indexEntryCountInterval; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** @var Array */ - private $_indexBlocks = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - $indexBlocksCount = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - for ($i = 0; $i < $indexBlocksCount; $i++) { - $indexEntryCount = $this->_reader->readUInt32LE(); - $blockPositions = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $blockPositions[] = $this->_reader->readInt64LE(); - } - $offsets = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $offsets[] = $this->_reader->readUInt32LE(); - } - $this->_indexBlocks[] = array - ('blockPositions' => $blockPositions, - 'indexEntryOffsets' => $offsets); - } - } - - /** - * Returns the interval between each index entry in number of media objects. - * - * @return integer - */ - public function getIndexEntryCountInterval() - { - return $this->_indexEntryCountInterval; - } - - /** - * Returns an array of index specifiers. Each entry consists of the - * following keys. - * - * o streamNumber -- Specifies the stream number that the Index - * Specifiers refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o blockPositions -- Specifies a list of byte offsets of the beginnings - * of the blocks relative to the beginning of the first Data Packet (for - * example, the beginning of the Data Object + 50 bytes). - * - * o indexEntryOffsets -- Specifies the offset. An offset value of - * 0xffffffff indicates an invalid offset value. - * - * @return Array - */ - public function getIndexBlocks() - { - return $this->_indexBlocks; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Media Object Index Object are in terms of media + * object numbers, with the first frame for a given stream in the ASF file + * corresponding to entry 0 in the Media Object Index Object. The + * corresponding Offset field values of the Index Entry are byte + * offsets that, when combined with the Block Position value of the + * Index Block, indicate the starting location in bytes of an ASF Data Packet + * relative to the start of the first ASF Data Packet in the file. + * + + * Any ASF file containing a Media Object Index Object shall also contain + * a Media Object Index Parameters Object in its + * {@link Zend_Media_Asf_Object_Header ASF Header}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: MediaObjectIndex.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_MediaObjectIndex extends Zend_Media_Asf_Object +{ + /** + * Indicates that the index type is Nearest Past Data Packet. The Nearest + * Past Data Packet indexes point to the data packet whose presentation time + * is closest to the index entry time. + */ + const NEAREST_PAST_DATA_PACKET = 1; + + /** + * Indicates that the index type is Nearest Past Media. The Nearest Past + * Object indexes point to the closest data packet containing an entire + * object or first fragment of an object. + */ + const NEAREST_PAST_MEDIA = 2; + + /** + * Indicates that the index type is Nearest Past Cleanpoint. The Nearest + * Past Cleanpoint indexes point to the closest data packet containing an + * entire object (or first fragment of an object) that has the Cleanpoint + * Flag set. + * + * Nearest Past Cleanpoint is the most common type of index. + */ + const NEAREST_PAST_CLEANPOINT = 3; + + /** @var integer */ + private $_indexEntryCountInterval; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** @var Array */ + private $_indexBlocks = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + $indexBlocksCount = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + for ($i = 0; $i < $indexBlocksCount; $i++) { + $indexEntryCount = $this->_reader->readUInt32LE(); + $blockPositions = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $blockPositions[] = $this->_reader->readInt64LE(); + } + $offsets = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $offsets[] = $this->_reader->readUInt32LE(); + } + $this->_indexBlocks[] = array + ('blockPositions' => $blockPositions, + 'indexEntryOffsets' => $offsets); + } + } + + /** + * Returns the interval between each index entry in number of media objects. + * + * @return integer + */ + public function getIndexEntryCountInterval() + { + return $this->_indexEntryCountInterval; + } + + /** + * Returns an array of index specifiers. Each entry consists of the + * following keys. + * + * o streamNumber -- Specifies the stream number that the Index + * Specifiers refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o blockPositions -- Specifies a list of byte offsets of the beginnings + * of the blocks relative to the beginning of the first Data Packet (for + * example, the beginning of the Data Object + 50 bytes). + * + * o indexEntryOffsets -- Specifies the offset. An offset value of + * 0xffffffff indicates an invalid offset value. + * + * @return Array + */ + public function getIndexBlocks() + { + return $this->_indexBlocks; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndexParameters.php b/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndexParameters.php index f117fe53..e4a8c442 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndexParameters.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/MediaObjectIndexParameters.php @@ -1,133 +1,133 @@ -Media Object Index Parameters Object supplies information about - * those streams that actually indexed (there must be at least one stream in an - * index) by media objects. This object shall be present in the - * {@link Zend_Media_Asf_Object_Header Header Object} if there is a - * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object} - * present in the file. - * - * An Index Specifier is required for each stream that will be indexed by the - * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object}. - * These specifiers must exactly match those in the - * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: MediaObjectIndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_MediaObjectIndexParameters - extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_indexEntryCountInterval; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - } - - /** - * Returns the interval between each index entry by the number of media - * objects. This value cannot be 0. - * - * @return integer - */ - public function getIndexEntryCountInterval() - { - return $this->_indexEntryCountInterval; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o streamNumber -- Specifies the stream number that the Index Specifiers - * refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. Values are defined as - * follows: - * 1 = Nearest Past Data Packet, - * 2 = Nearest Past Media Object, - * 3 = Nearest Past Cleanpoint, - * 0xff = Frame Number Offset. - * For a video stream, the Nearest Past Media Object and Nearest Past - * Data Packet indexes point to the closest data packet containing an - * entire video frame or first fragment of a video frame; Nearest Past - * Cleanpoint indexes point to the closest data packet containing an - * entire video frame (or first fragment of a video frame) that is a key - * frame; and Frame Number Offset indicates how many more frames need to - * be read for the given stream, starting with the first frame in the - * packet pointed to by the index entry, in order to get to the - * requested frame. Nearest Past Media Object is the most common value. - * Because ASF payloads do not contain the full frame number, there is - * often a Frame Number Offset index alongside one of the other types of - * indexes to allow the user to identify the exact frame being seeked - * to. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Media Object Index Parameters Object supplies information about + * those streams that actually indexed (there must be at least one stream in an + * index) by media objects. This object shall be present in the + * {@link Zend_Media_Asf_Object_Header Header Object} if there is a + * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object} + * present in the file. + * + * An Index Specifier is required for each stream that will be indexed by the + * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object}. + * These specifiers must exactly match those in the + * {@link Zend_Media_Asf_Object_MediaObjectIndex Media Object Index Object}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: MediaObjectIndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_MediaObjectIndexParameters + extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_indexEntryCountInterval; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + } + + /** + * Returns the interval between each index entry by the number of media + * objects. This value cannot be 0. + * + * @return integer + */ + public function getIndexEntryCountInterval() + { + return $this->_indexEntryCountInterval; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o streamNumber -- Specifies the stream number that the Index Specifiers + * refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. Values are defined as + * follows: + * 1 = Nearest Past Data Packet, + * 2 = Nearest Past Media Object, + * 3 = Nearest Past Cleanpoint, + * 0xff = Frame Number Offset. + * For a video stream, the Nearest Past Media Object and Nearest Past + * Data Packet indexes point to the closest data packet containing an + * entire video frame or first fragment of a video frame; Nearest Past + * Cleanpoint indexes point to the closest data packet containing an + * entire video frame (or first fragment of a video frame) that is a key + * frame; and Frame Number Offset indicates how many more frames need to + * be read for the given stream, starting with the first frame in the + * packet pointed to by the index entry, in order to get to the + * requested frame. Nearest Past Media Object is the most common value. + * Because ASF payloads do not contain the full frame number, there is + * often a Frame Number Offset index alongside one of the other types of + * indexes to allow the user to identify the exact frame being seeked + * to. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Metadata.php b/app/libs/vendor/Zend/Media/Asf/Object/Metadata.php index 9cf6f73a..a82ce302 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Metadata.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Metadata.php @@ -1,218 +1,218 @@ -Metadata Object permits authors to store stream-based metadata in - * a file. This object supports the same types of metadata information as the - * Extended Content Description Object except that it also allows a - * stream number to be specified. - * - * @todo Implement better handling of various types of attributes - * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Metadata.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Metadata extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_descriptionRecords = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $descriptionRecordsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $descriptionRecordsCount; $i++) { - $this->_reader->skip(2); - $descriptionRecord = - array('streamNumber' => $this->_reader->readUInt16LE()); - $nameLength = $this->_reader->readUInt16LE(); - $dataType = $this->_reader->readUInt16LE(); - $dataLength = $this->_reader->readUInt32LE(); - $descriptionRecord['name'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($nameLength)); - switch ($dataType) { - case 0: // Unicode string - $descriptionRecord['data'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($dataLength)); - break; - case 1: // BYTE array - $descriptionRecord['data'] = $this->_reader->read($dataLength); - break; - case 2: // BOOL - $descriptionRecord['data'] = $this->_reader->readUInt16LE() == 1; - break; - case 3: // DWORD - $descriptionRecord['data'] = $this->_reader->readUInt32LE(); - break; - case 4: // QWORD - $descriptionRecord['data'] = $this->_reader->readInt64LE(); - break; - case 5: // WORD - $descriptionRecord['data'] = $this->_reader->readUInt16LE(); - break; - default: - break; - } - $this->_descriptionRecords[] = $descriptionRecord; - } - } - - /** - * Returns the array of description records. Each record consists of the - * following keys. - * - * o streamNumber -- Specifies the stream number. Valid values are between - * 1 and 127. - * - * o name -- Specifies the name that uniquely identifies the attribute - * being described. Names are case-sensitive. - * - * o data -- Specifies the actual metadata being stored. - * - * @return Array - */ - public function getDescriptionRecords() - { - return $this->_descriptionRecords; - } - - /** - * Sets the array of description records. Each record must consist of the - * following keys. - * - * o streamNumber -- Specifies the stream number. Valid values are between - * 1 and 127. - * - * o name -- Specifies the name that uniquely identifies the attribute - * being described. Names are case-sensitive. - * - * o data -- Specifies the actual metadata being stored. - * - * @param Array $descriptionRecords The array of description records. - */ - public function setDescriptionRecords($descriptionRecords) - { - $this->_descriptionRecords = $descriptionRecords; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $descriptionRecordsCount = count($this->_descriptionRecords); - $descriptionRecordsWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $descriptionRecordsCount; $i++) { - $descriptionRecordsWriter - ->writeUInt16LE(0) - ->writeUInt16LE($this->_descriptionRecords[$i]['streamNumber']) - ->writeUInt16LE(strlen($name = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_descriptionRecords[$i]['name']) . "\0\0")); - if (is_string($this->_descriptionRecords[$i]['data'])) { - /* There is no way to distinguish byte arrays from unicode - * strings and hence the need for a list of fields of type byte - * array */ - static $byteArray = array ( - '' - ); // TODO: Add to the list if you encounter one - - if (in_array($name, $byteArray)) { - $descriptionRecordsWriter - ->writeUInt16LE(1) - ->writeUInt32LE - (strlen($this->_descriptionRecords[$i]['data'])) - ->write($name) - ->write($this->_descriptionRecords[$i]['data']); - } else { - $value = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_descriptionRecords[$i]['data']); - $value = ($value ? $value . "\0\0" : ''); - $descriptionRecordsWriter - ->writeUInt16LE(0) - ->writeUInt32LE(strlen($value)) - ->write($name) - ->writeString16($value); - } - } else if (is_bool($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(2) - ->writeUInt32LE(2) - ->write($name) - ->writeUInt16LE - ($this->_descriptionRecords[$i]['data'] ? 1 : 0); - } else if (is_int($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(3) - ->writeUInt32LE(4) - ->write($name) - ->writeUInt32LE($this->_descriptionRecords[$i]['data']); - } else if (is_float($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(4) - ->writeUInt32LE(8) - ->write($name) - ->writeInt64LE($this->_descriptionRecords[$i]['data']); - } else { - // Invalid value and there is nothing to be done - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Invalid data type'); - } - } - - $this->setSize - (24 /* for header */ + 2 + $descriptionRecordsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($descriptionRecordsCount) - ->write($descriptionRecordsWriter->toString()); - } -} +Metadata Object permits authors to store stream-based metadata in + * a file. This object supports the same types of metadata information as the + * Extended Content Description Object except that it also allows a + * stream number to be specified. + * + * @todo Implement better handling of various types of attributes + * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Metadata.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Metadata extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_descriptionRecords = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $descriptionRecordsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $descriptionRecordsCount; $i++) { + $this->_reader->skip(2); + $descriptionRecord = + array('streamNumber' => $this->_reader->readUInt16LE()); + $nameLength = $this->_reader->readUInt16LE(); + $dataType = $this->_reader->readUInt16LE(); + $dataLength = $this->_reader->readUInt32LE(); + $descriptionRecord['name'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($nameLength)); + switch ($dataType) { + case 0: // Unicode string + $descriptionRecord['data'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($dataLength)); + break; + case 1: // BYTE array + $descriptionRecord['data'] = $this->_reader->read($dataLength); + break; + case 2: // BOOL + $descriptionRecord['data'] = $this->_reader->readUInt16LE() == 1; + break; + case 3: // DWORD + $descriptionRecord['data'] = $this->_reader->readUInt32LE(); + break; + case 4: // QWORD + $descriptionRecord['data'] = $this->_reader->readInt64LE(); + break; + case 5: // WORD + $descriptionRecord['data'] = $this->_reader->readUInt16LE(); + break; + default: + break; + } + $this->_descriptionRecords[] = $descriptionRecord; + } + } + + /** + * Returns the array of description records. Each record consists of the + * following keys. + * + * o streamNumber -- Specifies the stream number. Valid values are between + * 1 and 127. + * + * o name -- Specifies the name that uniquely identifies the attribute + * being described. Names are case-sensitive. + * + * o data -- Specifies the actual metadata being stored. + * + * @return Array + */ + public function getDescriptionRecords() + { + return $this->_descriptionRecords; + } + + /** + * Sets the array of description records. Each record must consist of the + * following keys. + * + * o streamNumber -- Specifies the stream number. Valid values are between + * 1 and 127. + * + * o name -- Specifies the name that uniquely identifies the attribute + * being described. Names are case-sensitive. + * + * o data -- Specifies the actual metadata being stored. + * + * @param Array $descriptionRecords The array of description records. + */ + public function setDescriptionRecords($descriptionRecords) + { + $this->_descriptionRecords = $descriptionRecords; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $descriptionRecordsCount = count($this->_descriptionRecords); + $descriptionRecordsWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $descriptionRecordsCount; $i++) { + $descriptionRecordsWriter + ->writeUInt16LE(0) + ->writeUInt16LE($this->_descriptionRecords[$i]['streamNumber']) + ->writeUInt16LE(strlen($name = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_descriptionRecords[$i]['name']) . "\0\0")); + if (is_string($this->_descriptionRecords[$i]['data'])) { + /* There is no way to distinguish byte arrays from unicode + * strings and hence the need for a list of fields of type byte + * array */ + static $byteArray = array ( + '' + ); // TODO: Add to the list if you encounter one + + if (in_array($name, $byteArray)) { + $descriptionRecordsWriter + ->writeUInt16LE(1) + ->writeUInt32LE + (strlen($this->_descriptionRecords[$i]['data'])) + ->write($name) + ->write($this->_descriptionRecords[$i]['data']); + } else { + $value = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_descriptionRecords[$i]['data']); + $value = ($value ? $value . "\0\0" : ''); + $descriptionRecordsWriter + ->writeUInt16LE(0) + ->writeUInt32LE(strlen($value)) + ->write($name) + ->writeString16($value); + } + } else if (is_bool($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(2) + ->writeUInt32LE(2) + ->write($name) + ->writeUInt16LE + ($this->_descriptionRecords[$i]['data'] ? 1 : 0); + } else if (is_int($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(3) + ->writeUInt32LE(4) + ->write($name) + ->writeUInt32LE($this->_descriptionRecords[$i]['data']); + } else if (is_float($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(4) + ->writeUInt32LE(8) + ->write($name) + ->writeInt64LE($this->_descriptionRecords[$i]['data']); + } else { + // Invalid value and there is nothing to be done + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Invalid data type'); + } + } + + $this->setSize + (24 /* for header */ + 2 + $descriptionRecordsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($descriptionRecordsCount) + ->write($descriptionRecordsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/MetadataLibrary.php b/app/libs/vendor/Zend/Media/Asf/Object/MetadataLibrary.php index ba31f1e8..0399a230 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/MetadataLibrary.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/MetadataLibrary.php @@ -1,256 +1,256 @@ -Metadata Library Object lets authors store stream-based, - * language-attributed, multiply defined, and large metadata attributes in a - * file. - * - * This object supports the same types of metadata as the - * {@link Zend_Media_Asf_Object_Metadata Metadata Object}, as well as - * attributes with language IDs, attributes that are defined more than once, - * large attributes, and attributes with the GUID data type. - * - * @todo Implement better handling of various types of attributes - * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: MetadataLibrary.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_MetadataLibrary extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_descriptionRecords = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $descriptionRecordsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $descriptionRecordsCount; $i++) { - $descriptionRecord = array - ('languageIndex' => $this->_reader->readUInt16LE(), - 'streamNumber' => $this->_reader->readUInt16LE()); - $nameLength = $this->_reader->readUInt16LE(); - $dataType = $this->_reader->readUInt16LE(); - $dataLength = $this->_reader->readUInt32LE(); - $descriptionRecord['name'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($nameLength)); - switch ($dataType) { - case 0: // Unicode string - $descriptionRecord['data'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($dataLength)); - break; - case 1: // BYTE array - $descriptionRecord['data'] = - $this->_reader->read($dataLength); - break; - case 2: // BOOL - $descriptionRecord['data'] = - $this->_reader->readUInt16LE() == 1; - break; - case 3: // DWORD - $descriptionRecord['data'] = $this->_reader->readUInt32LE(); - break; - case 4: // QWORD - $descriptionRecord['data'] = $this->_reader->readInt64LE(); - break; - case 5: // WORD - $descriptionRecord['data'] = $this->_reader->readUInt16LE(); - break; - case 6: // GUID - $descriptionRecord['data'] = $this->_reader->readGuid(); - break; - default: - break; - } - $this->_descriptionRecords[] = $descriptionRecord; - } - } - - /** - * Returns an array of description records. Each record consists of the - * following keys. - * - * o languageIndex -- Specifies the index into the - * {@link LanguageList Language List Object} that identifies the - * language of this attribute. If there is no Language List - * Object present, this field is zero. - * - * o streamNumber -- Specifies whether the entry applies to a specific - * digital media stream or whether it applies to the whole file. A value - * of 0 in this field indicates that it applies to the whole file; - * otherwise, the entry applies only to the indicated stream number. - * Valid values are between 1 and 127. - * - * o name -- Specifies the name that identifies the attribute being - * described. - * - * o data -- Specifies the actual metadata being stored. - * - * @return Array - */ - public function getDescriptionRecords() - { - return $this->_descriptionRecords; - } - - /** - * Sets an array of description records. Each record must consist of the - * following keys. - * - * o languageIndex -- Specifies the index into the Language List - * Object that identifies the language of this attribute. If there - * is no Language List Object present, this field is zero. - * - * o streamNumber -- Specifies whether the entry applies to a specific - * digital media stream or whether it applies to the whole file. A value - * of 0 in this field indicates that it applies to the whole file; - * otherwise, the entry applies only to the indicated stream number. - * Valid values are between 1 and 127. - * - * o name -- Specifies the name that identifies the attribute being - * described. - * - * o data -- Specifies the actual metadata being stored. - * - * @return Array - */ - public function setDescriptionRecords($descriptionRecords) - { - $this->_descriptionRecords = $descriptionRecords; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $descriptionRecordsCount = count($this->_descriptionRecords); - $descriptionRecordsWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $descriptionRecordsCount; $i++) { - $descriptionRecordsWriter - ->writeUInt16LE - ($this->_descriptionRecords[$i]['languageIndex']) - ->writeUInt16LE - ($this->_descriptionRecords[$i]['streamNumber']) - ->writeUInt16LE(strlen($name = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_descriptionRecords[$i]['name']) . "\0\0")); - if (is_string($this->_descriptionRecords[$i]['data'])) { - $chunks = array(); - if (preg_match - ("/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{1" . - "2}$/i", $this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(6) - ->writeUInt32LE(16) - ->write($name) - ->writeGuid($this->_descriptionRecords[$i]['data']); - } else { - /* There is no way to distinguish byte arrays from unicode - * strings and hence the need for a list of fields of type - * byte array */ - static $byteArray = array ( - "W\0M\0/\0L\0y\0r\0i\0c\0s\0_\0S\0y\0n\0c\0h\0r\0o\0n\0i\0s\0e\0d\0\0\0", - "W\0M\0/\0P\0i\0c\0t\0u\0r\0e\0\0\0" - ); // TODO: Add to the list if you encounter one - - if (in_array($name, $byteArray)) { - $descriptionRecordsWriter - ->writeUInt16LE(1) - ->writeUInt32LE - (strlen($this->_descriptionRecords[$i]['data'])) - ->write($name) - ->write($this->_descriptionRecords[$i]['data']); - } else { - $value = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_descriptionRecords[$i]['data']); - $value = ($value ? $value . "\0\0" : ''); - $descriptionRecordsWriter - ->writeUInt16LE(0) - ->writeUInt32LE(strlen($value)) - ->write($name) - ->writeString16($value); - } - } - } else if (is_bool($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(2) - ->writeUInt32LE(2) - ->write($name) - ->writeUInt16LE - ($this->_descriptionRecords[$i]['data'] ? 1 : 0); - } else if (is_int($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(3) - ->writeUInt32LE(4) - ->write($name) - ->writeUInt32LE($this->_descriptionRecords[$i]['data']); - } else if (is_float($this->_descriptionRecords[$i]['data'])) { - $descriptionRecordsWriter - ->writeUInt16LE(4) - ->writeUInt32LE(8) - ->write($name) - ->writeInt64LE($this->_descriptionRecords[$i]['data']); - } else { - // Invalid value and there is nothing to be done - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Invalid data type'); - } - } - - $this->setSize - (24 /* for header */ + 2 + $descriptionRecordsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($descriptionRecordsCount) - ->write($descriptionRecordsWriter->toString()); - } -} +Metadata Library Object lets authors store stream-based, + * language-attributed, multiply defined, and large metadata attributes in a + * file. + * + * This object supports the same types of metadata as the + * {@link Zend_Media_Asf_Object_Metadata Metadata Object}, as well as + * attributes with language IDs, attributes that are defined more than once, + * large attributes, and attributes with the GUID data type. + * + * @todo Implement better handling of various types of attributes + * according to http://msdn.microsoft.com/en-us/library/aa384495(VS.85).aspx + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: MetadataLibrary.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_MetadataLibrary extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_descriptionRecords = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $descriptionRecordsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $descriptionRecordsCount; $i++) { + $descriptionRecord = array + ('languageIndex' => $this->_reader->readUInt16LE(), + 'streamNumber' => $this->_reader->readUInt16LE()); + $nameLength = $this->_reader->readUInt16LE(); + $dataType = $this->_reader->readUInt16LE(); + $dataLength = $this->_reader->readUInt32LE(); + $descriptionRecord['name'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($nameLength)); + switch ($dataType) { + case 0: // Unicode string + $descriptionRecord['data'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($dataLength)); + break; + case 1: // BYTE array + $descriptionRecord['data'] = + $this->_reader->read($dataLength); + break; + case 2: // BOOL + $descriptionRecord['data'] = + $this->_reader->readUInt16LE() == 1; + break; + case 3: // DWORD + $descriptionRecord['data'] = $this->_reader->readUInt32LE(); + break; + case 4: // QWORD + $descriptionRecord['data'] = $this->_reader->readInt64LE(); + break; + case 5: // WORD + $descriptionRecord['data'] = $this->_reader->readUInt16LE(); + break; + case 6: // GUID + $descriptionRecord['data'] = $this->_reader->readGuid(); + break; + default: + break; + } + $this->_descriptionRecords[] = $descriptionRecord; + } + } + + /** + * Returns an array of description records. Each record consists of the + * following keys. + * + * o languageIndex -- Specifies the index into the + * {@link LanguageList Language List Object} that identifies the + * language of this attribute. If there is no Language List + * Object present, this field is zero. + * + * o streamNumber -- Specifies whether the entry applies to a specific + * digital media stream or whether it applies to the whole file. A value + * of 0 in this field indicates that it applies to the whole file; + * otherwise, the entry applies only to the indicated stream number. + * Valid values are between 1 and 127. + * + * o name -- Specifies the name that identifies the attribute being + * described. + * + * o data -- Specifies the actual metadata being stored. + * + * @return Array + */ + public function getDescriptionRecords() + { + return $this->_descriptionRecords; + } + + /** + * Sets an array of description records. Each record must consist of the + * following keys. + * + * o languageIndex -- Specifies the index into the Language List + * Object that identifies the language of this attribute. If there + * is no Language List Object present, this field is zero. + * + * o streamNumber -- Specifies whether the entry applies to a specific + * digital media stream or whether it applies to the whole file. A value + * of 0 in this field indicates that it applies to the whole file; + * otherwise, the entry applies only to the indicated stream number. + * Valid values are between 1 and 127. + * + * o name -- Specifies the name that identifies the attribute being + * described. + * + * o data -- Specifies the actual metadata being stored. + * + * @return Array + */ + public function setDescriptionRecords($descriptionRecords) + { + $this->_descriptionRecords = $descriptionRecords; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $descriptionRecordsCount = count($this->_descriptionRecords); + $descriptionRecordsWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $descriptionRecordsCount; $i++) { + $descriptionRecordsWriter + ->writeUInt16LE + ($this->_descriptionRecords[$i]['languageIndex']) + ->writeUInt16LE + ($this->_descriptionRecords[$i]['streamNumber']) + ->writeUInt16LE(strlen($name = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_descriptionRecords[$i]['name']) . "\0\0")); + if (is_string($this->_descriptionRecords[$i]['data'])) { + $chunks = array(); + if (preg_match + ("/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{1" . + "2}$/i", $this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(6) + ->writeUInt32LE(16) + ->write($name) + ->writeGuid($this->_descriptionRecords[$i]['data']); + } else { + /* There is no way to distinguish byte arrays from unicode + * strings and hence the need for a list of fields of type + * byte array */ + static $byteArray = array ( + "W\0M\0/\0L\0y\0r\0i\0c\0s\0_\0S\0y\0n\0c\0h\0r\0o\0n\0i\0s\0e\0d\0\0\0", + "W\0M\0/\0P\0i\0c\0t\0u\0r\0e\0\0\0" + ); // TODO: Add to the list if you encounter one + + if (in_array($name, $byteArray)) { + $descriptionRecordsWriter + ->writeUInt16LE(1) + ->writeUInt32LE + (strlen($this->_descriptionRecords[$i]['data'])) + ->write($name) + ->write($this->_descriptionRecords[$i]['data']); + } else { + $value = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_descriptionRecords[$i]['data']); + $value = ($value ? $value . "\0\0" : ''); + $descriptionRecordsWriter + ->writeUInt16LE(0) + ->writeUInt32LE(strlen($value)) + ->write($name) + ->writeString16($value); + } + } + } else if (is_bool($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(2) + ->writeUInt32LE(2) + ->write($name) + ->writeUInt16LE + ($this->_descriptionRecords[$i]['data'] ? 1 : 0); + } else if (is_int($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(3) + ->writeUInt32LE(4) + ->write($name) + ->writeUInt32LE($this->_descriptionRecords[$i]['data']); + } else if (is_float($this->_descriptionRecords[$i]['data'])) { + $descriptionRecordsWriter + ->writeUInt16LE(4) + ->writeUInt32LE(8) + ->write($name) + ->writeInt64LE($this->_descriptionRecords[$i]['data']); + } else { + // Invalid value and there is nothing to be done + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Invalid data type'); + } + } + + $this->setSize + (24 /* for header */ + 2 + $descriptionRecordsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($descriptionRecordsCount) + ->write($descriptionRecordsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Padding.php b/app/libs/vendor/Zend/Media/Asf/Object/Padding.php index bbc0807f..e60fc660 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Padding.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Padding.php @@ -1,77 +1,77 @@ -Padding Object is a dummy object that is used to pad the size of - * the Header Object. This object enables the size of any object stored - * in the Header Object to grow or shrink without having to rewrite the - * entire Data Object and Index Object sections of the ASF file. - * For instance, if entries in the Content Description Object or - * Extended Content Description Object need to be removed or shortened, - * the size of the Padding Object can be increased to compensate for the - * reduction in size of the Content Description Object. The ASF file can - * then be updated by overwriting the previous Header Object with the - * edited Header Object of identical size, without having to move or - * rewrite the data contained in the Data Object. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Padding.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Padding extends Zend_Media_Asf_Object -{ - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - if ($this->getSize() == 0) { - $this->setSize(24); - } - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->write(str_pad('', $this->getSize() - 24 /* header */, "\0")); - } -} +Padding Object is a dummy object that is used to pad the size of + * the Header Object. This object enables the size of any object stored + * in the Header Object to grow or shrink without having to rewrite the + * entire Data Object and Index Object sections of the ASF file. + * For instance, if entries in the Content Description Object or + * Extended Content Description Object need to be removed or shortened, + * the size of the Padding Object can be increased to compensate for the + * reduction in size of the Content Description Object. The ASF file can + * then be updated by overwriting the previous Header Object with the + * edited Header Object of identical size, without having to move or + * rewrite the data contained in the Data Object. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Padding.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Padding extends Zend_Media_Asf_Object +{ + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + if ($this->getSize() == 0) { + $this->setSize(24); + } + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->write(str_pad('', $this->getSize() - 24 /* header */, "\0")); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/ScriptCommand.php b/app/libs/vendor/Zend/Media/Asf/Object/ScriptCommand.php index db1a9f59..36bba811 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/ScriptCommand.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/ScriptCommand.php @@ -1,183 +1,183 @@ -Script Command Object provides a list of type/parameter pairs of - * strings that are synchronized to the ASF file's timeline. Types can include - * URL or FILENAME values. Other type values may also be freely defined and - * used. The semantics and treatment of this set of types are defined by the - * local implementations. The parameter value is specific to the type field. You - * can use this type/parameter pairing for many purposes, including sending URLs - * to be launched by a client into an HTML frame (in other words, the URL type) - * or launching another ASF file for the chained continuous play of audio or - * video presentations (in other words, the FILENAME type). This object is also - * used as a method to stream text, as well as to provide script commands that - * you can use to control elements within the client environment. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ScriptCommand.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_ScriptCommand extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_reserved; - - /** @var Array */ - private $_commands = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_reserved = $this->_reader->readGuid(); - $commandsCount = $this->_reader->readUInt16LE(); - $commandTypesCount = $this->_reader->readUInt16LE(); - $commandTypes = array(); - for ($i = 0; $i < $commandTypesCount; $i++) { - $commandTypeNameLength = $this->_reader->readUInt16LE(); - $commandTypes[] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($commandTypeNameLength * 2)); - } - for ($i = 0; $i < $commandsCount; $i++) { - $command = array - ('presentationTime' => $this->_reader->readUInt32LE(), - 'type' => $commandTypes[$this->_reader->readUInt16LE()]); - $commandNameLength = $this->_reader->readUInt16LE(); - $command['name'] = iconv - ('utf-16le', $this->getOption('encoding'), - $this->_reader->readString16($commandNameLength * 2)); - $this->_commands[] = $command; - } - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o presentationTime -- Specifies the presentation time of the command, - * in milliseconds. - * - * o type -- Specifies the type of this command. - * - * o name -- Specifies the name of this command. - * - * @return Array - */ - public function getCommands() - { - return $this->_commands; - } - - /** - * Sets the array of index entries. Each entry is to consist of the - * following keys. - * - * o presentationTime -- Specifies the presentation time of the command, - * in milliseconds. - * - * o type -- Specifies the type of this command. - * - * o name -- Specifies the name of this command. - * - * @param Array $commands The array of index entries. - */ - public function setCommands($commands) - { - $this->_commands = $commands; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - - $commandTypes = array(); - foreach ($this->_commands as $command) { - if (!in_array($command['type'], $commandTypes)) { - $commandTypes[] = $command['type']; - } - } - - $commandTypesCount = count($commandTypes); - $commandTypesWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $commandTypesCount; $i++) { - $commandTypesWriter - ->writeUInt16LE - (strlen($commandType = iconv - ($this->getOption('encoding'), 'utf-16le', - $commandTypes[$i])) / 2) - ->write($commandType); - } - - $commandsCount = count($this->_commands); - $commandsWriter = new Zend_Io_StringWriter(); - for ($i = 0; $i < $commandsCount; $i++) { - $commandsWriter - ->writeUInt32LE($this->_commands[$i]['presentationTime']) - ->writeUInt16LE - (array_search($this->_commands[$i]['type'], $commandTypes)) - ->writeUInt16LE - (strlen($command = iconv - ($this->getOption('encoding'), 'utf-16le', - $this->_commands[$i]['name'])) / 2) - ->write($command); - } - - $this->setSize - (24 /* for header */ + 20 + $commandTypesWriter->getSize() + - $commandsWriter->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_reserved) - ->writeUInt16LE($commandsCount) - ->writeUInt16LE($commandTypesCount) - ->write($commandTypesWriter->toString()) - ->write($commandsWriter->toString()); - } -} +Script Command Object provides a list of type/parameter pairs of + * strings that are synchronized to the ASF file's timeline. Types can include + * URL or FILENAME values. Other type values may also be freely defined and + * used. The semantics and treatment of this set of types are defined by the + * local implementations. The parameter value is specific to the type field. You + * can use this type/parameter pairing for many purposes, including sending URLs + * to be launched by a client into an HTML frame (in other words, the URL type) + * or launching another ASF file for the chained continuous play of audio or + * video presentations (in other words, the FILENAME type). This object is also + * used as a method to stream text, as well as to provide script commands that + * you can use to control elements within the client environment. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ScriptCommand.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_ScriptCommand extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_reserved; + + /** @var Array */ + private $_commands = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_reserved = $this->_reader->readGuid(); + $commandsCount = $this->_reader->readUInt16LE(); + $commandTypesCount = $this->_reader->readUInt16LE(); + $commandTypes = array(); + for ($i = 0; $i < $commandTypesCount; $i++) { + $commandTypeNameLength = $this->_reader->readUInt16LE(); + $commandTypes[] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($commandTypeNameLength * 2)); + } + for ($i = 0; $i < $commandsCount; $i++) { + $command = array + ('presentationTime' => $this->_reader->readUInt32LE(), + 'type' => $commandTypes[$this->_reader->readUInt16LE()]); + $commandNameLength = $this->_reader->readUInt16LE(); + $command['name'] = iconv + ('utf-16le', $this->getOption('encoding'), + $this->_reader->readString16($commandNameLength * 2)); + $this->_commands[] = $command; + } + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o presentationTime -- Specifies the presentation time of the command, + * in milliseconds. + * + * o type -- Specifies the type of this command. + * + * o name -- Specifies the name of this command. + * + * @return Array + */ + public function getCommands() + { + return $this->_commands; + } + + /** + * Sets the array of index entries. Each entry is to consist of the + * following keys. + * + * o presentationTime -- Specifies the presentation time of the command, + * in milliseconds. + * + * o type -- Specifies the type of this command. + * + * o name -- Specifies the name of this command. + * + * @param Array $commands The array of index entries. + */ + public function setCommands($commands) + { + $this->_commands = $commands; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + + $commandTypes = array(); + foreach ($this->_commands as $command) { + if (!in_array($command['type'], $commandTypes)) { + $commandTypes[] = $command['type']; + } + } + + $commandTypesCount = count($commandTypes); + $commandTypesWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $commandTypesCount; $i++) { + $commandTypesWriter + ->writeUInt16LE + (strlen($commandType = iconv + ($this->getOption('encoding'), 'utf-16le', + $commandTypes[$i])) / 2) + ->write($commandType); + } + + $commandsCount = count($this->_commands); + $commandsWriter = new Zend_Io_StringWriter(); + for ($i = 0; $i < $commandsCount; $i++) { + $commandsWriter + ->writeUInt32LE($this->_commands[$i]['presentationTime']) + ->writeUInt16LE + (array_search($this->_commands[$i]['type'], $commandTypes)) + ->writeUInt16LE + (strlen($command = iconv + ($this->getOption('encoding'), 'utf-16le', + $this->_commands[$i]['name'])) / 2) + ->write($command); + } + + $this->setSize + (24 /* for header */ + 20 + $commandTypesWriter->getSize() + + $commandsWriter->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_reserved) + ->writeUInt16LE($commandsCount) + ->writeUInt16LE($commandTypesCount) + ->write($commandTypesWriter->toString()) + ->write($commandsWriter->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/SimpleIndex.php b/app/libs/vendor/Zend/Media/Asf/Object/SimpleIndex.php index 21d11229..48fc6506 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/SimpleIndex.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/SimpleIndex.php @@ -1,150 +1,150 @@ -Simple Index Object. Additionally, the instances of the Simple - * Index Object shall be ordered by stream number. - * - * Index entries in the Simple Index Object are in terms of - * Presentation Times. The corresponding Packet Number field - * values (of the Index Entry, see below) indicate the packet number of - * the ASF Data Packet with the closest past key frame. Note that for - * video streams that contain both key frames and non-key frames, the Packet - * Number field will always point to the closest past key frame. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: SimpleIndex.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_SimpleIndex extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_fileId; - - /** @var integer */ - private $_indexEntryTimeInterval; - - /** @var integer */ - private $_maximumPacketCount; - - /** @var Array */ - private $_indexEntries = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_fileId = $this->_reader->readGuid(); - $this->_indexEntryTimeInterval = $this->_reader->readInt64LE(); - $this->_maximumPacketCount = $this->_reader->readUInt32LE(); - $indexEntriesCount = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $indexEntriesCount; $i++) { - $this->_indexEntries[] = array - ('packetNumber' => $this->_reader->readUInt32LE(), - 'packetCount' => $this->_reader->readUInt16LE()); - } - } - - /** - * Returns the unique identifier for this ASF file. The value of this field - * should be changed every time the file is modified in any way. The value - * of this field may be set to 0 or set to be identical to the value of the - * File ID field of the Data Object and the Header - * Object. - * - * @return string - */ - public function getFileId() - { - return $this->_fileId; - } - - /** - * Returns the time interval between each index entry in 100-nanosecond units. - * The most common value is 10000000, to indicate that the index entries are - * in 1-second intervals, though other values can be used as well. - * - * @return integer - */ - public function getIndexEntryTimeInterval() - { - return $this->_indexEntryTimeInterval; - } - - /** - * Returns the maximum Packet Count value of all Index Entries. - * - * @return integer - */ - public function getMaximumPacketCount() - { - return $this->_maximumPacketCount; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o packetNumber -- Specifies the number of the Data Packet associated - * with this index entry. Note that for video streams that contain both - * key frames and non-key frames, this field will always point to the - * closest key frame prior to the time interval. - * - * o packetCount -- Specifies the number of Data Packets to send at - * this index entry. If a video key frame has been fragmented into two - * Data Packets, the value of this field will be equal to 2. - * - * @return Array - */ - public function getIndexEntries() - { - return $this->_indexEntries; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Simple Index Object. Additionally, the instances of the Simple + * Index Object shall be ordered by stream number. + * + * Index entries in the Simple Index Object are in terms of + * Presentation Times. The corresponding Packet Number field + * values (of the Index Entry, see below) indicate the packet number of + * the ASF Data Packet with the closest past key frame. Note that for + * video streams that contain both key frames and non-key frames, the Packet + * Number field will always point to the closest past key frame. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: SimpleIndex.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_SimpleIndex extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_fileId; + + /** @var integer */ + private $_indexEntryTimeInterval; + + /** @var integer */ + private $_maximumPacketCount; + + /** @var Array */ + private $_indexEntries = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_fileId = $this->_reader->readGuid(); + $this->_indexEntryTimeInterval = $this->_reader->readInt64LE(); + $this->_maximumPacketCount = $this->_reader->readUInt32LE(); + $indexEntriesCount = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $indexEntriesCount; $i++) { + $this->_indexEntries[] = array + ('packetNumber' => $this->_reader->readUInt32LE(), + 'packetCount' => $this->_reader->readUInt16LE()); + } + } + + /** + * Returns the unique identifier for this ASF file. The value of this field + * should be changed every time the file is modified in any way. The value + * of this field may be set to 0 or set to be identical to the value of the + * File ID field of the Data Object and the Header + * Object. + * + * @return string + */ + public function getFileId() + { + return $this->_fileId; + } + + /** + * Returns the time interval between each index entry in 100-nanosecond units. + * The most common value is 10000000, to indicate that the index entries are + * in 1-second intervals, though other values can be used as well. + * + * @return integer + */ + public function getIndexEntryTimeInterval() + { + return $this->_indexEntryTimeInterval; + } + + /** + * Returns the maximum Packet Count value of all Index Entries. + * + * @return integer + */ + public function getMaximumPacketCount() + { + return $this->_maximumPacketCount; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o packetNumber -- Specifies the number of the Data Packet associated + * with this index entry. Note that for video streams that contain both + * key frames and non-key frames, this field will always point to the + * closest key frame prior to the time interval. + * + * o packetCount -- Specifies the number of Data Packets to send at + * this index entry. If a video key frame has been fragmented into two + * Data Packets, the value of this field will be equal to 2. + * + * @return Array + */ + public function getIndexEntries() + { + return $this->_indexEntries; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/StreamBitrateProperties.php b/app/libs/vendor/Zend/Media/Asf/Object/StreamBitrateProperties.php index 440e5657..11ce2ce5 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/StreamBitrateProperties.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/StreamBitrateProperties.php @@ -1,134 +1,134 @@ -Stream Bitrate Properties Object defines the average bit rate of - * each digital media stream. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StreamBitrateProperties.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_StreamBitrateProperties - extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_bitrateRecords = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $bitrateRecordsCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $bitrateRecordsCount; $i++) { - $this->_bitrateRecords[] = array - ('streamNumber' => - ($tmp = $this->_reader->readInt16LE()) & 0x1f, - 'flags' => $tmp >> 5, - 'averageBitrate' => $this->_reader->readUInt32LE()); - } - } - - /** - * Returns an array of bitrate records. Each record consists of the - * following keys. - * - * o streamNumber -- Specifies the number of this stream described by this - * record. 0 is an invalid stream. Valid values are between 1 and 127. - * - * o flags -- These bits are reserved and should be set to 0. - * - * o averageBitrate -- Specifies the average bit rate of the stream in - * bits per second. This value should include an estimate of ASF packet - * and payload overhead associated with this stream. - * - * @return Array - */ - public function getBitrateRecords() - { - return $this->_bitrateRecords; - } - - /** - * Sets an array of bitrate records. Each record consists of the following - * keys. - * - * o streamNumber -- Specifies the number of this stream described by this - * record. 0 is an invalid stream. Valid values are between 1 and 127. - * - * o flags -- These bits are reserved and should be set to 0. - * - * o averageBitrate -- Specifies the average bit rate of the stream in bits - * per second. This value should include an estimate of ASF packet and - * payload overhead associated with this stream. - * - * @param Array $bitrateRecords The array of bitrate records. - */ - public function setBitrateRecords($bitrateRecords) - { - $this->_bitrateRecords = $bitrateRecords; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $bitrateRecordsCount = count($this->_bitrateRecords); - - $this->setSize - (24 /* for header */ + 2 + $bitrateRecordsCount * 6); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($bitrateRecordsCount); - for ($i = 0; $i < $bitrateRecordsCount; $i++) { - $writer->writeUInt16LE - (($this->_bitrateRecords[$i]['flags'] << 5) | - ($this->_bitrateRecords[$i]['streamNumber'] & 0x1f)) - ->writeUInt32LE - ($this->_bitrateRecords[$i]['averageBitrate']); - } - } -} +Stream Bitrate Properties Object defines the average bit rate of + * each digital media stream. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StreamBitrateProperties.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_StreamBitrateProperties + extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_bitrateRecords = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $bitrateRecordsCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $bitrateRecordsCount; $i++) { + $this->_bitrateRecords[] = array + ('streamNumber' => + ($tmp = $this->_reader->readInt16LE()) & 0x1f, + 'flags' => $tmp >> 5, + 'averageBitrate' => $this->_reader->readUInt32LE()); + } + } + + /** + * Returns an array of bitrate records. Each record consists of the + * following keys. + * + * o streamNumber -- Specifies the number of this stream described by this + * record. 0 is an invalid stream. Valid values are between 1 and 127. + * + * o flags -- These bits are reserved and should be set to 0. + * + * o averageBitrate -- Specifies the average bit rate of the stream in + * bits per second. This value should include an estimate of ASF packet + * and payload overhead associated with this stream. + * + * @return Array + */ + public function getBitrateRecords() + { + return $this->_bitrateRecords; + } + + /** + * Sets an array of bitrate records. Each record consists of the following + * keys. + * + * o streamNumber -- Specifies the number of this stream described by this + * record. 0 is an invalid stream. Valid values are between 1 and 127. + * + * o flags -- These bits are reserved and should be set to 0. + * + * o averageBitrate -- Specifies the average bit rate of the stream in bits + * per second. This value should include an estimate of ASF packet and + * payload overhead associated with this stream. + * + * @param Array $bitrateRecords The array of bitrate records. + */ + public function setBitrateRecords($bitrateRecords) + { + $this->_bitrateRecords = $bitrateRecords; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $bitrateRecordsCount = count($this->_bitrateRecords); + + $this->setSize + (24 /* for header */ + 2 + $bitrateRecordsCount * 6); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($bitrateRecordsCount); + for ($i = 0; $i < $bitrateRecordsCount; $i++) { + $writer->writeUInt16LE + (($this->_bitrateRecords[$i]['flags'] << 5) | + ($this->_bitrateRecords[$i]['streamNumber'] & 0x1f)) + ->writeUInt32LE + ($this->_bitrateRecords[$i]['averageBitrate']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/StreamPrioritization.php b/app/libs/vendor/Zend/Media/Asf/Object/StreamPrioritization.php index ed7053f2..e6f35ca0 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/StreamPrioritization.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/StreamPrioritization.php @@ -1,132 +1,132 @@ -Stream Prioritization Object indicates the author's intentions as - * to which streams should or should not be dropped in response to varying - * network congestion situations. There may be special cases where this - * preferential order may be ignored (for example, the user hits the 'mute' - * button). Generally it is expected that implementations will try to honor the - * author's preference. - * - * The priority of each stream is indicated by how early in the list that - * stream's stream number is listed (in other words, the list is ordered in - * terms of decreasing priority). - * - * The Mandatory flag field shall be set if the author wants that stream kept - * 'regardless'. If this flag is not set, then that indicates that the stream - * should be dropped in response to network congestion situations. Non-mandatory - * streams must never be assigned a higher priority than mandatory streams. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StreamPrioritization.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_StreamPrioritization - extends Zend_Media_Asf_Object -{ - /** @var Array */ - private $_priorityRecords = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $priorityRecordCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $priorityRecordCount; $i++) { - $this->_priorityRecords[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'flags' => $this->_reader->readUInt16LE()); - } - } - - /** - * Returns an array of records. Each record consists of the following keys. - * - * o streamNumber -- Specifies the stream number. Valid values are between - * 1 and 127. - * - * o flags -- Specifies the flags. The mandatory flag is the bit 1 (LSB). - * - * @return Array - */ - public function getPriorityRecords() - { - return $this->_priorityRecords; - } - - /** - * Sets the array of records. Each record consists of the following keys. - * - * o streamNumber -- Specifies the stream number. Valid values are between - * 1 and 127. - * - * o flags -- Specifies the flags. The mandatory flag is the bit 1 (LSB). - * - * @param Array $priorityRecords The array of records. - */ - public function setPriorityRecords($priorityRecords) - { - $this->_priorityRecords = $priorityRecords; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $priorityRecordCount = count($this->_priorityRecords); - - $this->setSize - (24 /* for header */ + 2 + $priorityRecordCount * 4); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeUInt16LE($priorityRecordCount); - for ($i = 0; $i < $priorityRecordCount; $i++) { - $writer->writeUInt16LE($this->_priorityRecords[$i]['streamNumber']) - ->writeUInt16LE($this->_priorityRecords[$i]['flags']); - } - } -} +Stream Prioritization Object indicates the author's intentions as + * to which streams should or should not be dropped in response to varying + * network congestion situations. There may be special cases where this + * preferential order may be ignored (for example, the user hits the 'mute' + * button). Generally it is expected that implementations will try to honor the + * author's preference. + * + * The priority of each stream is indicated by how early in the list that + * stream's stream number is listed (in other words, the list is ordered in + * terms of decreasing priority). + * + * The Mandatory flag field shall be set if the author wants that stream kept + * 'regardless'. If this flag is not set, then that indicates that the stream + * should be dropped in response to network congestion situations. Non-mandatory + * streams must never be assigned a higher priority than mandatory streams. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StreamPrioritization.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_StreamPrioritization + extends Zend_Media_Asf_Object +{ + /** @var Array */ + private $_priorityRecords = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $priorityRecordCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $priorityRecordCount; $i++) { + $this->_priorityRecords[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'flags' => $this->_reader->readUInt16LE()); + } + } + + /** + * Returns an array of records. Each record consists of the following keys. + * + * o streamNumber -- Specifies the stream number. Valid values are between + * 1 and 127. + * + * o flags -- Specifies the flags. The mandatory flag is the bit 1 (LSB). + * + * @return Array + */ + public function getPriorityRecords() + { + return $this->_priorityRecords; + } + + /** + * Sets the array of records. Each record consists of the following keys. + * + * o streamNumber -- Specifies the stream number. Valid values are between + * 1 and 127. + * + * o flags -- Specifies the flags. The mandatory flag is the bit 1 (LSB). + * + * @param Array $priorityRecords The array of records. + */ + public function setPriorityRecords($priorityRecords) + { + $this->_priorityRecords = $priorityRecords; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $priorityRecordCount = count($this->_priorityRecords); + + $this->setSize + (24 /* for header */ + 2 + $priorityRecordCount * 4); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeUInt16LE($priorityRecordCount); + for ($i = 0; $i < $priorityRecordCount; $i++) { + $writer->writeUInt16LE($this->_priorityRecords[$i]['streamNumber']) + ->writeUInt16LE($this->_priorityRecords[$i]['flags']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/StreamProperties.php b/app/libs/vendor/Zend/Media/Asf/Object/StreamProperties.php index 508dc797..54f0bbef 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/StreamProperties.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/StreamProperties.php @@ -1,534 +1,534 @@ -Stream Properties Object defines the specific properties and - * characteristics of a digital media stream. This object defines how a digital - * media stream within the Data Object is interpreted, as well as the - * specific format (of elements) of the Data Packet itself. - * - * Whereas every stream in an ASF presentation, including each stream in a - * mutual exclusion relationship, must be represented by a Stream Properties - * Object, in certain cases, this object might be found embedded in the - * Extended Stream Properties Object. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StreamProperties.php 254 2011-07-07 09:14:41Z svollbehr $ - */ -final class Zend_Media_Asf_Object_StreamProperties extends Zend_Media_Asf_Object -{ - /** - * Indicates, if set, that the data contained in this stream is encrypted - * and will be unreadable unless there is a way to decrypt the stream. - */ - const ENCRYPTED_CONTENT = 0x8000; - - const AUDIO_MEDIA = 'f8699e40-5b4d-11cf-a8fd-00805f5c442b'; - const VIDEO_MEDIA = 'bc19efc0-5b4d-11cf-a8fd-00805f5c442b'; - const COMMAND_MEDIA = '59dacfc0-59e6-11d0-a3ac-00a0c90348f6'; - const JFIF_MEDIA = 'b61be100-5b4e-11cf-a8fD-00805f5c442b'; - const DEGRADABLE_JPEG_MEDIA = '35907dE0-e415-11cf-a917-00805f5c442b'; - const FILE_TRANSFER_MEDIA = '91bd222c-f21c-497a-8b6d-5aa86bfc0185'; - const BINARY_MEDIA = '3afb65e2-47ef-40f2-ac2c-70a90d71d343'; - - const NO_ERROR_CORRECTION = '20fb5700-5b55-11cf-a8fd-00805f5c442b'; - const AUDIO_SPREAD = 'bfc3cd50-618f-11cf-8bb2-00aa00b4e220'; - - /** @var string */ - private $_streamType; - - /** @var string */ - private $_errorCorrectionType; - - /** @var integer */ - private $_timeOffset; - - /** @var integer */ - private $_flags; - - /** @var integer */ - private $_reserved; - - /** @var Array */ - private $_typeSpecificData = array(); - - /** @var Array */ - private $_errorCorrectionData = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_streamType = $this->_reader->readGuid(); - $this->_errorCorrectionType = $this->_reader->readGuid(); - $this->_timeOffset = $this->_reader->readInt64LE(); - $typeSpecificDataLength = $this->_reader->readUInt32LE(); - $errorCorrectionDataLength = $this->_reader->readUInt32LE(); - $this->_flags = $this->_reader->readUInt16LE(); - $this->_reserved = $this->_reader->readUInt32LE(); - - switch ($this->_streamType) { - case self::AUDIO_MEDIA: - $this->_typeSpecificData = array - ('codecId' => $this->_reader->readUInt16LE(), - 'numberOfChannels' => $this->_reader->readUInt16LE(), - 'samplesPerSecond' => $this->_reader->readUInt32LE(), - 'avgNumBytesPerSecond' => $this->_reader->readUInt32LE(), - 'blockAlignment' => $this->_reader->readUInt16LE(), - 'bitsPerSample' => $this->_reader->readUInt16LE()); - $codecSpecificDataSize = $this->_reader->readUInt16LE(); - $this->_typeSpecificData['codecSpecificData'] = - $this->_reader->read($codecSpecificDataSize); - break; - case self::VIDEO_MEDIA: - $this->_typeSpecificData = array - ('encodedImageWidth' => $this->_reader->readUInt32LE(), - 'encodedImageHeight' => $this->_reader->readUInt32LE(), - 'reservedFlags' => $this->_reader->readInt8()); - $this->_reader->skip(2); - $formatDataSize = $this->_reader->readUInt32LE(); - $this->_typeSpecificData = array_merge - ($this->_typeSpecificData, array - ('imageWidth' => $this->_reader->readUInt32LE(), - 'imageHeight' => $this->_reader->readUInt32LE(), - 'reserved' => $this->_reader->readUInt16LE(), - 'bitsPerPixelCount' => $this->_reader->readUInt16LE(), - 'compressionId' => $this->_reader->readUInt32LE(), - 'imageSize' => $this->_reader->readUInt32LE(), - 'horizontalPixelsPerMeter' => - $this->_reader->readUInt32LE(), - 'verticalPixelsPerMeter' => - $this->_reader->readUInt32LE(), - 'colorsUsedCount' => $this->_reader->readUInt32LE(), - 'importantColorsCount' => $this->_reader->readUInt32LE(), - 'codecSpecificData' => - $this->_reader->read($formatDataSize - 38))); - break; - case self::JFIF_MEDIA: - $this->_typeSpecificData = array - ('imageWidth' => $this->_reader->readUInt32LE(), - 'imageHeight' => $this->_reader->readUInt32LE(), - 'reserved' => $this->_reader->readUInt32LE()); - break; - case self::DEGRADABLE_JPEG_MEDIA: - $this->_typeSpecificData = array - ('imageWidth' => $this->_reader->readUInt32LE(), - 'imageHeight' => $this->_reader->readUInt32LE(), - $this->_reader->readUInt16LE(), - $this->_reader->readUInt16LE(), - $this->_reader->readUInt16LE()); - $interchangeDataSize = $this->_reader->readUInt16LE(); - if ($interchangeDataSize == 0) { - $interchangeDataSize++; - } - $this->_typeSpecificData['interchangeData'] = - $this->_reader->read($interchangeDataSize); - break; - case self::FILE_TRANSFER_MEDIA: - // break intentionally omitted - case self::BINARY_MEDIA: - $this->_typeSpecificData = array - ('majorMediaType' => $this->_reader->readGUID(), - 'mediaSubtype' => $this->_reader->readGUID(), - 'fixedSizeSamples' => $this->_reader->readUInt32LE(), - 'temporalCompression' => $this->_reader->readUInt32LE(), - 'sampleSize' => $this->_reader->readUInt32LE(), - 'formatType' => $this->_reader->readGUID()); - $formatDataSize = $this->_reader->readUInt32LE(); - $this->_typeSpecificData['formatData'] = - $this->_reader->read($formatDataSize); - break; - case self::COMMAND_MEDIA: - // break intentionally omitted - default: - $this->_reader->skip($typeSpecificDataLength); - break; - } - switch ($this->_errorCorrectionType) { - case self::AUDIO_SPREAD: - $this->_errorCorrectionData = array - ('span' => $this->_reader->readInt8(), - 'virtualPacketLength' => $this->_reader->readUInt16LE(), - 'virtualChunkLength' => $this->_reader->readUInt16LE()); - $silenceDataSize = $this->_reader->readUInt16LE(); - $this->_errorCorrectionData['silenceData'] = - $this->_reader->read($silenceDataSize); - break; - case self::NO_ERROR_CORRECTION: - // break intentionally omitted - default: - $this->_reader->skip($errorCorrectionDataLength); - break; - } - } - - /** - * Returns the number of this stream. 0 is an invalid stream. Valid values - * are between 1 and 127. The numbers assigned to streams in an ASF - * presentation may be any combination of unique values; parsing logic must - * not assume that streams are numbered sequentially. - * - * @return integer - */ - public function getStreamNumber() - { - return $this->_flags & 0x3f; - } - - /** - * Returns the number of this stream. 0 is an invalid stream. Valid values - * are between 1 and 127. The numbers assigned to streams in an ASF - * presentation may be any combination of unique values; parsing logic must - * not assume that streams are numbered sequentially. - * - * @param integer $streamNumber The number of this stream. - */ - public function setStreamNumber($streamNumber) - { - if ($streamNumber < 1 || $streamNumber > 127) { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Invalid argument'); - } - $this->_flags = ($this->_flags & 0xffc0) | ($streamNumber & 0x3f); - } - - /** - * Returns the type of the stream (for example, audio, video, and so on). - * - * @return string - */ - public function getStreamType() - { - return $this->_streamType; - } - - /** - * Sets the type of the stream (for example, audio, video, and so on). - * - * @param integer $streamType The type of the stream. - */ - public function setStreamType($streamType) - { - $this->_streamType = $streamType; - } - - /** - * Returns the error correction type used by this digital media stream. For - * streams other than audio, this value should be set to - * NO_ERROR_CORRECTION. For audio streams, this value should be set to - * AUDIO_SPREAD. - * - * @return string - */ - public function getErrorCorrectionType() - { - return $this->_errorCorrectionType; - } - - /** - * Sets the error correction type used by this digital media stream. For - * streams other than audio, this value should be set to - * NO_ERROR_CORRECTION. For audio streams, this value should be set to - * AUDIO_SPREAD. - * - * @param integer $errorCorrectionType The error correction type used by - * this digital media stream. - */ - public function setErrorCorrectionType($errorCorrectionType) - { - $this->_errorCorrectionType = $errorCorrectionType; - } - - /** - * Returns the presentation time offset of the stream in 100-nanosecond - * units. The value of this field is added to all of the timestamps of the - * samples in the stream. This value shall be equal to the send time of the - * first interleaved packet in the data section. The value of this field is - * typically 0. It is non-zero in the case when an ASF file is edited and it - * is not possible for the editor to change the presentation times and send - * times of ASF packets. Note that if more than one stream is present in an - * ASF file the offset values of all stream properties objects must be - * equal. - * - * @return integer - */ - public function getTimeOffset() - { - return $this->_timeOffset; - } - - /** - * Sets the presentation time offset of the stream in 100-nanosecond units. - * The value of this field is added to all of the timestamps of the samples - * in the stream. This value shall be equal to the send time of the first - * interleaved packet in the data section. The value of this field is - * typically 0. It is non-zero in the case when an ASF file is edited and it - * is not possible for the editor to change the presentation times and send - * times of ASF packets. Note that if more than one stream is present in an - * ASF file the offset values of all stream properties objects must be - * equal. - * - * @param integer $timeOffset The presentation time offset of the stream. - */ - public function setTimeOffset($timeOffset) - { - $this->_timeOffset = $timeOffset; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the flags field. - * - * @return integer - */ - public function getFlags() - { - return $this->_flags; - } - - /** - * Sets the flags field. - * - * @param integer $flags The flags field. - */ - public function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Returns type-specific format data. The structure for the Type-Specific - * Data field is determined by the value stored in the Stream - * Type field. - * - * The type-specific data is returned as key-value pairs of an associate - * array. - * - * @return Array - */ - public function getTypeSpecificData() - { - return $this->_typeSpecificData; - } - - /** - * Sets type-specific format data. The structure for the Type-Specific - * Data field is determined by the value stored in the Stream Type - * field. - * - * @param Array $typeSpecificData The type-specific data as key-value pairs - * of an associate array. - */ - public function setTypeSpecificData($typeSpecificData) - { - $this->_typeSpecificData = $typeSpecificData; - } - - /** - * Returns data specific to the error correction type. The structure for the - * Error Correction Data field is determined by the value stored in - * the Error Correction Type field. For example, an audio data stream - * might need to know how codec chunks were redistributed, or it might need - * a sample of encoded silence. - * - * The error correction type-specific data is returned as key-value pairs of - * an associate array. - * - * @return integer - */ - public function getErrorCorrectionData() - { - return $this->_errorCorrectionData; - } - - /** - * Sets data specific to the error correction type. The structure for the - * Error Correction Data field is determined by the value stored in - * the Error Correction Type field. For example, an audio data stream - * might need to know how codec chunks were redistributed, or it might need - * a sample of encoded silence. - * - * @param Array $errorCorrectionData The error correction type-specific data - * as key-value pairs of an associate array. - */ - public function setErrorCorrectionData($errorCorrectionData) - { - $this->_errorCorrectionData = $errorCorrectionData; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Io/StringWriter.php'; - $typeSpecificData = new Zend_Io_StringWriter(); - switch ($this->_streamType) { - case self::AUDIO_MEDIA: - $typeSpecificData - ->writeUInt16LE($this->_typeSpecificData['codecId']) - ->writeUInt16LE - ($this->_typeSpecificData['numberOfChannels']) - ->writeUInt32LE - ($this->_typeSpecificData['samplesPerSecond']) - ->writeUInt32LE - ($this->_typeSpecificData['avgNumBytesPerSecond']) - ->writeUInt16LE($this->_typeSpecificData['blockAlignment']) - ->writeUInt16LE($this->_typeSpecificData['bitsPerSample']) - ->writeUInt16LE - (strlen($this->_typeSpecificData['codecSpecificData'])) - ->write($this->_typeSpecificData['codecSpecificData']); - break; - case self::VIDEO_MEDIA: - $typeSpecificData - ->writeUInt32LE - ($this->_typeSpecificData['encodedImageWidth']) - ->writeUInt32LE - ($this->_typeSpecificData['encodedImageHeight']) - ->writeInt8($this->_typeSpecificData['reservedFlags']) - ->writeUInt16LE(0) // Reserved - ->writeUInt32LE - (38 + - strlen($this->_typeSpecificData['codecSpecificData'])) - ->writeUInt32LE($this->_typeSpecificData['imageWidth']) - ->writeUInt32LE($this->_typeSpecificData['imageHeight']) - ->writeUInt16LE($this->_typeSpecificData['reserved']) - ->writeUInt16LE - ($this->_typeSpecificData['bitsPerPixelCount']) - ->writeUInt32LE($this->_typeSpecificData['compressionId']) - ->writeUInt32LE($this->_typeSpecificData['imageSize']) - ->writeUInt32LE - ($this->_typeSpecificData['horizontalPixelsPerMeter']) - ->writeUInt32LE - ($this->_typeSpecificData['verticalPixelsPerMeter']) - ->writeUInt32LE($this->_typeSpecificData['colorsUsedCount']) - ->writeUInt32LE - ($this->_typeSpecificData['importantColorsCount']) - ->write($this->_typeSpecificData['codecSpecificData']); - break; - case self::JFIF_MEDIA: - $typeSpecificData - ->writeUInt32LE($this->_typeSpecificData['imageWidth']) - ->writeUInt32LE($this->_typeSpecificData['imageHeight']) - ->writeUInt32LE(0); - break; - case self::DEGRADABLE_JPEG_MEDIA: - $typeSpecificData - ->writeUInt32LE($this->_typeSpecificData['imageWidth']) - ->writeUInt32LE($this->_typeSpecificData['imageHeight']) - ->writeUInt16LE(0) - ->writeUInt16LE(0) - ->writeUInt16LE(0); - $interchangeDataSize = strlen - ($this->_typeSpecificData['interchangeData']); - if ($interchangeDataSize == 1) - $interchangeDataSize = 0; - $typeSpecificData - ->writeUInt16LE($interchangeDataSize) - ->write($this->_typeSpecificData['interchangeData']); - break; - case self::FILE_TRANSFER_MEDIA: - // break intentionally omitted - case self::BINARY_MEDIA: - $typeSpecificData - ->writeGuid($this->_typeSpecificData['majorMediaType']) - ->writeGuid($this->_typeSpecificData['mediaSubtype']) - ->writeUInt32LE($this->_typeSpecificData['fixedSizeSamples']) - ->writeUInt32LE - ($this->_typeSpecificData['temporalCompression']) - ->writeUInt32LE($this->_typeSpecificData['sampleSize']) - ->writeGuid($this->_typeSpecificData['formatType']) - ->writeUInt32LE(strlen($this->_typeSpecificData['formatData'])) - ->write($this->_typeSpecificData['formatData']); - break; - case self::COMMAND_MEDIA: - // break intentionally omitted - default: - break; - } - - $errorCorrectionData = new Zend_Io_StringWriter(); - switch ($this->_errorCorrectionType) { - case self::AUDIO_SPREAD: - $errorCorrectionData - ->writeInt8($this->_errorCorrectionData['span']) - ->writeUInt16LE - ($this->_errorCorrectionData['virtualPacketLength']) - ->writeUInt16LE - ($this->_errorCorrectionData['virtualChunkLength']) - ->writeUInt16LE - (strlen($this->_errorCorrectionData['silenceData'])) - ->write($this->_errorCorrectionData['silenceData']); - break; - case self::NO_ERROR_CORRECTION: - // break intentionally omitted - default: - break; - } - - $this->setSize - (24 /* for header */ + 54 + $typeSpecificData->getSize() + - $errorCorrectionData->getSize()); - - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->writeGuid($this->_streamType) - ->writeGuid($this->_errorCorrectionType) - ->writeInt64LE($this->_timeOffset) - ->writeUInt32LE($typeSpecificData->getSize()) - ->writeUInt32LE($errorCorrectionData->getSize()) - ->writeUInt16LE($this->_flags) - ->writeUInt32LE($this->_reserved) - ->write($typeSpecificData->toString()) - ->write($errorCorrectionData->toString()); - } -} +Stream Properties Object defines the specific properties and + * characteristics of a digital media stream. This object defines how a digital + * media stream within the Data Object is interpreted, as well as the + * specific format (of elements) of the Data Packet itself. + * + * Whereas every stream in an ASF presentation, including each stream in a + * mutual exclusion relationship, must be represented by a Stream Properties + * Object, in certain cases, this object might be found embedded in the + * Extended Stream Properties Object. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StreamProperties.php 254 2011-07-07 09:14:41Z svollbehr $ + */ +final class Zend_Media_Asf_Object_StreamProperties extends Zend_Media_Asf_Object +{ + /** + * Indicates, if set, that the data contained in this stream is encrypted + * and will be unreadable unless there is a way to decrypt the stream. + */ + const ENCRYPTED_CONTENT = 0x8000; + + const AUDIO_MEDIA = 'f8699e40-5b4d-11cf-a8fd-00805f5c442b'; + const VIDEO_MEDIA = 'bc19efc0-5b4d-11cf-a8fd-00805f5c442b'; + const COMMAND_MEDIA = '59dacfc0-59e6-11d0-a3ac-00a0c90348f6'; + const JFIF_MEDIA = 'b61be100-5b4e-11cf-a8fD-00805f5c442b'; + const DEGRADABLE_JPEG_MEDIA = '35907dE0-e415-11cf-a917-00805f5c442b'; + const FILE_TRANSFER_MEDIA = '91bd222c-f21c-497a-8b6d-5aa86bfc0185'; + const BINARY_MEDIA = '3afb65e2-47ef-40f2-ac2c-70a90d71d343'; + + const NO_ERROR_CORRECTION = '20fb5700-5b55-11cf-a8fd-00805f5c442b'; + const AUDIO_SPREAD = 'bfc3cd50-618f-11cf-8bb2-00aa00b4e220'; + + /** @var string */ + private $_streamType; + + /** @var string */ + private $_errorCorrectionType; + + /** @var integer */ + private $_timeOffset; + + /** @var integer */ + private $_flags; + + /** @var integer */ + private $_reserved; + + /** @var Array */ + private $_typeSpecificData = array(); + + /** @var Array */ + private $_errorCorrectionData = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_streamType = $this->_reader->readGuid(); + $this->_errorCorrectionType = $this->_reader->readGuid(); + $this->_timeOffset = $this->_reader->readInt64LE(); + $typeSpecificDataLength = $this->_reader->readUInt32LE(); + $errorCorrectionDataLength = $this->_reader->readUInt32LE(); + $this->_flags = $this->_reader->readUInt16LE(); + $this->_reserved = $this->_reader->readUInt32LE(); + + switch ($this->_streamType) { + case self::AUDIO_MEDIA: + $this->_typeSpecificData = array + ('codecId' => $this->_reader->readUInt16LE(), + 'numberOfChannels' => $this->_reader->readUInt16LE(), + 'samplesPerSecond' => $this->_reader->readUInt32LE(), + 'avgNumBytesPerSecond' => $this->_reader->readUInt32LE(), + 'blockAlignment' => $this->_reader->readUInt16LE(), + 'bitsPerSample' => $this->_reader->readUInt16LE()); + $codecSpecificDataSize = $this->_reader->readUInt16LE(); + $this->_typeSpecificData['codecSpecificData'] = + $this->_reader->read($codecSpecificDataSize); + break; + case self::VIDEO_MEDIA: + $this->_typeSpecificData = array + ('encodedImageWidth' => $this->_reader->readUInt32LE(), + 'encodedImageHeight' => $this->_reader->readUInt32LE(), + 'reservedFlags' => $this->_reader->readInt8()); + $this->_reader->skip(2); + $formatDataSize = $this->_reader->readUInt32LE(); + $this->_typeSpecificData = array_merge + ($this->_typeSpecificData, array + ('imageWidth' => $this->_reader->readUInt32LE(), + 'imageHeight' => $this->_reader->readUInt32LE(), + 'reserved' => $this->_reader->readUInt16LE(), + 'bitsPerPixelCount' => $this->_reader->readUInt16LE(), + 'compressionId' => $this->_reader->readUInt32LE(), + 'imageSize' => $this->_reader->readUInt32LE(), + 'horizontalPixelsPerMeter' => + $this->_reader->readUInt32LE(), + 'verticalPixelsPerMeter' => + $this->_reader->readUInt32LE(), + 'colorsUsedCount' => $this->_reader->readUInt32LE(), + 'importantColorsCount' => $this->_reader->readUInt32LE(), + 'codecSpecificData' => + $this->_reader->read($formatDataSize - 38))); + break; + case self::JFIF_MEDIA: + $this->_typeSpecificData = array + ('imageWidth' => $this->_reader->readUInt32LE(), + 'imageHeight' => $this->_reader->readUInt32LE(), + 'reserved' => $this->_reader->readUInt32LE()); + break; + case self::DEGRADABLE_JPEG_MEDIA: + $this->_typeSpecificData = array + ('imageWidth' => $this->_reader->readUInt32LE(), + 'imageHeight' => $this->_reader->readUInt32LE(), + $this->_reader->readUInt16LE(), + $this->_reader->readUInt16LE(), + $this->_reader->readUInt16LE()); + $interchangeDataSize = $this->_reader->readUInt16LE(); + if ($interchangeDataSize == 0) { + $interchangeDataSize++; + } + $this->_typeSpecificData['interchangeData'] = + $this->_reader->read($interchangeDataSize); + break; + case self::FILE_TRANSFER_MEDIA: + // break intentionally omitted + case self::BINARY_MEDIA: + $this->_typeSpecificData = array + ('majorMediaType' => $this->_reader->readGUID(), + 'mediaSubtype' => $this->_reader->readGUID(), + 'fixedSizeSamples' => $this->_reader->readUInt32LE(), + 'temporalCompression' => $this->_reader->readUInt32LE(), + 'sampleSize' => $this->_reader->readUInt32LE(), + 'formatType' => $this->_reader->readGUID()); + $formatDataSize = $this->_reader->readUInt32LE(); + $this->_typeSpecificData['formatData'] = + $this->_reader->read($formatDataSize); + break; + case self::COMMAND_MEDIA: + // break intentionally omitted + default: + $this->_reader->skip($typeSpecificDataLength); + break; + } + switch ($this->_errorCorrectionType) { + case self::AUDIO_SPREAD: + $this->_errorCorrectionData = array + ('span' => $this->_reader->readInt8(), + 'virtualPacketLength' => $this->_reader->readUInt16LE(), + 'virtualChunkLength' => $this->_reader->readUInt16LE()); + $silenceDataSize = $this->_reader->readUInt16LE(); + $this->_errorCorrectionData['silenceData'] = + $this->_reader->read($silenceDataSize); + break; + case self::NO_ERROR_CORRECTION: + // break intentionally omitted + default: + $this->_reader->skip($errorCorrectionDataLength); + break; + } + } + + /** + * Returns the number of this stream. 0 is an invalid stream. Valid values + * are between 1 and 127. The numbers assigned to streams in an ASF + * presentation may be any combination of unique values; parsing logic must + * not assume that streams are numbered sequentially. + * + * @return integer + */ + public function getStreamNumber() + { + return $this->_flags & 0x3f; + } + + /** + * Returns the number of this stream. 0 is an invalid stream. Valid values + * are between 1 and 127. The numbers assigned to streams in an ASF + * presentation may be any combination of unique values; parsing logic must + * not assume that streams are numbered sequentially. + * + * @param integer $streamNumber The number of this stream. + */ + public function setStreamNumber($streamNumber) + { + if ($streamNumber < 1 || $streamNumber > 127) { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Invalid argument'); + } + $this->_flags = ($this->_flags & 0xffc0) | ($streamNumber & 0x3f); + } + + /** + * Returns the type of the stream (for example, audio, video, and so on). + * + * @return string + */ + public function getStreamType() + { + return $this->_streamType; + } + + /** + * Sets the type of the stream (for example, audio, video, and so on). + * + * @param integer $streamType The type of the stream. + */ + public function setStreamType($streamType) + { + $this->_streamType = $streamType; + } + + /** + * Returns the error correction type used by this digital media stream. For + * streams other than audio, this value should be set to + * NO_ERROR_CORRECTION. For audio streams, this value should be set to + * AUDIO_SPREAD. + * + * @return string + */ + public function getErrorCorrectionType() + { + return $this->_errorCorrectionType; + } + + /** + * Sets the error correction type used by this digital media stream. For + * streams other than audio, this value should be set to + * NO_ERROR_CORRECTION. For audio streams, this value should be set to + * AUDIO_SPREAD. + * + * @param integer $errorCorrectionType The error correction type used by + * this digital media stream. + */ + public function setErrorCorrectionType($errorCorrectionType) + { + $this->_errorCorrectionType = $errorCorrectionType; + } + + /** + * Returns the presentation time offset of the stream in 100-nanosecond + * units. The value of this field is added to all of the timestamps of the + * samples in the stream. This value shall be equal to the send time of the + * first interleaved packet in the data section. The value of this field is + * typically 0. It is non-zero in the case when an ASF file is edited and it + * is not possible for the editor to change the presentation times and send + * times of ASF packets. Note that if more than one stream is present in an + * ASF file the offset values of all stream properties objects must be + * equal. + * + * @return integer + */ + public function getTimeOffset() + { + return $this->_timeOffset; + } + + /** + * Sets the presentation time offset of the stream in 100-nanosecond units. + * The value of this field is added to all of the timestamps of the samples + * in the stream. This value shall be equal to the send time of the first + * interleaved packet in the data section. The value of this field is + * typically 0. It is non-zero in the case when an ASF file is edited and it + * is not possible for the editor to change the presentation times and send + * times of ASF packets. Note that if more than one stream is present in an + * ASF file the offset values of all stream properties objects must be + * equal. + * + * @param integer $timeOffset The presentation time offset of the stream. + */ + public function setTimeOffset($timeOffset) + { + $this->_timeOffset = $timeOffset; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the flags field. + * + * @return integer + */ + public function getFlags() + { + return $this->_flags; + } + + /** + * Sets the flags field. + * + * @param integer $flags The flags field. + */ + public function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Returns type-specific format data. The structure for the Type-Specific + * Data field is determined by the value stored in the Stream + * Type field. + * + * The type-specific data is returned as key-value pairs of an associate + * array. + * + * @return Array + */ + public function getTypeSpecificData() + { + return $this->_typeSpecificData; + } + + /** + * Sets type-specific format data. The structure for the Type-Specific + * Data field is determined by the value stored in the Stream Type + * field. + * + * @param Array $typeSpecificData The type-specific data as key-value pairs + * of an associate array. + */ + public function setTypeSpecificData($typeSpecificData) + { + $this->_typeSpecificData = $typeSpecificData; + } + + /** + * Returns data specific to the error correction type. The structure for the + * Error Correction Data field is determined by the value stored in + * the Error Correction Type field. For example, an audio data stream + * might need to know how codec chunks were redistributed, or it might need + * a sample of encoded silence. + * + * The error correction type-specific data is returned as key-value pairs of + * an associate array. + * + * @return integer + */ + public function getErrorCorrectionData() + { + return $this->_errorCorrectionData; + } + + /** + * Sets data specific to the error correction type. The structure for the + * Error Correction Data field is determined by the value stored in + * the Error Correction Type field. For example, an audio data stream + * might need to know how codec chunks were redistributed, or it might need + * a sample of encoded silence. + * + * @param Array $errorCorrectionData The error correction type-specific data + * as key-value pairs of an associate array. + */ + public function setErrorCorrectionData($errorCorrectionData) + { + $this->_errorCorrectionData = $errorCorrectionData; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Io/StringWriter.php'; + $typeSpecificData = new Zend_Io_StringWriter(); + switch ($this->_streamType) { + case self::AUDIO_MEDIA: + $typeSpecificData + ->writeUInt16LE($this->_typeSpecificData['codecId']) + ->writeUInt16LE + ($this->_typeSpecificData['numberOfChannels']) + ->writeUInt32LE + ($this->_typeSpecificData['samplesPerSecond']) + ->writeUInt32LE + ($this->_typeSpecificData['avgNumBytesPerSecond']) + ->writeUInt16LE($this->_typeSpecificData['blockAlignment']) + ->writeUInt16LE($this->_typeSpecificData['bitsPerSample']) + ->writeUInt16LE + (strlen($this->_typeSpecificData['codecSpecificData'])) + ->write($this->_typeSpecificData['codecSpecificData']); + break; + case self::VIDEO_MEDIA: + $typeSpecificData + ->writeUInt32LE + ($this->_typeSpecificData['encodedImageWidth']) + ->writeUInt32LE + ($this->_typeSpecificData['encodedImageHeight']) + ->writeInt8($this->_typeSpecificData['reservedFlags']) + ->writeUInt16LE(0) // Reserved + ->writeUInt32LE + (38 + + strlen($this->_typeSpecificData['codecSpecificData'])) + ->writeUInt32LE($this->_typeSpecificData['imageWidth']) + ->writeUInt32LE($this->_typeSpecificData['imageHeight']) + ->writeUInt16LE($this->_typeSpecificData['reserved']) + ->writeUInt16LE + ($this->_typeSpecificData['bitsPerPixelCount']) + ->writeUInt32LE($this->_typeSpecificData['compressionId']) + ->writeUInt32LE($this->_typeSpecificData['imageSize']) + ->writeUInt32LE + ($this->_typeSpecificData['horizontalPixelsPerMeter']) + ->writeUInt32LE + ($this->_typeSpecificData['verticalPixelsPerMeter']) + ->writeUInt32LE($this->_typeSpecificData['colorsUsedCount']) + ->writeUInt32LE + ($this->_typeSpecificData['importantColorsCount']) + ->write($this->_typeSpecificData['codecSpecificData']); + break; + case self::JFIF_MEDIA: + $typeSpecificData + ->writeUInt32LE($this->_typeSpecificData['imageWidth']) + ->writeUInt32LE($this->_typeSpecificData['imageHeight']) + ->writeUInt32LE(0); + break; + case self::DEGRADABLE_JPEG_MEDIA: + $typeSpecificData + ->writeUInt32LE($this->_typeSpecificData['imageWidth']) + ->writeUInt32LE($this->_typeSpecificData['imageHeight']) + ->writeUInt16LE(0) + ->writeUInt16LE(0) + ->writeUInt16LE(0); + $interchangeDataSize = strlen + ($this->_typeSpecificData['interchangeData']); + if ($interchangeDataSize == 1) + $interchangeDataSize = 0; + $typeSpecificData + ->writeUInt16LE($interchangeDataSize) + ->write($this->_typeSpecificData['interchangeData']); + break; + case self::FILE_TRANSFER_MEDIA: + // break intentionally omitted + case self::BINARY_MEDIA: + $typeSpecificData + ->writeGuid($this->_typeSpecificData['majorMediaType']) + ->writeGuid($this->_typeSpecificData['mediaSubtype']) + ->writeUInt32LE($this->_typeSpecificData['fixedSizeSamples']) + ->writeUInt32LE + ($this->_typeSpecificData['temporalCompression']) + ->writeUInt32LE($this->_typeSpecificData['sampleSize']) + ->writeGuid($this->_typeSpecificData['formatType']) + ->writeUInt32LE(strlen($this->_typeSpecificData['formatData'])) + ->write($this->_typeSpecificData['formatData']); + break; + case self::COMMAND_MEDIA: + // break intentionally omitted + default: + break; + } + + $errorCorrectionData = new Zend_Io_StringWriter(); + switch ($this->_errorCorrectionType) { + case self::AUDIO_SPREAD: + $errorCorrectionData + ->writeInt8($this->_errorCorrectionData['span']) + ->writeUInt16LE + ($this->_errorCorrectionData['virtualPacketLength']) + ->writeUInt16LE + ($this->_errorCorrectionData['virtualChunkLength']) + ->writeUInt16LE + (strlen($this->_errorCorrectionData['silenceData'])) + ->write($this->_errorCorrectionData['silenceData']); + break; + case self::NO_ERROR_CORRECTION: + // break intentionally omitted + default: + break; + } + + $this->setSize + (24 /* for header */ + 54 + $typeSpecificData->getSize() + + $errorCorrectionData->getSize()); + + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->writeGuid($this->_streamType) + ->writeGuid($this->_errorCorrectionType) + ->writeInt64LE($this->_timeOffset) + ->writeUInt32LE($typeSpecificData->getSize()) + ->writeUInt32LE($errorCorrectionData->getSize()) + ->writeUInt16LE($this->_flags) + ->writeUInt32LE($this->_reserved) + ->write($typeSpecificData->toString()) + ->write($errorCorrectionData->toString()); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndex.php b/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndex.php index 72dff874..96716c1b 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndex.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndex.php @@ -1,189 +1,189 @@ -Timecode Index Object - * is used, it is recommended that timecodes be stored as a Payload Extension - * System on the appropriate stream. It is also recommended that every - * timecode appearing in the ASF file have a corresponging index entry. - * - * The index is designed to be broken into blocks to facilitate storage that is - * more space-efficient by using 32-bit offsets relative to a 64-bit base. That - * is, each index block has a full 64-bit offset in the block header that is - * added to the 32-bit offsets found in each index entry. If a file is larger - * than 2^32 bytes, then multiple index blocks can be used to fully index the - * entire large file while still keeping index entry offsets at 32 bits. - * - * To locate an object with a particular timecode in an ASF file, one would - * typically look through the Timecode Index Object in blocks of the - * appropriate range and try to locate the nearest possible timecode. The - * corresponding Offset field values of the Index Entry are byte - * offsets that, when combined with the Block Position value of the Index - * Block, indicate the starting location in bytes of an ASF Data Packet relative - * to the start of the first ASF Data Packet in the file. - * - * Any ASF file containing a Timecode Index Object shall also contain a - * Timecode Index Parameters Object in its - * {@link Zend_Media_Asf_Object_Header ASF Header}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: TimecodeIndex.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_TimecodeIndex extends Zend_Media_Asf_Object -{ - /** - * Indicates that the index type is Nearest Past Data Packet. The Nearest - * Past Data Packet indexes point to the data packet whose presentation time - * is closest to the index entry time. - */ - const NEAREST_PAST_DATA_PACKET = 1; - - /** - * Indicates that the index type is Nearest Past Media. The Nearest Past - * Object indexes point to the closest data packet containing an entire - * object or first fragment of an object. - */ - const NEAREST_PAST_MEDIA = 2; - - /** - * Indicates that the index type is Nearest Past Cleanpoint. The Nearest - * Past Cleanpoint indexes point to the closest data packet containing an - * entire object (or first fragment of an object) that has the Cleanpoint - * Flag set. - * - * Nearest Past Cleanpoint is the most common type of index. - */ - const NEAREST_PAST_CLEANPOINT = 3; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** @var Array */ - private $_indexBlocks = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_reader->skip(4); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - $indexBlocksCount = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - for ($i = 0; $i < $indexBlocksCount; $i++) { - $indexEntryCount = $this->_reader->readUInt32LE(); - $timecodeRange = $this->_reader->readUInt16LE(); - $blockPositions = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $blockPositions[] = $this->_reader->readInt64LE(); - } - $indexEntries = array(); - for ($i = 0; $i < $indexEntryCount; $i++) { - $timecode = $this->_reader->readUInt32LE(); - $offsets = array(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $offsets[] = $this->_reader->readUInt32LE(); - } - $indexEntries[] = array - ('timecode' => $timecode, - 'offsets' => $offsets); - } - $this->_indexBlocks[] = array - ('timecodeRange' => $timecodeRange, - 'blockPositions' => $blockPositions, - 'indexEntries' => $indexEntries); - } - } - - /** - * Returns an array of index specifiers. Each entry consists of the - * following keys. - * - * o streamNumber -- Specifies the stream number that the Index - * Specifiers refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o timecodeRange -- Specifies the timecode range for this block. - * Subsequent blocks must contain range numbers greater than or equal to - * this one. - * - * o blockPositions -- Specifies a list of byte offsets of the beginnings - * of the blocks relative to the beginning of the first Data Packet (for - * example, the beginning of the Data Object + 50 bytes). - * - * o indexEntries -- An array that consists of the following keys - * o timecode -- This is the 4-byte timecode for these entries. - * o offsets -- Specifies the offset. An offset value of 0xffffffff - * indicates an invalid offset value. - * - * @return Array - */ - public function getIndexBlocks() - { - return $this->_indexBlocks; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Timecode Index Object + * is used, it is recommended that timecodes be stored as a Payload Extension + * System on the appropriate stream. It is also recommended that every + * timecode appearing in the ASF file have a corresponging index entry. + * + * The index is designed to be broken into blocks to facilitate storage that is + * more space-efficient by using 32-bit offsets relative to a 64-bit base. That + * is, each index block has a full 64-bit offset in the block header that is + * added to the 32-bit offsets found in each index entry. If a file is larger + * than 2^32 bytes, then multiple index blocks can be used to fully index the + * entire large file while still keeping index entry offsets at 32 bits. + * + * To locate an object with a particular timecode in an ASF file, one would + * typically look through the Timecode Index Object in blocks of the + * appropriate range and try to locate the nearest possible timecode. The + * corresponding Offset field values of the Index Entry are byte + * offsets that, when combined with the Block Position value of the Index + * Block, indicate the starting location in bytes of an ASF Data Packet relative + * to the start of the first ASF Data Packet in the file. + * + * Any ASF file containing a Timecode Index Object shall also contain a + * Timecode Index Parameters Object in its + * {@link Zend_Media_Asf_Object_Header ASF Header}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: TimecodeIndex.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_TimecodeIndex extends Zend_Media_Asf_Object +{ + /** + * Indicates that the index type is Nearest Past Data Packet. The Nearest + * Past Data Packet indexes point to the data packet whose presentation time + * is closest to the index entry time. + */ + const NEAREST_PAST_DATA_PACKET = 1; + + /** + * Indicates that the index type is Nearest Past Media. The Nearest Past + * Object indexes point to the closest data packet containing an entire + * object or first fragment of an object. + */ + const NEAREST_PAST_MEDIA = 2; + + /** + * Indicates that the index type is Nearest Past Cleanpoint. The Nearest + * Past Cleanpoint indexes point to the closest data packet containing an + * entire object (or first fragment of an object) that has the Cleanpoint + * Flag set. + * + * Nearest Past Cleanpoint is the most common type of index. + */ + const NEAREST_PAST_CLEANPOINT = 3; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** @var Array */ + private $_indexBlocks = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_reader->skip(4); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + $indexBlocksCount = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + for ($i = 0; $i < $indexBlocksCount; $i++) { + $indexEntryCount = $this->_reader->readUInt32LE(); + $timecodeRange = $this->_reader->readUInt16LE(); + $blockPositions = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $blockPositions[] = $this->_reader->readInt64LE(); + } + $indexEntries = array(); + for ($i = 0; $i < $indexEntryCount; $i++) { + $timecode = $this->_reader->readUInt32LE(); + $offsets = array(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $offsets[] = $this->_reader->readUInt32LE(); + } + $indexEntries[] = array + ('timecode' => $timecode, + 'offsets' => $offsets); + } + $this->_indexBlocks[] = array + ('timecodeRange' => $timecodeRange, + 'blockPositions' => $blockPositions, + 'indexEntries' => $indexEntries); + } + } + + /** + * Returns an array of index specifiers. Each entry consists of the + * following keys. + * + * o streamNumber -- Specifies the stream number that the Index + * Specifiers refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o timecodeRange -- Specifies the timecode range for this block. + * Subsequent blocks must contain range numbers greater than or equal to + * this one. + * + * o blockPositions -- Specifies a list of byte offsets of the beginnings + * of the blocks relative to the beginning of the first Data Packet (for + * example, the beginning of the Data Object + 50 bytes). + * + * o indexEntries -- An array that consists of the following keys + * o timecode -- This is the 4-byte timecode for these entries. + * o offsets -- Specifies the offset. An offset value of 0xffffffff + * indicates an invalid offset value. + * + * @return Array + */ + public function getIndexBlocks() + { + return $this->_indexBlocks; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndexParameters.php b/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndexParameters.php index 55280899..02da0ca5 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndexParameters.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/TimecodeIndexParameters.php @@ -1,129 +1,129 @@ -Timecode Index Parameters Object supplies information about those - * streams that are actually indexed (there must be at least one stream in an - * index) by timecodes. All streams referred to in the - * {@link Zend_Media_Asf_Object_TimecodeIndexParameters Timecode Index - * Parameters Object} must have timecode Payload Extension Systems associated - * with them in the - * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream - * Properties Object}. This object shall be present in the - * {@link Zend_Media_Asf_Object_Header Header Object} if there is a - * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object} present in - * the file. - * - * An Index Specifier is required for each stream that will be indexed by the - * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object}. These - * specifiers must exactly match those in the - * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object}. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: TimecodeIndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_TimecodeIndexParameters - extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_indexEntryCountInterval; - - /** @var Array */ - private $_indexSpecifiers = array(); - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); - $indexSpecifiersCount = $this->_reader->readUInt16LE(); - for ($i = 0; $i < $indexSpecifiersCount; $i++) { - $this->_indexSpecifiers[] = array - ('streamNumber' => $this->_reader->readUInt16LE(), - 'indexType' => $this->_reader->readUInt16LE()); - } - } - - /** - * Returns the interval between each index entry by the number of media - * objects. This value cannot be 0. - * - * @return integer - */ - public function getIndexEntryCountInterval() - { - return $this->_indexEntryCountInterval; - } - - /** - * Returns an array of index entries. Each entry consists of the following - * keys. - * - * o streamNumber -- Specifies the stream number that the Index Specifiers - * refer to. Valid values are between 1 and 127. - * - * o indexType -- Specifies the type of index. Values are defined as - * follows: - * 2 = Nearest Past Media Object, - * 3 = Nearest Past Cleanpoint (1 is not a valid value). - * For a video stream, The Nearest Past Media Object indexes point to - * the closest data packet containing an entire video frame or the first - * fragment of a video frame, and the Nearest Past Cleanpoint indexes - * point to the closest data packet containing an entire video frame (or - * first fragment of a video frame) that is a key frame. Nearest Past - * Media Object is the most common value. - * - * @return Array - */ - public function getIndexSpecifiers() - { - return $this->_indexSpecifiers; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - require_once 'Zend/Media/Asf/Exception.php'; - throw new Zend_Media_Asf_Exception('Operation not supported'); - } -} +Timecode Index Parameters Object supplies information about those + * streams that are actually indexed (there must be at least one stream in an + * index) by timecodes. All streams referred to in the + * {@link Zend_Media_Asf_Object_TimecodeIndexParameters Timecode Index + * Parameters Object} must have timecode Payload Extension Systems associated + * with them in the + * {@link Zend_Media_Asf_Object_ExtendedStreamProperties Extended Stream + * Properties Object}. This object shall be present in the + * {@link Zend_Media_Asf_Object_Header Header Object} if there is a + * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object} present in + * the file. + * + * An Index Specifier is required for each stream that will be indexed by the + * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object}. These + * specifiers must exactly match those in the + * {@link Zend_Media_Asf_Object_TimecodeIndex Timecode Index Object}. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: TimecodeIndexParameters.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_TimecodeIndexParameters + extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_indexEntryCountInterval; + + /** @var Array */ + private $_indexSpecifiers = array(); + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_indexEntryCountInterval = $this->_reader->readUInt32LE(); + $indexSpecifiersCount = $this->_reader->readUInt16LE(); + for ($i = 0; $i < $indexSpecifiersCount; $i++) { + $this->_indexSpecifiers[] = array + ('streamNumber' => $this->_reader->readUInt16LE(), + 'indexType' => $this->_reader->readUInt16LE()); + } + } + + /** + * Returns the interval between each index entry by the number of media + * objects. This value cannot be 0. + * + * @return integer + */ + public function getIndexEntryCountInterval() + { + return $this->_indexEntryCountInterval; + } + + /** + * Returns an array of index entries. Each entry consists of the following + * keys. + * + * o streamNumber -- Specifies the stream number that the Index Specifiers + * refer to. Valid values are between 1 and 127. + * + * o indexType -- Specifies the type of index. Values are defined as + * follows: + * 2 = Nearest Past Media Object, + * 3 = Nearest Past Cleanpoint (1 is not a valid value). + * For a video stream, The Nearest Past Media Object indexes point to + * the closest data packet containing an entire video frame or the first + * fragment of a video frame, and the Nearest Past Cleanpoint indexes + * point to the closest data packet containing an entire video frame (or + * first fragment of a video frame) that is a key frame. Nearest Past + * Media Object is the most common value. + * + * @return Array + */ + public function getIndexSpecifiers() + { + return $this->_indexSpecifiers; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + require_once 'Zend/Media/Asf/Exception.php'; + throw new Zend_Media_Asf_Exception('Operation not supported'); + } +} diff --git a/app/libs/vendor/Zend/Media/Asf/Object/Unknown.php b/app/libs/vendor/Zend/Media/Asf/Object/Unknown.php index 6b739bf0..9b7e0ce6 100644 --- a/app/libs/vendor/Zend/Media/Asf/Object/Unknown.php +++ b/app/libs/vendor/Zend/Media/Asf/Object/Unknown.php @@ -1,71 +1,71 @@ -Unknown Object represents objects that are not known to the - * library. - * - * @category Zend - * @package Zend_Media - * @subpackage ASF - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Unknown.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Asf_Object_Unknown extends Zend_Media_Asf_Object -{ - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and reads object related data - * from the ASF file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_data = $this->_reader->read - ($this->getSize() - 24 /* for header */); - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $writer->writeGuid($this->getIdentifier()) - ->writeInt64LE($this->getSize()) - ->write($this->_data); - } -} +Unknown Object represents objects that are not known to the + * library. + * + * @category Zend + * @package Zend_Media + * @subpackage ASF + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Unknown.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Asf_Object_Unknown extends Zend_Media_Asf_Object +{ + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and reads object related data + * from the ASF file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_data = $this->_reader->read + ($this->getSize() - 24 /* for header */); + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $writer->writeGuid($this->getIdentifier()) + ->writeInt64LE($this->getSize()) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Exception.php b/app/libs/vendor/Zend/Media/Exception.php index 0c80b638..c76b8af0 100644 --- a/app/libs/vendor/Zend/Media/Exception.php +++ b/app/libs/vendor/Zend/Media/Exception.php @@ -1,39 +1,39 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Exception extends Zend_Exception -{} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Exception extends Zend_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Flac.php b/app/libs/vendor/Zend/Media/Flac.php index 1d55c92d..878a14c2 100644 --- a/app/libs/vendor/Zend/Media/Flac.php +++ b/app/libs/vendor/Zend/Media/Flac.php @@ -1,270 +1,270 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Flac.php 251 2011-06-13 15:41:51Z svollbehr $ - */ -final class Zend_Media_Flac -{ - /** The streaminfo metadata block */ - const STREAMINFO = 0; - - /** The padding metadata block */ - const PADDING = 1; - - /** The application metadata block */ - const APPLICATION = 2; - - /** The seektable metadata block */ - const SEEKTABLE = 3; - - /** The vorbis comment metadata block */ - const VORBIS_COMMENT = 4; - - /** The cuesheet metadata block */ - const CUESHEET = 5; - - /** The picture metadata block */ - const PICTURE = 6; - - /** @var Zend_Io_Reader */ - private $_reader; - - /** @var Array */ - private $_metadataBlocks = array(); - - /** @var string */ - private $_filename = null; - - /** - * Constructs the class with given filename. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @throws Zend_Io_Exception if an error occur in stream handling. - * @throws Zend_Media_Flac_Exception if an error occurs in vorbis bitstream reading. - */ - public function __construct($filename) - { - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - $this->_filename = $filename; - require_once('Zend/Io/FileReader.php'); - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } - - $capturePattern = $this->_reader->read(4); - if ($capturePattern != 'fLaC') { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception('Not a valid FLAC bitstream'); - } - - while (true) { - $offset = $this->_reader->getOffset(); - $last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1; - $type = $tmp & 0x7f; - $size = $this->_reader->readUInt24BE(); - - $this->_reader->setOffset($offset); - switch ($type) { - case self::STREAMINFO: // 0 - require_once 'Zend/Media/Flac/MetadataBlock/Streaminfo.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Streaminfo($this->_reader); - break; - case self::PADDING: // 1 - require_once 'Zend/Media/Flac/MetadataBlock/Padding.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Padding($this->_reader); - break; - case self::APPLICATION: // 2 - require_once 'Zend/Media/Flac/MetadataBlock/Application.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Application($this->_reader); - break; - case self::SEEKTABLE: // 3 - require_once 'Zend/Media/Flac/MetadataBlock/Seektable.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Seektable($this->_reader); - break; - case self::VORBIS_COMMENT: // 4 - require_once 'Zend/Media/Flac/MetadataBlock/VorbisComment.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_VorbisComment($this->_reader); - break; - case self::CUESHEET: // 5 - require_once 'Zend/Media/Flac/MetadataBlock/Cuesheet.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Cuesheet($this->_reader); - break; - case self::PICTURE: // 6 - require_once 'Zend/Media/Flac/MetadataBlock/Picture.php'; - $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Picture($this->_reader); - break; - default: - // break intentionally omitted - } - $this->_reader->setOffset($offset + 4 /* header */ + $size); - - // Jump off the loop if we reached the end of metadata blocks - if ($last === 1) { - break; - } - } - } - - /** - * Checks whether the given metadata block is there. Returns true if one ore more frames are present, - * false otherwise. - * - * @param string $type The metadata block type. - * @return boolean - */ - public function hasMetadataBlock($type) - { - $metadataBlockCount = count($this->_metadataBlocks); - for ($i = 0; $i < $metadataBlockCount; $i++) { - if ($this->_metadataBlocks[$i]->getType() === $type) { - return true; - } - } - return false; - } - - /** - * Returns all the metadata blocks as an associate array. - * - * @return Array - */ - public function getMetadataBlocks() - { - return $this->_metadataBlocks; - } - - /** - * Returns an array of metadata blocks frames matching the given type or an empty array if no metadata blocks - * matched the type. - * - * Please note that one may also use the shorthand $obj->type or $obj->getType(), where the type is the metadata - * block name, to access the first metadata block with the given type. - * - * @param string $type The metadata block type. - * @return Array - */ - public function getMetadataBlocksByType($type) - { - $matches = array(); - $metadataBlockCount = count($this->_metadataBlocks); - for ($i = 0; $i < $metadataBlockCount; $i++) { - if ($this->_metadataBlocks[$i]->getType() === $type) { - $matches[] = $this->_metadataBlocks[$i]; - } - } - return $matches; - } - - /** - * Magic function so that $obj->X() or $obj->getX() will work, where X is the name of the metadata block. If there - * is no metadata block by the given name, an exception is thrown. - * - * @param string $name The metadata block name. - * @return mixed - */ - public function __call($name, $arguments) - { - if (preg_match('/^(?:get)([A-Z].*)$/', $name, $matches)) { - $name = lcfirst($matches[1]); - } - if (defined($constant = 'self::' . strtoupper(preg_replace('/(?<=[a-z])[A-Z]/', '_$0', $name)))) { - $metadataBlocks = $this->getMetadataBlocksByType(constant($constant)); - if (isset($metadataBlocks[0])) { - return $metadataBlocks[0]; - } - } - if (!empty($this->_comments[strtoupper($name)])) { - return $this->_comments[strtoupper($name)][0]; - } - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception('Unknown metadata block: ' . strtoupper($name)); - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The metadata block name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func - (array($this, 'get' . ucfirst($name))); - } - if (defined($constant = 'self::' . strtoupper(preg_replace('/(?<=[a-z])[A-Z]/', '_$0', $name)))) { - $metadataBlocks = $this->getMetadataBlocksByType(constant($constant)); - if (isset($metadataBlocks[0])) { - return $metadataBlocks[0]; - } - } - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception('Unknown metadata block or field: ' . $name); - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { - call_user_func - (array($this, 'set' . ucfirst(strtolower($name))), $value); - } else { - require_once('Zend/Media/Flac/Exception.php'); - throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Flac.php 251 2011-06-13 15:41:51Z svollbehr $ + */ +final class Zend_Media_Flac +{ + /** The streaminfo metadata block */ + const STREAMINFO = 0; + + /** The padding metadata block */ + const PADDING = 1; + + /** The application metadata block */ + const APPLICATION = 2; + + /** The seektable metadata block */ + const SEEKTABLE = 3; + + /** The vorbis comment metadata block */ + const VORBIS_COMMENT = 4; + + /** The cuesheet metadata block */ + const CUESHEET = 5; + + /** The picture metadata block */ + const PICTURE = 6; + + /** @var Zend_Io_Reader */ + private $_reader; + + /** @var Array */ + private $_metadataBlocks = array(); + + /** @var string */ + private $_filename = null; + + /** + * Constructs the class with given filename. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @throws Zend_Io_Exception if an error occur in stream handling. + * @throws Zend_Media_Flac_Exception if an error occurs in vorbis bitstream reading. + */ + public function __construct($filename) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + $this->_filename = $filename; + require_once('Zend/Io/FileReader.php'); + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } + + $capturePattern = $this->_reader->read(4); + if ($capturePattern != 'fLaC') { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception('Not a valid FLAC bitstream'); + } + + while (true) { + $offset = $this->_reader->getOffset(); + $last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1; + $type = $tmp & 0x7f; + $size = $this->_reader->readUInt24BE(); + + $this->_reader->setOffset($offset); + switch ($type) { + case self::STREAMINFO: // 0 + require_once 'Zend/Media/Flac/MetadataBlock/Streaminfo.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Streaminfo($this->_reader); + break; + case self::PADDING: // 1 + require_once 'Zend/Media/Flac/MetadataBlock/Padding.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Padding($this->_reader); + break; + case self::APPLICATION: // 2 + require_once 'Zend/Media/Flac/MetadataBlock/Application.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Application($this->_reader); + break; + case self::SEEKTABLE: // 3 + require_once 'Zend/Media/Flac/MetadataBlock/Seektable.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Seektable($this->_reader); + break; + case self::VORBIS_COMMENT: // 4 + require_once 'Zend/Media/Flac/MetadataBlock/VorbisComment.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_VorbisComment($this->_reader); + break; + case self::CUESHEET: // 5 + require_once 'Zend/Media/Flac/MetadataBlock/Cuesheet.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Cuesheet($this->_reader); + break; + case self::PICTURE: // 6 + require_once 'Zend/Media/Flac/MetadataBlock/Picture.php'; + $this->_metadataBlocks[] = new Zend_Media_Flac_MetadataBlock_Picture($this->_reader); + break; + default: + // break intentionally omitted + } + $this->_reader->setOffset($offset + 4 /* header */ + $size); + + // Jump off the loop if we reached the end of metadata blocks + if ($last === 1) { + break; + } + } + } + + /** + * Checks whether the given metadata block is there. Returns true if one ore more frames are present, + * false otherwise. + * + * @param string $type The metadata block type. + * @return boolean + */ + public function hasMetadataBlock($type) + { + $metadataBlockCount = count($this->_metadataBlocks); + for ($i = 0; $i < $metadataBlockCount; $i++) { + if ($this->_metadataBlocks[$i]->getType() === $type) { + return true; + } + } + return false; + } + + /** + * Returns all the metadata blocks as an associate array. + * + * @return Array + */ + public function getMetadataBlocks() + { + return $this->_metadataBlocks; + } + + /** + * Returns an array of metadata blocks frames matching the given type or an empty array if no metadata blocks + * matched the type. + * + * Please note that one may also use the shorthand $obj->type or $obj->getType(), where the type is the metadata + * block name, to access the first metadata block with the given type. + * + * @param string $type The metadata block type. + * @return Array + */ + public function getMetadataBlocksByType($type) + { + $matches = array(); + $metadataBlockCount = count($this->_metadataBlocks); + for ($i = 0; $i < $metadataBlockCount; $i++) { + if ($this->_metadataBlocks[$i]->getType() === $type) { + $matches[] = $this->_metadataBlocks[$i]; + } + } + return $matches; + } + + /** + * Magic function so that $obj->X() or $obj->getX() will work, where X is the name of the metadata block. If there + * is no metadata block by the given name, an exception is thrown. + * + * @param string $name The metadata block name. + * @return mixed + */ + public function __call($name, $arguments) + { + if (preg_match('/^(?:get)([A-Z].*)$/', $name, $matches)) { + $name = lcfirst($matches[1]); + } + if (defined($constant = 'self::' . strtoupper(preg_replace('/(?<=[a-z])[A-Z]/', '_$0', $name)))) { + $metadataBlocks = $this->getMetadataBlocksByType(constant($constant)); + if (isset($metadataBlocks[0])) { + return $metadataBlocks[0]; + } + } + if (!empty($this->_comments[strtoupper($name)])) { + return $this->_comments[strtoupper($name)][0]; + } + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception('Unknown metadata block: ' . strtoupper($name)); + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The metadata block name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func + (array($this, 'get' . ucfirst($name))); + } + if (defined($constant = 'self::' . strtoupper(preg_replace('/(?<=[a-z])[A-Z]/', '_$0', $name)))) { + $metadataBlocks = $this->getMetadataBlocksByType(constant($constant)); + if (isset($metadataBlocks[0])) { + return $metadataBlocks[0]; + } + } + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception('Unknown metadata block or field: ' . $name); + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Media/Flac/Exception.php'); + throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/Exception.php b/app/libs/vendor/Zend/Media/Flac/Exception.php index 70a32c65..e7f007e7 100644 --- a/app/libs/vendor/Zend/Media/Flac/Exception.php +++ b/app/libs/vendor/Zend/Media/Flac/Exception.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -class Zend_Media_Flac_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +class Zend_Media_Flac_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock.php index 508ae27e..9067a1fe 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock.php @@ -1,173 +1,173 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: MetadataBlock.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -abstract class Zend_Media_Flac_MetadataBlock -{ - /** - * The reader object. - * - * @var Zend_Io_Reader - */ - protected $_reader; - - /** @var integer */ - private $_last; - - /** @var integer */ - private $_type; - - /** @var integer */ - private $_size; - - /** - * Constructs the class with given parameters and reads object related data - * from the Flac bitstream. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - $this->_reader = $reader; - - $this->_last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1; - $this->_type = $tmp & 0x7f; - $this->_size = $this->_reader->readUInt24BE(); - } - - /** - * Returns the metadata block type. The type is one of the following. - * - * o 0: STREAMINFO - * o 1: PADDING - * o 2: APPLICATION - * o 3: SEEKTABLE - * o 4: VORBIS_COMMENT - * o 5: CUESHEET - * o 6: PICTURE - * o 7-126: reserved - * o 127: invalid, to avoid confusion with a frame sync code - * - * @return integer - */ - public function getType() - { - return $this->_type; - } - - /** - * Returns the metadata block length without the header, in bytes. - * - * @return integer - */ - public function getSize() - { - return $this->_size; - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } else { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } else { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: MetadataBlock.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +abstract class Zend_Media_Flac_MetadataBlock +{ + /** + * The reader object. + * + * @var Zend_Io_Reader + */ + protected $_reader; + + /** @var integer */ + private $_last; + + /** @var integer */ + private $_type; + + /** @var integer */ + private $_size; + + /** + * Constructs the class with given parameters and reads object related data + * from the Flac bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + $this->_reader = $reader; + + $this->_last = ($tmp = $this->_reader->readUInt8()) >> 7 & 0x1; + $this->_type = $tmp & 0x7f; + $this->_size = $this->_reader->readUInt24BE(); + } + + /** + * Returns the metadata block type. The type is one of the following. + * + * o 0: STREAMINFO + * o 1: PADDING + * o 2: APPLICATION + * o 3: SEEKTABLE + * o 4: VORBIS_COMMENT + * o 5: CUESHEET + * o 6: PICTURE + * o 7-126: reserved + * o 127: invalid, to avoid confusion with a frame sync code + * + * @return integer + */ + public function getType() + { + return $this->_type; + } + + /** + * Returns the metadata block length without the header, in bytes. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } else { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } else { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Application.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Application.php index 4ca97398..bf06bbb8 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Application.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Application.php @@ -1,77 +1,77 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Application.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Application extends Zend_Media_Flac_MetadataBlock -{ - /** - * Constructs the class with given parameters and parses object related data. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_identifier = $this->_reader->readUInt32BE(); - $this->_data = $this->_reader->read($this->getSize() - 4); - } - - /** - * Returns the application identifier. - * - * @return integer - */ - public function getIdentifier() - { - return $this->_identifier; - } - - /** - * Returns the application data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Application.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Application extends Zend_Media_Flac_MetadataBlock +{ + /** + * Constructs the class with given parameters and parses object related data. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_identifier = $this->_reader->readUInt32BE(); + $this->_data = $this->_reader->read($this->getSize() - 4); + } + + /** + * Returns the application identifier. + * + * @return integer + */ + public function getIdentifier() + { + return $this->_identifier; + } + + /** + * Returns the application data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Cuesheet.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Cuesheet.php index 70c2868f..ef9bcfa3 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Cuesheet.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Cuesheet.php @@ -1,189 +1,189 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Cuesheet.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Cuesheet extends Zend_Media_Flac_MetadataBlock -{ - /** @var string */ - private $_catalogNumber; - - /** @var integer */ - private $_leadinSamples; - - /** @var boolean */ - private $_compactDisc; - - /** @var Array */ - private $_tracks; - - /** - * Constructs the class with given parameters and parses object related data. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_catalogNumber = rtrim($this->_reader->read(128), "\x00"); - $this->_leadinSamples = $this->_reader->readInt64BE(); - $this->_compactDisc = ($this->_reader->readUInt8() >> 7) & 0x1; - $this->_reader->skip(258); - $tracksLength = $this->_reader->readUInt8(); - for ($i = 0; $i < $tracksLength; $i++) { - $this->_tracks[$i] = array( - 'offset' => $this->_reader->readInt64BE(), - 'number' => $this->_reader->readUInt8(), - 'isrc' => rtrim($this->_reader->read(12), "\x00"), - 'type' => (($tmp = $this->_reader->readUInt8()) >> 7 ) & 0x1, - 'pre-emphasis' => (($tmp) >> 6 ) & 0x1, - 'index' => array()); - $this->_reader->skip(13); - $indexPointsLength = $this->_reader->readUInt8(); - for ($j = 0; $j < $indexPointsLength; $j++) { - $this->_tracks[$i]['index'][$j] = array( - 'offset' => $this->_reader->readInt64BE(), - 'number' => $this->_reader->readUInt8() - ); - $this->_reader->skip(3); - } - } - } - - /** - * Returns the media catalog number, in ASCII printable characters 0x20-0x7e. In general, the media catalog number - * may be 0 to 128 bytes long; any unused characters should be right-padded with NUL characters. For CD-DA, this is - * a thirteen digit number, followed by 115 NUL bytes.minimum block size (in samples) used in the stream. - * - * @return string - */ - public function getCatalogNumber() - { - return $this->_catalogNumber; - } - - /** - * Returns the number of lead-in samples. This field has meaning only for CD-DA cuesheets; for other uses it should - * be 0. For CD-DA, the lead-in is the TRACK 00 area where the table of contents is stored; more precisely, it is - * the number of samples from the first sample of the media to the first sample of the first index point of the - * first track. According to the Red Book, the lead-in must be silence and CD grabbing software does not usually - * store it; additionally, the lead-in must be at least two seconds but may be longer. For these reasons the - * lead-in length is stored here so that the absolute position of the first track can be computed. Note that the - * lead-in stored here is the number of samples up to the first index point of the first track, not necessarily to - * INDEX 01 of the first track; even the first track may have INDEX 00 data. - * - * @return integer - */ - public function getLeadinSamples() - { - return $this->_leadinSamples; - } - - /** - * Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. - * - * @return integer - */ - public function getMinimumFrameSize() - { - return $this->_minimumFrameSize; - } - - /** - * Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. - * - * @return integer - */ - public function getMaximumFrameSize() - { - return $this->_maximumFrameSize; - } - - /** - * Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz. - * Also, a value of 0 is invalid. - * - * @return integer - */ - public function getSampleRate() - { - return $this->_sampleRate; - } - - /** - * Returns whether the CUESHEET corresponds to a Compact Disc or not. - * - * @return boolean - */ - public function getCompactDisk() - { - return $this->_compactDisk == 1; - } - - /** - * Returns an array of values. Each entry is an array containing the following keys. - * o offset -- Track offset in samples, relative to the beginning of the FLAC audio stream. It is the offset to - * the first index point of the track. (Note how this differs from CD-DA, where the track's offset in the TOC - * is that of the track's INDEX 01 even if there is an INDEX 00.) For CD-DA, the offset must be evenly divisible - * by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec). - * o number -- Track number. A track number of 0 is not allowed to avoid conflicting with the CD-DA spec, which - * reserves this for the lead-in. For CD-DA the number must be 1-99, or 170 for the lead-out; for non-CD-DA, - * the track number must for 255 for the lead-out. It is not required but encouraged to start with track 1 and - * increase sequentially. Track numbers must be unique within a CUESHEET. - * o isrc -- Track ISRC. This is a 12-digit alphanumeric code or an empty string to denote absence of an ISRC. - * o type -- The track type: 0 for audio, 1 for non-audio. This corresponds to the CD-DA Q-channel control bit 3. - * o pre-emphasis -- The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. This corresponds to the - * CD-DA Q-channel control bit 5. - * o index -- An array of track index points. There must be at least one index in every track in a CUESHEET except - * for the lead-out track, which must have zero. For CD-DA, this number may be no more than 100. Each entry is - * an array containing the following keys. - * o offset -- Offset in samples, relative to the track offset, of the index point. For CD-DA, the offset must - * be evenly divisible by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec). Note that the - * offset is from the beginning of the track, not the beginning of the audio data. - * o number -- The index point number. For CD-DA, an index number of 0 corresponds to the track pre-gap. The - * first index in a track must have a number of 0 or 1, and subsequently, index numbers must increase by 1. - * Index numbers must be unique within a track. - * - * @return Array - */ - public function getTracks() - { - return $this->_tracks; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Cuesheet.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Cuesheet extends Zend_Media_Flac_MetadataBlock +{ + /** @var string */ + private $_catalogNumber; + + /** @var integer */ + private $_leadinSamples; + + /** @var boolean */ + private $_compactDisc; + + /** @var Array */ + private $_tracks; + + /** + * Constructs the class with given parameters and parses object related data. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_catalogNumber = rtrim($this->_reader->read(128), "\x00"); + $this->_leadinSamples = $this->_reader->readInt64BE(); + $this->_compactDisc = ($this->_reader->readUInt8() >> 7) & 0x1; + $this->_reader->skip(258); + $tracksLength = $this->_reader->readUInt8(); + for ($i = 0; $i < $tracksLength; $i++) { + $this->_tracks[$i] = array( + 'offset' => $this->_reader->readInt64BE(), + 'number' => $this->_reader->readUInt8(), + 'isrc' => rtrim($this->_reader->read(12), "\x00"), + 'type' => (($tmp = $this->_reader->readUInt8()) >> 7 ) & 0x1, + 'pre-emphasis' => (($tmp) >> 6 ) & 0x1, + 'index' => array()); + $this->_reader->skip(13); + $indexPointsLength = $this->_reader->readUInt8(); + for ($j = 0; $j < $indexPointsLength; $j++) { + $this->_tracks[$i]['index'][$j] = array( + 'offset' => $this->_reader->readInt64BE(), + 'number' => $this->_reader->readUInt8() + ); + $this->_reader->skip(3); + } + } + } + + /** + * Returns the media catalog number, in ASCII printable characters 0x20-0x7e. In general, the media catalog number + * may be 0 to 128 bytes long; any unused characters should be right-padded with NUL characters. For CD-DA, this is + * a thirteen digit number, followed by 115 NUL bytes.minimum block size (in samples) used in the stream. + * + * @return string + */ + public function getCatalogNumber() + { + return $this->_catalogNumber; + } + + /** + * Returns the number of lead-in samples. This field has meaning only for CD-DA cuesheets; for other uses it should + * be 0. For CD-DA, the lead-in is the TRACK 00 area where the table of contents is stored; more precisely, it is + * the number of samples from the first sample of the media to the first sample of the first index point of the + * first track. According to the Red Book, the lead-in must be silence and CD grabbing software does not usually + * store it; additionally, the lead-in must be at least two seconds but may be longer. For these reasons the + * lead-in length is stored here so that the absolute position of the first track can be computed. Note that the + * lead-in stored here is the number of samples up to the first index point of the first track, not necessarily to + * INDEX 01 of the first track; even the first track may have INDEX 00 data. + * + * @return integer + */ + public function getLeadinSamples() + { + return $this->_leadinSamples; + } + + /** + * Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + * + * @return integer + */ + public function getMinimumFrameSize() + { + return $this->_minimumFrameSize; + } + + /** + * Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + * + * @return integer + */ + public function getMaximumFrameSize() + { + return $this->_maximumFrameSize; + } + + /** + * Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz. + * Also, a value of 0 is invalid. + * + * @return integer + */ + public function getSampleRate() + { + return $this->_sampleRate; + } + + /** + * Returns whether the CUESHEET corresponds to a Compact Disc or not. + * + * @return boolean + */ + public function getCompactDisk() + { + return $this->_compactDisk == 1; + } + + /** + * Returns an array of values. Each entry is an array containing the following keys. + * o offset -- Track offset in samples, relative to the beginning of the FLAC audio stream. It is the offset to + * the first index point of the track. (Note how this differs from CD-DA, where the track's offset in the TOC + * is that of the track's INDEX 01 even if there is an INDEX 00.) For CD-DA, the offset must be evenly divisible + * by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec). + * o number -- Track number. A track number of 0 is not allowed to avoid conflicting with the CD-DA spec, which + * reserves this for the lead-in. For CD-DA the number must be 1-99, or 170 for the lead-out; for non-CD-DA, + * the track number must for 255 for the lead-out. It is not required but encouraged to start with track 1 and + * increase sequentially. Track numbers must be unique within a CUESHEET. + * o isrc -- Track ISRC. This is a 12-digit alphanumeric code or an empty string to denote absence of an ISRC. + * o type -- The track type: 0 for audio, 1 for non-audio. This corresponds to the CD-DA Q-channel control bit 3. + * o pre-emphasis -- The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. This corresponds to the + * CD-DA Q-channel control bit 5. + * o index -- An array of track index points. There must be at least one index in every track in a CUESHEET except + * for the lead-out track, which must have zero. For CD-DA, this number may be no more than 100. Each entry is + * an array containing the following keys. + * o offset -- Offset in samples, relative to the track offset, of the index point. For CD-DA, the offset must + * be evenly divisible by 588 samples (588 samples = 44100 samples/sec * 1/75th of a sec). Note that the + * offset is from the beginning of the track, not the beginning of the audio data. + * o number -- The index point number. For CD-DA, an index number of 0 corresponds to the track pre-gap. The + * first index in a track must have a number of 0 or 1, and subsequently, index numbers must increase by 1. + * Index numbers must be unique within a track. + * + * @return Array + */ + public function getTracks() + { + return $this->_tracks; + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Padding.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Padding.php index e221f679..5fd8d9aa 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Padding.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Padding.php @@ -1,53 +1,53 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Padding.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Padding extends Zend_Media_Flac_MetadataBlock -{ - /** - * Constructs the class with given parameters and parses object related data. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Padding.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Padding extends Zend_Media_Flac_MetadataBlock +{ + /** + * Constructs the class with given parameters and parses object related data. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Picture.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Picture.php index 243f7a2b..c8f83618 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Picture.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Picture.php @@ -1,199 +1,199 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Picture.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Picture extends Zend_Media_Flac_MetadataBlock -{ - /** - * The list of picture types. - * - * @var Array - */ - public static $types = array - ('Other', '32x32 pixels file icon (PNG only)', 'Other file icon', - 'Cover (front)', 'Cover (back)', 'Leaflet page', - 'Media (e.g. label side of CD)', 'Lead artist/lead performer/soloist', - 'Artist/performer', 'Conductor', 'Band/Orchestra', 'Composer', - 'Lyricist/text writer', 'Recording Location', 'During recording', - 'During performance', 'Movie/video screen capture', - 'A bright coloured fish', 'Illustration', 'Band/artist logotype', - 'Publisher/Studio logotype'); - - /** @var integer */ - private $_type; - - /** @var string */ - private $_mimeType; - - /** @var string */ - private $_description; - - /** @var integer */ - private $_width; - - /** @var integer */ - private $_height; - - /** @var integer */ - private $_colorDepth; - - /** @var integer */ - private $_numberOfColors; - - /** @var integer */ - private $_dataSize; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and parses object related data. - * - * @todo There is the possibility to put only a link to the picture file by - * using the MIME type '-->' and having a complete URL instead of picture - * data. Support for such needs design considerations. - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_type = $this->_reader->readUInt32BE(); - $this->_mimeType = $this->_reader->read($this->_reader->readUInt32BE()); - $this->_description = $this->_reader->read($this->_reader->readUInt32BE()); - $this->_width = $this->_reader->readUInt32BE(); - $this->_height = $this->_reader->readUInt32BE(); - $this->_colorDepth = $this->_reader->readUInt32BE(); - $this->_numberOfColors = $this->_reader->readUInt32BE(); - $this->_data = $this->_reader->read($this->_dataSize = $this->_reader->readUInt32BE()); - } - - /** - * Returns the picture type. - * - * @return integer - */ - public function getPictureType() - { - return $this->_pictureType; - } - - /** - * Returns the MIME type. - * - * @return string - */ - public function getMimeType() - { - return $this->_mimeType; - } - - /** - * Returns the picture description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Returns the picture width. - * - * @return integer - */ - public function getWidth() - { - return $this->_width; - } - - /** - * Returns the picture height. - * - * @return integer - */ - public function getHeight() - { - return $this->_height; - } - - /** - * Returns the color depth of the picture in bits-per-pixel. - * - * @return integer - */ - public function getColorDepth() - { - return $this->_colorDepth; - } - - /** - * Returns the number of colors used for indexed-color pictures, or 0 for non-indexed pictures. - * - * @return integer - */ - public function getNumberOfColors() - { - return $this->_numberOfColors; - } - - /** - * Returns the picture data size. - * - * @return integer - */ - public function getDataSize() - { - return $this->_dataSize; - } - - /** - * Returns the picture data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Picture.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Picture extends Zend_Media_Flac_MetadataBlock +{ + /** + * The list of picture types. + * + * @var Array + */ + public static $types = array + ('Other', '32x32 pixels file icon (PNG only)', 'Other file icon', + 'Cover (front)', 'Cover (back)', 'Leaflet page', + 'Media (e.g. label side of CD)', 'Lead artist/lead performer/soloist', + 'Artist/performer', 'Conductor', 'Band/Orchestra', 'Composer', + 'Lyricist/text writer', 'Recording Location', 'During recording', + 'During performance', 'Movie/video screen capture', + 'A bright coloured fish', 'Illustration', 'Band/artist logotype', + 'Publisher/Studio logotype'); + + /** @var integer */ + private $_type; + + /** @var string */ + private $_mimeType; + + /** @var string */ + private $_description; + + /** @var integer */ + private $_width; + + /** @var integer */ + private $_height; + + /** @var integer */ + private $_colorDepth; + + /** @var integer */ + private $_numberOfColors; + + /** @var integer */ + private $_dataSize; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and parses object related data. + * + * @todo There is the possibility to put only a link to the picture file by + * using the MIME type '-->' and having a complete URL instead of picture + * data. Support for such needs design considerations. + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_type = $this->_reader->readUInt32BE(); + $this->_mimeType = $this->_reader->read($this->_reader->readUInt32BE()); + $this->_description = $this->_reader->read($this->_reader->readUInt32BE()); + $this->_width = $this->_reader->readUInt32BE(); + $this->_height = $this->_reader->readUInt32BE(); + $this->_colorDepth = $this->_reader->readUInt32BE(); + $this->_numberOfColors = $this->_reader->readUInt32BE(); + $this->_data = $this->_reader->read($this->_dataSize = $this->_reader->readUInt32BE()); + } + + /** + * Returns the picture type. + * + * @return integer + */ + public function getPictureType() + { + return $this->_pictureType; + } + + /** + * Returns the MIME type. + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Returns the picture description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Returns the picture width. + * + * @return integer + */ + public function getWidth() + { + return $this->_width; + } + + /** + * Returns the picture height. + * + * @return integer + */ + public function getHeight() + { + return $this->_height; + } + + /** + * Returns the color depth of the picture in bits-per-pixel. + * + * @return integer + */ + public function getColorDepth() + { + return $this->_colorDepth; + } + + /** + * Returns the number of colors used for indexed-color pictures, or 0 for non-indexed pictures. + * + * @return integer + */ + public function getNumberOfColors() + { + return $this->_numberOfColors; + } + + /** + * Returns the picture data size. + * + * @return integer + */ + public function getDataSize() + { + return $this->_dataSize; + } + + /** + * Returns the picture data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Seektable.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Seektable.php index 5cecc3d8..a34a3444 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Seektable.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Seektable.php @@ -1,82 +1,82 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Seektable.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Seektable extends Zend_Media_Flac_MetadataBlock -{ - /** @var Array */ - private $_seekpoints = array(); - - /** - * Constructs the class with given parameters and parses object related data. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $seekpointCount = $this->getSize() / 18; - for ($i = 0; $i < $seekpointCount; $i++) { - $this->_seekpoints[] = array( - 'sampleNumber' => $this->_reader->readInt64BE(), - 'offset' => $this->_reader->readInt64BE(), - 'numberOfSamples' => $this->_reader->readUInt16BE() - ); - } - } - - /** - * Returns the seekpoint table. The array consists of items having three keys. - * - * o sampleNumber -- Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a - * placeholder point. - * o offset -- Offset (in bytes) from the first byte of the first frame header to the first byte of the - * target frame's header. - * o numberOfSamples -- Number of samples in the target frame. - * - * @return Array - */ - public function getSeekpoints() - { - return $this->_seekpoints; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Seektable.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Seektable extends Zend_Media_Flac_MetadataBlock +{ + /** @var Array */ + private $_seekpoints = array(); + + /** + * Constructs the class with given parameters and parses object related data. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $seekpointCount = $this->getSize() / 18; + for ($i = 0; $i < $seekpointCount; $i++) { + $this->_seekpoints[] = array( + 'sampleNumber' => $this->_reader->readInt64BE(), + 'offset' => $this->_reader->readInt64BE(), + 'numberOfSamples' => $this->_reader->readUInt16BE() + ); + } + } + + /** + * Returns the seekpoint table. The array consists of items having three keys. + * + * o sampleNumber -- Sample number of first sample in the target frame, or 0xFFFFFFFFFFFFFFFF for a + * placeholder point. + * o offset -- Offset (in bytes) from the first byte of the first frame header to the first byte of the + * target frame's header. + * o numberOfSamples -- Number of samples in the target frame. + * + * @return Array + */ + public function getSeekpoints() + { + return $this->_seekpoints; + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Streaminfo.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Streaminfo.php index 558b9075..fa2209d1 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Streaminfo.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/Streaminfo.php @@ -1,185 +1,185 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Streaminfo.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_Streaminfo extends Zend_Media_Flac_MetadataBlock -{ - /** @var integer */ - private $_minimumBlockSize; - - /** @var integer */ - private $_maximumBlockSize; - - /** @var integer */ - private $_minimumFrameSize; - - /** @var integer */ - private $_maximumFrameSize; - - /** @var integer */ - private $_sampleRate; - - /** @var integer */ - private $_numberOfChannels; - - /** @var integer */ - private $_bitsPerSample; - - /** @var integer */ - private $_numberOfSamples; - - /** @var string */ - private $_md5Signature; - - /** - * Constructs the class with given parameters and parses object related data. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_minimumBlockSize = $this->_reader->readUInt16BE(); - $this->_maximumBlockSize = $this->_reader->readUInt16BE(); - $this->_minimumFrameSize = $this->_reader->readUInt24BE(); - $this->_maximumFrameSize = $this->_reader->readUInt24BE(); - $this->_sampleRate = Zend_Bit_Twiddling::getValue(($tmp = $this->_reader->readUInt32BE()), 12, 31); - $this->_numberOfChannels = Zend_Bit_Twiddling::getValue($tmp, 9, 11) + 1; - $this->_bitsPerSample = Zend_Bit_Twiddling::getValue($tmp, 4, 8) + 1; - $this->_numberOfSamples = (Zend_Bit_Twiddling::getValue($tmp, 0, 3) << 32) | $this->_reader->readUInt32BE(); - $this->_md5Signature = bin2hex($this->_reader->read(16)); - } - - /** - * Returns the minimum block size (in samples) used in the stream. - * - * @return integer - */ - public function getMinimumBlockSize() - { - return $this->_minimumBlockSize; - } - - /** - * Returns the maximum block size (in samples) used in the stream. (Minimum blocksize == maximum blocksize) implies - * a fixed-blocksize stream. - * - * @return integer - */ - public function getMaximumBlockSize() - { - return $this->_maximumBlockSize; - } - - /** - * Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. - * - * @return integer - */ - public function getMinimumFrameSize() - { - return $this->_minimumFrameSize; - } - - /** - * Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. - * - * @return integer - */ - public function getMaximumFrameSize() - { - return $this->_maximumFrameSize; - } - - /** - * Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz. - * Also, a value of 0 is invalid. - * - * @return integer - */ - public function getSampleRate() - { - return $this->_sampleRate; - } - - /** - * Returns number of channels. FLAC supports from 1 to 8 channels. - * - * @return integer - */ - public function getNumberOfChannels() - { - return $this->_numberOfChannels; - } - - /** - * Returns bits per sample. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and - * decoders only support up to 24 bits per sample. - * - * @return integer - */ - public function getBitsPerSample() - { - return $this->_bitsPerSample; - } - - /** - * Returns total samples in stream. 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will - * have 44100 samples regardless of the number of channels. A value of zero here means the number of total samples - * is unknown. - * - * @return integer - */ - public function getNumberOfSamples() - { - return $this->_numberOfSamples; - } - - /** - * Returns MD5 signature of the unencoded audio data. This allows the decoder to determine if an error exists in - * the audio data even when the error does not result in an invalid bitstream. - * - * @return integer - */ - public function getMd5Signature() - { - return $this->_md5Signature; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Streaminfo.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_Streaminfo extends Zend_Media_Flac_MetadataBlock +{ + /** @var integer */ + private $_minimumBlockSize; + + /** @var integer */ + private $_maximumBlockSize; + + /** @var integer */ + private $_minimumFrameSize; + + /** @var integer */ + private $_maximumFrameSize; + + /** @var integer */ + private $_sampleRate; + + /** @var integer */ + private $_numberOfChannels; + + /** @var integer */ + private $_bitsPerSample; + + /** @var integer */ + private $_numberOfSamples; + + /** @var string */ + private $_md5Signature; + + /** + * Constructs the class with given parameters and parses object related data. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_minimumBlockSize = $this->_reader->readUInt16BE(); + $this->_maximumBlockSize = $this->_reader->readUInt16BE(); + $this->_minimumFrameSize = $this->_reader->readUInt24BE(); + $this->_maximumFrameSize = $this->_reader->readUInt24BE(); + $this->_sampleRate = Zend_Bit_Twiddling::getValue(($tmp = $this->_reader->readUInt32BE()), 12, 31); + $this->_numberOfChannels = Zend_Bit_Twiddling::getValue($tmp, 9, 11) + 1; + $this->_bitsPerSample = Zend_Bit_Twiddling::getValue($tmp, 4, 8) + 1; + $this->_numberOfSamples = (Zend_Bit_Twiddling::getValue($tmp, 0, 3) << 32) | $this->_reader->readUInt32BE(); + $this->_md5Signature = bin2hex($this->_reader->read(16)); + } + + /** + * Returns the minimum block size (in samples) used in the stream. + * + * @return integer + */ + public function getMinimumBlockSize() + { + return $this->_minimumBlockSize; + } + + /** + * Returns the maximum block size (in samples) used in the stream. (Minimum blocksize == maximum blocksize) implies + * a fixed-blocksize stream. + * + * @return integer + */ + public function getMaximumBlockSize() + { + return $this->_maximumBlockSize; + } + + /** + * Returns the minimum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + * + * @return integer + */ + public function getMinimumFrameSize() + { + return $this->_minimumFrameSize; + } + + /** + * Returns the maximum frame size (in bytes) used in the stream. May be 0 to imply the value is not known. + * + * @return integer + */ + public function getMaximumFrameSize() + { + return $this->_maximumFrameSize; + } + + /** + * Returns sample rate in Hz. The maximum sample rate is limited by the structure of frame headers to 655350Hz. + * Also, a value of 0 is invalid. + * + * @return integer + */ + public function getSampleRate() + { + return $this->_sampleRate; + } + + /** + * Returns number of channels. FLAC supports from 1 to 8 channels. + * + * @return integer + */ + public function getNumberOfChannels() + { + return $this->_numberOfChannels; + } + + /** + * Returns bits per sample. FLAC supports from 4 to 32 bits per sample. Currently the reference encoder and + * decoders only support up to 24 bits per sample. + * + * @return integer + */ + public function getBitsPerSample() + { + return $this->_bitsPerSample; + } + + /** + * Returns total samples in stream. 'Samples' means inter-channel sample, i.e. one second of 44.1Khz audio will + * have 44100 samples regardless of the number of channels. A value of zero here means the number of total samples + * is unknown. + * + * @return integer + */ + public function getNumberOfSamples() + { + return $this->_numberOfSamples; + } + + /** + * Returns MD5 signature of the unencoded audio data. This allows the decoder to determine if an error exists in + * the audio data even when the error does not result in an invalid bitstream. + * + * @return integer + */ + public function getMd5Signature() + { + return $this->_md5Signature; + } +} diff --git a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/VorbisComment.php b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/VorbisComment.php index 3c39159e..67121d0b 100644 --- a/app/libs/vendor/Zend/Media/Flac/MetadataBlock/VorbisComment.php +++ b/app/libs/vendor/Zend/Media/Flac/MetadataBlock/VorbisComment.php @@ -1,155 +1,155 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: VorbisComment.php 251 2011-06-13 15:41:51Z svollbehr $ - */ -final class Zend_Media_Flac_MetadataBlock_VorbisComment extends Zend_Media_Flac_MetadataBlock -{ - /** @var Zend_Media_Vorbis_Header_Comment */ - private $_impl; - - /** - * Constructs the class with given parameters and parses object related data using the vorbis comment implementation - * class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - $this->_impl = new Zend_Media_Vorbis_Header_Comment($this->_reader, array('vorbisContext' => false)); - } - - /** - * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param string $name The method name. - * @param Array $arguments The method arguments. - * @return mixed - */ - public function __call($name, $arguments) - { - if (method_exists($this, $name)) { - return call_user_func(array($this, $name), $arguments); - } - try { - return $this->_impl->$name($arguments); - } catch (Zend_Media_Vorbis_Exception $e) { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } - - /** - * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - if (method_exists($this->_impl, 'get' . ucfirst($name))) { - return call_user_func(array($this->_impl, 'get' . ucfirst($name))); - } - try { - return $this->_impl->__get($name); - } catch (Zend_Media_Vorbis_Exception $e) { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } - - /** - * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param string $name The field name. - * @param string $name The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } else { - try { - return $this->_impl->__set($name, $value); - } catch (Zend_Media_Vorbis_Exception $e) { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } - } - - /** - * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param string $name The field name. - * @return boolean - */ - public function __isset($name) - { - try { - return $this->_impl->__isset($name); - } catch (Zend_Media_Vorbis_Exception $e) { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } - - /** - * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. - * - * @param string $name The field name. - */ - public function __unset($name) - { - try { - $this->_impl->__unset($name); - } catch (Zend_Media_Vorbis_Exception $e) { - require_once 'Zend/Media/Flac/Exception.php'; - throw new Zend_Media_Flac_Exception($e->getMessage()); - } - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: VorbisComment.php 251 2011-06-13 15:41:51Z svollbehr $ + */ +final class Zend_Media_Flac_MetadataBlock_VorbisComment extends Zend_Media_Flac_MetadataBlock +{ + /** @var Zend_Media_Vorbis_Header_Comment */ + private $_impl; + + /** + * Constructs the class with given parameters and parses object related data using the vorbis comment implementation + * class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + $this->_impl = new Zend_Media_Vorbis_Header_Comment($this->_reader, array('vorbisContext' => false)); + } + + /** + * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param string $name The method name. + * @param Array $arguments The method arguments. + * @return mixed + */ + public function __call($name, $arguments) + { + if (method_exists($this, $name)) { + return call_user_func(array($this, $name), $arguments); + } + try { + return $this->_impl->$name($arguments); + } catch (Zend_Media_Vorbis_Exception $e) { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } + + /** + * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + if (method_exists($this->_impl, 'get' . ucfirst($name))) { + return call_user_func(array($this->_impl, 'get' . ucfirst($name))); + } + try { + return $this->_impl->__get($name); + } catch (Zend_Media_Vorbis_Exception $e) { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } + + /** + * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param string $name The field name. + * @param string $name The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } else { + try { + return $this->_impl->__set($name, $value); + } catch (Zend_Media_Vorbis_Exception $e) { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } + } + + /** + * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param string $name The field name. + * @return boolean + */ + public function __isset($name) + { + try { + return $this->_impl->__isset($name); + } catch (Zend_Media_Vorbis_Exception $e) { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } + + /** + * Forward all calls to the vorbis comment implementation class {@link Zend_Media_Vorbis_Header_Comment}. + * + * @param string $name The field name. + */ + public function __unset($name) + { + try { + $this->_impl->__unset($name); + } catch (Zend_Media_Vorbis_Exception $e) { + require_once 'Zend/Media/Flac/Exception.php'; + throw new Zend_Media_Flac_Exception($e->getMessage()); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/DateFrame.php b/app/libs/vendor/Zend/Media/Id3/DateFrame.php index 9e59c9ce..104fedeb 100644 --- a/app/libs/vendor/Zend/Media/Id3/DateFrame.php +++ b/app/libs/vendor/Zend/Media/Id3/DateFrame.php @@ -1,109 +1,109 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: DateFrame.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -abstract class Zend_Media_Id3_DateFrame - extends Zend_Media_Id3_TextFrame -{ - private $_format; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - * @param string $format Rule for formatting output. If null the default - * ISO 8601 date format is used. - */ - public function __construct - ($reader = null, &$options = array(), $format = null) - { - parent::__construct($reader, $options); - $this->_format = $format; - - if ($this->_reader === null) { - return; - } - } - - /** - * Returns the date. - * - * @return Zend_Date - */ - public function getDate() - { - require_once 'Zend/Date.php'; - $date = new Zend_Date(0); - $date->setTimezone('UTC'); - $date->set - ($this->getText(), - $this->_format ? $this->_format : Zend_Date::ISO_8601); - return $date; - } - - /** - * Sets the date. If called with null value the current time is entered. - * - * @param Zend_Date $date The date. - */ - public function setDate($date = null) - { - require_once 'Zend/Date.php'; - if ($date === null) { - $date = Zend_Date::now(); - } - $date->setTimezone('UTC'); - $this->setText($date->toString(Zend_Date::ISO_8601)); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - if ($this->getOption('version', 4) >= 4) { - parent::_writeData($writer); - } else { - $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); - parent::_writeData($writer); - } - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: DateFrame.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +abstract class Zend_Media_Id3_DateFrame + extends Zend_Media_Id3_TextFrame +{ + private $_format; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + * @param string $format Rule for formatting output. If null the default + * ISO 8601 date format is used. + */ + public function __construct + ($reader = null, &$options = array(), $format = null) + { + parent::__construct($reader, $options); + $this->_format = $format; + + if ($this->_reader === null) { + return; + } + } + + /** + * Returns the date. + * + * @return Zend_Date + */ + public function getDate() + { + require_once 'Zend/Date.php'; + $date = new Zend_Date(0); + $date->setTimezone('UTC'); + $date->set + ($this->getText(), + $this->_format ? $this->_format : Zend_Date::ISO_8601); + return $date; + } + + /** + * Sets the date. If called with null value the current time is entered. + * + * @param Zend_Date $date The date. + */ + public function setDate($date = null) + { + require_once 'Zend/Date.php'; + if ($date === null) { + $date = Zend_Date::now(); + } + $date->setTimezone('UTC'); + $this->setText($date->toString(Zend_Date::ISO_8601)); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + if ($this->getOption('version', 4) >= 4) { + parent::_writeData($writer); + } else { + $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); + parent::_writeData($writer); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Encoding.php b/app/libs/vendor/Zend/Media/Id3/Encoding.php index b83b1912..f68bcb3a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Encoding.php +++ b/app/libs/vendor/Zend/Media/Id3/Encoding.php @@ -1,82 +1,82 @@ -Encoding interface implies that the implementing ID3v2 frame - * supports content encoding. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Encoding.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -interface Zend_Media_Id3_Encoding -{ - /** The ISO-8859-1 encoding. */ - const ISO88591 = 0; - - /** The UTF-16 Unicode encoding with BOM. */ - const UTF16 = 1; - - /** The UTF-16LE Unicode encoding without BOM. */ - const UTF16LE = 4; - - /** The UTF-16BE Unicode encoding without BOM. */ - const UTF16BE = 2; - - /** The UTF-8 Unicode encoding. */ - const UTF8 = 3; - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding(); - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding); -} +Encoding interface implies that the implementing ID3v2 frame + * supports content encoding. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Encoding.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +interface Zend_Media_Id3_Encoding +{ + /** The ISO-8859-1 encoding. */ + const ISO88591 = 0; + + /** The UTF-16 Unicode encoding with BOM. */ + const UTF16 = 1; + + /** The UTF-16LE Unicode encoding without BOM. */ + const UTF16LE = 4; + + /** The UTF-16BE Unicode encoding without BOM. */ + const UTF16BE = 2; + + /** The UTF-8 Unicode encoding. */ + const UTF8 = 3; + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding(); + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding); +} diff --git a/app/libs/vendor/Zend/Media/Id3/Exception.php b/app/libs/vendor/Zend/Media/Id3/Exception.php index a2755330..f7372b34 100644 --- a/app/libs/vendor/Zend/Media/Id3/Exception.php +++ b/app/libs/vendor/Zend/Media/Id3/Exception.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Id3_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Id3_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Id3/ExtendedHeader.php b/app/libs/vendor/Zend/Media/Id3/ExtendedHeader.php index 508760e6..2e4c253a 100644 --- a/app/libs/vendor/Zend/Media/Id3/ExtendedHeader.php +++ b/app/libs/vendor/Zend/Media/Id3/ExtendedHeader.php @@ -1,348 +1,348 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ExtendedHeader.php 211 2011-01-12 15:43:48Z svollbehr $ - */ -final class Zend_Media_Id3_ExtendedHeader extends Zend_Media_Id3_Object -{ - /** - * A flag to denote that the present tag is an update of a tag found earlier - * in the present file or stream. If frames defined as unique are found in - * the present tag, they are to override any corresponding ones found in the - * earlier tag. This flag has no corresponding data. - * - * @since ID3v2.4.0 - */ - const UPDATE = 64; - - /** - * @since ID3v2.4.0 A flag to denote that a CRC-32 data is included in the - * extended header. The CRC is calculated on all the data between the header - * and footer as indicated by the header's tag length field, minus the - * extended header. Note that this includes the padding (if there is any), - * but excludes the footer. The CRC-32 is stored as an 35 bit synchsafe - * integer, leaving the upper four bits always zeroed. - * - * @since ID3v2.3.0 The CRC is calculated before unsynchronisation on the - * data between the extended header and the padding, i.e. the frames and - * only the frames. - */ - const CRC32 = 32; - - /** - * A flag to denote whether or not the tag has restrictions applied on it. - * - * @since ID3v2.4.0 - */ - const RESTRICTED = 16; - - /** @var integer */ - private $_size; - - /** @var integer */ - private $_flags = 0; - - /** @var integer */ - private $_padding; - - /** @var integer */ - private $_crc; - - /** @var integer */ - private $_restrictions = 0; - - /** - * Constructs the class with given parameters and reads object related data - * from the ID3v2 tag. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) - return; - - $offset = $this->_reader->getOffset(); - $this->_size = $this->_reader->readUInt32BE(); - - /* ID3v2.3.0 ExtendedHeader */ - if ($this->getOption('version', 4) < 4) { - if ($this->_reader->readUInt16BE() == 0x8000) { - $this->_flags = self::CRC32; - } - $this->_padding = $this->_reader->readUInt32BE(); - if ($this->hasFlag(self::CRC32)) { - $this->_crc = $this->_reader->readUInt32BE(); - } - } - - /* ID3v2.4.0 ExtendedHeader */ - else { - $this->_size = $this->_decodeSynchsafe32($this->_size); - $this->_reader->skip(1); - $this->_flags = $this->_reader->readInt8(); - if ($this->hasFlag(self::UPDATE)) { - $this->_reader->skip(1); - } - if ($this->hasFlag(self::CRC32)) { - $this->_reader->skip(1); - $this->_crc = - $this->_reader->readInt8() * (0xfffffff + 1) + - $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); - } - if ($this->hasFlag(self::RESTRICTED)) { - $this->_reader->skip(1); - $this->_restrictions = $this->_reader->readInt8(); - } - } - } - - /** - * Returns the extended header size in bytes. - * - * @return integer - */ - public function getSize() - { - return $this->_size; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the flags byte. - * - * @return integer - */ - public function getFlags($flags) - { - return $this->_flags; - } - - /** - * Sets the flags byte. - * - * @param integer $flags The flags byte. - */ - public function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Returns the CRC-32 data. - * - * @return integer - */ - public function getCrc() - { - if ($this->hasFlag(self::CRC32)) { - return $this->_crc; - } - return false; - } - - /** - * Sets whether the CRC-32 should be generated upon tag write. - * - * @param boolean $useCrc Whether CRC-32 should be generated. - */ - public function useCrc($useCrc) - { - if ($useCrc) { - $this->setFlags($this->getFlags() | self::CRC32); - } else { - $this->setFlags($this->getFlags() & ~self::CRC32); - } - } - - /** - * Sets the CRC-32. The CRC-32 value is calculated of all the frames in the - * tag and includes padding. - * - * @param integer $crc The 32-bit CRC value. - */ - public function setCrc($crc) - { - if (is_bool($crc)) { - $this->useCrc($crc); - } else { - $this->_crc = $crc; - } - } - - /** - * Returns the restrictions. For some applications it might be desired to - * restrict a tag in more ways than imposed by the ID3v2 specification. Note - * that the presence of these restrictions does not affect how the tag is - * decoded, merely how it was restricted before encoding. If this flag is - * set the tag is restricted as follows: - * - *
    -     * Restrictions %ppqrrstt
    -     *
    -     * p - Tag size restrictions
    -     *
    -     *   00   No more than 128 frames and 1 MB total tag size.
    -     *   01   No more than 64 frames and 128 KB total tag size.
    -     *   10   No more than 32 frames and 40 KB total tag size.
    -     *   11   No more than 32 frames and 4 KB total tag size.
    -     *
    -     * q - Text encoding restrictions
    -     *
    -     *   0    No restrictions
    -     *   1    Strings are only encoded with ISO-8859-1 or UTF-8.
    -     *
    -     * r - Text fields size restrictions
    -     *
    -     *   00   No restrictions
    -     *   01   No string is longer than 1024 characters.
    -     *   10   No string is longer than 128 characters.
    -     *   11   No string is longer than 30 characters.
    -     *
    -     *   Note that nothing is said about how many bytes is used to represent
    -     *   those characters, since it is encoding dependent. If a text frame
    -     *   consists of more than one string, the sum of the strungs is restricted
    -     *   as stated.
    -     *
    -     * s - Image encoding restrictions
    -     *
    -     *   0   No restrictions
    -     *   1   Images are encoded only with PNG [PNG] or JPEG [JFIF].
    -     *
    -     * t - Image size restrictions
    -     *
    -     *   00  No restrictions
    -     *   01  All images are 256x256 pixels or smaller.
    -     *   10  All images are 64x64 pixels or smaller.
    -     *   11  All images are exactly 64x64 pixels, unless required otherwise.
    -     * 
    - * - * @return integer - */ - public function getRestrictions() - { - return $this->_restrictions; - } - - /** - * Sets the restrictions byte. See {@link #getRestrictions} for more. - * - * @param integer $restrictions The restrictions byte. - */ - public function setRestrictions($restrictions) - { - $this->_restrictions = $restrictions; - } - - /** - * Returns the total padding size, or simply the total tag size excluding - * the frames and the headers. - * - * @return integer - * @deprecated ID3v2.3.0 - */ - public function getPadding() - { - return $this->_padding; - } - - /** - * Sets the total padding size, or simply the total tag size excluding the - * frames and the headers. - * - * @param integer $padding The padding size. - * @deprecated ID3v2.3.0 - */ - public function setPadding($padding) - { - return $this->_padding = $padding; - } - - /** - * Writes the header data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - /* ID3v2.3.0 ExtendedHeader */ - if ($this->getOption('version', 4) < 4) { - $writer->writeUInt32BE($this->_size) - ->writeUInt16BE($this->hasFlag(self::CRC32) ? 0x8000 : 0) - ->writeUInt32BE($this->_padding); - if ($this->hasFlag(self::CRC32)) { - $writer->writeUInt32BE($this->_crc); - } - } - - /* ID3v2.4.0 ExtendedHeader */ - else { - $writer->writeUInt32BE($this->_encodeSynchsafe32($this->_size)) - ->writeInt8(1) - ->writeInt8($this->_flags); - if ($this->hasFlag(self::UPDATE)) { - $writer->write("\0"); - } - if ($this->hasFlag(self::CRC32)) { - $writer->writeInt8(5) - ->writeInt8 - ($this->_crc & 0xf0000000 >> 28 & 0xf /*eq >>> 28*/) - ->writeUInt32BE($this->_encodeSynchsafe32($this->_crc)); - } - if ($this->hasFlag(self::RESTRICTED)) { - $writer->writeInt8(1) - ->writeInt8($this->_restrictions); - } - } - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ExtendedHeader.php 211 2011-01-12 15:43:48Z svollbehr $ + */ +final class Zend_Media_Id3_ExtendedHeader extends Zend_Media_Id3_Object +{ + /** + * A flag to denote that the present tag is an update of a tag found earlier + * in the present file or stream. If frames defined as unique are found in + * the present tag, they are to override any corresponding ones found in the + * earlier tag. This flag has no corresponding data. + * + * @since ID3v2.4.0 + */ + const UPDATE = 64; + + /** + * @since ID3v2.4.0 A flag to denote that a CRC-32 data is included in the + * extended header. The CRC is calculated on all the data between the header + * and footer as indicated by the header's tag length field, minus the + * extended header. Note that this includes the padding (if there is any), + * but excludes the footer. The CRC-32 is stored as an 35 bit synchsafe + * integer, leaving the upper four bits always zeroed. + * + * @since ID3v2.3.0 The CRC is calculated before unsynchronisation on the + * data between the extended header and the padding, i.e. the frames and + * only the frames. + */ + const CRC32 = 32; + + /** + * A flag to denote whether or not the tag has restrictions applied on it. + * + * @since ID3v2.4.0 + */ + const RESTRICTED = 16; + + /** @var integer */ + private $_size; + + /** @var integer */ + private $_flags = 0; + + /** @var integer */ + private $_padding; + + /** @var integer */ + private $_crc; + + /** @var integer */ + private $_restrictions = 0; + + /** + * Constructs the class with given parameters and reads object related data + * from the ID3v2 tag. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) + return; + + $offset = $this->_reader->getOffset(); + $this->_size = $this->_reader->readUInt32BE(); + + /* ID3v2.3.0 ExtendedHeader */ + if ($this->getOption('version', 4) < 4) { + if ($this->_reader->readUInt16BE() == 0x8000) { + $this->_flags = self::CRC32; + } + $this->_padding = $this->_reader->readUInt32BE(); + if ($this->hasFlag(self::CRC32)) { + $this->_crc = $this->_reader->readUInt32BE(); + } + } + + /* ID3v2.4.0 ExtendedHeader */ + else { + $this->_size = $this->_decodeSynchsafe32($this->_size); + $this->_reader->skip(1); + $this->_flags = $this->_reader->readInt8(); + if ($this->hasFlag(self::UPDATE)) { + $this->_reader->skip(1); + } + if ($this->hasFlag(self::CRC32)) { + $this->_reader->skip(1); + $this->_crc = + $this->_reader->readInt8() * (0xfffffff + 1) + + $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); + } + if ($this->hasFlag(self::RESTRICTED)) { + $this->_reader->skip(1); + $this->_restrictions = $this->_reader->readInt8(); + } + } + } + + /** + * Returns the extended header size in bytes. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the flags byte. + * + * @return integer + */ + public function getFlags($flags) + { + return $this->_flags; + } + + /** + * Sets the flags byte. + * + * @param integer $flags The flags byte. + */ + public function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Returns the CRC-32 data. + * + * @return integer + */ + public function getCrc() + { + if ($this->hasFlag(self::CRC32)) { + return $this->_crc; + } + return false; + } + + /** + * Sets whether the CRC-32 should be generated upon tag write. + * + * @param boolean $useCrc Whether CRC-32 should be generated. + */ + public function useCrc($useCrc) + { + if ($useCrc) { + $this->setFlags($this->getFlags() | self::CRC32); + } else { + $this->setFlags($this->getFlags() & ~self::CRC32); + } + } + + /** + * Sets the CRC-32. The CRC-32 value is calculated of all the frames in the + * tag and includes padding. + * + * @param integer $crc The 32-bit CRC value. + */ + public function setCrc($crc) + { + if (is_bool($crc)) { + $this->useCrc($crc); + } else { + $this->_crc = $crc; + } + } + + /** + * Returns the restrictions. For some applications it might be desired to + * restrict a tag in more ways than imposed by the ID3v2 specification. Note + * that the presence of these restrictions does not affect how the tag is + * decoded, merely how it was restricted before encoding. If this flag is + * set the tag is restricted as follows: + * + *
    +     * Restrictions %ppqrrstt
    +     *
    +     * p - Tag size restrictions
    +     *
    +     *   00   No more than 128 frames and 1 MB total tag size.
    +     *   01   No more than 64 frames and 128 KB total tag size.
    +     *   10   No more than 32 frames and 40 KB total tag size.
    +     *   11   No more than 32 frames and 4 KB total tag size.
    +     *
    +     * q - Text encoding restrictions
    +     *
    +     *   0    No restrictions
    +     *   1    Strings are only encoded with ISO-8859-1 or UTF-8.
    +     *
    +     * r - Text fields size restrictions
    +     *
    +     *   00   No restrictions
    +     *   01   No string is longer than 1024 characters.
    +     *   10   No string is longer than 128 characters.
    +     *   11   No string is longer than 30 characters.
    +     *
    +     *   Note that nothing is said about how many bytes is used to represent
    +     *   those characters, since it is encoding dependent. If a text frame
    +     *   consists of more than one string, the sum of the strungs is restricted
    +     *   as stated.
    +     *
    +     * s - Image encoding restrictions
    +     *
    +     *   0   No restrictions
    +     *   1   Images are encoded only with PNG [PNG] or JPEG [JFIF].
    +     *
    +     * t - Image size restrictions
    +     *
    +     *   00  No restrictions
    +     *   01  All images are 256x256 pixels or smaller.
    +     *   10  All images are 64x64 pixels or smaller.
    +     *   11  All images are exactly 64x64 pixels, unless required otherwise.
    +     * 
    + * + * @return integer + */ + public function getRestrictions() + { + return $this->_restrictions; + } + + /** + * Sets the restrictions byte. See {@link #getRestrictions} for more. + * + * @param integer $restrictions The restrictions byte. + */ + public function setRestrictions($restrictions) + { + $this->_restrictions = $restrictions; + } + + /** + * Returns the total padding size, or simply the total tag size excluding + * the frames and the headers. + * + * @return integer + * @deprecated ID3v2.3.0 + */ + public function getPadding() + { + return $this->_padding; + } + + /** + * Sets the total padding size, or simply the total tag size excluding the + * frames and the headers. + * + * @param integer $padding The padding size. + * @deprecated ID3v2.3.0 + */ + public function setPadding($padding) + { + return $this->_padding = $padding; + } + + /** + * Writes the header data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + /* ID3v2.3.0 ExtendedHeader */ + if ($this->getOption('version', 4) < 4) { + $writer->writeUInt32BE($this->_size) + ->writeUInt16BE($this->hasFlag(self::CRC32) ? 0x8000 : 0) + ->writeUInt32BE($this->_padding); + if ($this->hasFlag(self::CRC32)) { + $writer->writeUInt32BE($this->_crc); + } + } + + /* ID3v2.4.0 ExtendedHeader */ + else { + $writer->writeUInt32BE($this->_encodeSynchsafe32($this->_size)) + ->writeInt8(1) + ->writeInt8($this->_flags); + if ($this->hasFlag(self::UPDATE)) { + $writer->write("\0"); + } + if ($this->hasFlag(self::CRC32)) { + $writer->writeInt8(5) + ->writeInt8 + ($this->_crc & 0xf0000000 >> 28 & 0xf /*eq >>> 28*/) + ->writeUInt32BE($this->_encodeSynchsafe32($this->_crc)); + } + if ($this->hasFlag(self::RESTRICTED)) { + $writer->writeInt8(1) + ->writeInt8($this->_restrictions); + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame.php b/app/libs/vendor/Zend/Media/Id3/Frame.php index 23ec4490..d71ef84a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame.php @@ -1,327 +1,327 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Frame.php 215 2011-04-30 10:37:09Z svollbehr $ - */ -abstract class Zend_Media_Id3_Frame extends Zend_Media_Id3_Object -{ - /** - * This flag tells the tag parser what to do with this frame if it - * unknown and the tag is altered in any way. This applies to all kinds of - * alterations, including adding more padding and reordering the frames. - */ - const DISCARD_ON_TAGCHANGE = 16384; - - /** - * This flag tells the tag parser what to do with this frame if it is - * unknown and the file, excluding the tag, is altered. This does not apply - * when the audio is completely replaced with other audio data. - */ - const DISCARD_ON_FILECHANGE = 8192; - - /** - * This flag, if set, tells the software that the contents of this frame are - * intended to be read only. Changing the contents might break something, - * e.g. a signature. - */ - const READ_ONLY = 4096; - - /** - * This flag indicates whether or not this frame belongs in a group with - * other frames. If set, a group identifier byte is added to the frame. - * Every frame with the same group identifier belongs to the same group. - */ - const GROUPING_IDENTITY = 32; - - /** - * This flag indicates whether or not the frame is compressed. A Data - * Length Indicator byte is included in the frame. - * - * @see DATA_LENGTH_INDICATOR - */ - const COMPRESSION = 8; - - /** - * This flag indicates whether or not the frame is encrypted. If set, one - * byte indicating with which method it was encrypted will be added to the - * frame. See description of the {@link Zend_Media_Id3_Frame_Encr ENCR} - * frame for more information about encryption method registration. - * Encryption should be done after compression. Whether or not setting this - * flag requires the presence of a Data Length Indicator depends on - * the specific algorithm used. - * - * @see DATA_LENGTH_INDICATOR - */ - const ENCRYPTION = 4; - - /** - * This flag indicates whether or not unsynchronisation was applied to this - * frame. - * - * @since ID3v2.4.0 - */ - const UNSYNCHRONISATION = 2; - - /** - * This flag indicates that a data length indicator has been added to the - * frame. - * - * @since ID3v2.4.0 - */ - const DATA_LENGTH_INDICATOR = 1; - - /** @var integer */ - private $_identifier; - - /** @var integer */ - private $_size = 0; - - /** @var integer */ - private $_flags = 0; - - /** - * Constructs the class with given parameters and reads object related data - * from the ID3v2 tag. - * - * Replaces the reader instance with a string reader object instance that - * can be used to further process the data in the frame sub class. - * - * @todo Only limited subset of flags are processed. - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - $this->_identifier = strtoupper(substr(get_class($this), -4)); - } else { - $this->_identifier = - strtoupper($this->_reader->readString8(4, " ")); - - /* ID3v2.3.0 size and flags; convert flags to 2.4.0 format */ - if ($this->getOption('version', 4) < 4) { - $this->_size = $this->_reader->readUInt32BE(); - $flags = $this->_reader->readUInt16BE(); - if (($flags & 0x8000) == 0x8000) { - $this->_flags |= self::DISCARD_ON_TAGCHANGE; - } - if (($flags & 0x4000) == 0x4000) { - $this->_flags |= self::DISCARD_ON_FILECHANGE; - } - if (($flags & 0x2000) == 0x2000) { - $this->_flags |= self::READ_ONLY; - } - if (($flags & 0x80) == 0x80) { - $this->_flags |= self::COMPRESSION; - } - if (($flags & 0x40) == 0x40) { - $this->_flags |= self::ENCRYPTION; - } - if (($flags & 0x20) == 0x20) { - $this->_flags |= self::GROUPING_IDENTITY; - } - } - - /* ID3v2.4.0 size and flags */ - else { - $this->_size = - $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); - $this->_flags = $this->_reader->readUInt16BE(); - } - - $dataLength = $this->_size; - if ($this->hasFlag(self::DATA_LENGTH_INDICATOR)) { - $dataLength = - $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); - $this->_size -= 4; - } - - $data = $this->_reader->read($this->_size); - $this->_size = $dataLength; - - if ($this->hasFlag(self::UNSYNCHRONISATION) || - $this->getOption('unsynchronisation', false) === true) { - $data = $this->_decodeUnsynchronisation($data); - } - - $this->_reader = new Zend_Io_StringReader($data); - } - } - - /** - * Returns the frame identifier string. - * - * @return string - */ - public final function getIdentifier() - { - return $this->_identifier; - } - - /** - * Sets the frame identifier. - * - * @param string $identifier The identifier. - */ - public final function setIdentifier($identifier) - { - $this->_identifier = $identifier; - } - - /** - * Returns the size of the data in the final frame, after encryption, - * compression and unsynchronisation. The size is excluding the frame - * header. - * - * @return integer - */ - public final function getSize() - { - return $this->_size; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public final function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the frame flags byte. - * - * @return integer - */ - public final function getFlags($flags) - { - return $this->_flags; - } - - /** - * Sets the frame flags byte. - * - * @param string $flags The flags byte. - */ - public final function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - abstract protected function _writeData($writer); - - /** - * Writes the frame data with the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - /* ID3v2.3.0 Flags; convert from 2.4.0 format */ - if ($this->getOption('version', 4) < 4) { - $flags = 0; - if ($this->hasFlag(self::DISCARD_ON_TAGCHANGE)) { - $flags = $flags | 0x8000; - } - if ($this->hasFlag(self::DISCARD_ON_FILECHANGE)) { - $flags = $flags | 0x4000; - } - if ($this->hasFlag(self::READ_ONLY)) { - $flags = $flags | 0x2000; - } - if ($this->hasFlag(self::COMPRESSION)) { - $flags = $flags | 0x80; - } - if ($this->hasFlag(self::ENCRYPTION)) { - $flags = $flags | 0x40; - } - if ($this->hasFlag(self::GROUPING_IDENTITY)) { - $flags = $flags | 0x20; - } - } - - /* ID3v2.4.0 Flags */ - else { - $flags = $this->_flags; - } - - $this->_writeData($buffer = new Zend_Io_StringWriter()); - $data = $buffer->toString(); - $size = $this->_size = strlen($data); - - // ID3v2.4.0 supports frame level unsynchronisation. The corresponding - // option is set to true when any of the frames use the - // unsynchronisation scheme. The usage is denoted by - // Zend_Media_Id3_Header flag that is set accordingly upon file write. - if ($this->getOption('version', 4) >= 4) { - $data = $this->_encodeUnsynchronisation($data); - if (($dataLength = strlen($data)) != $size) { - $size = 4 + $dataLength; - $flags |= self::DATA_LENGTH_INDICATOR | self::UNSYNCHRONISATION; - $this->setOption('unsynchronisation', true); - } else { - $flags &= ~(self::DATA_LENGTH_INDICATOR | - self::UNSYNCHRONISATION); - } - } - - $writer->writeString8(substr($this->_identifier, 0, 4), 4, " ") - ->writeUInt32BE($this->getOption('version', 4) < 4 ? $size : $this->_encodeSynchsafe32($size)) - ->writeUInt16BE($flags); - - if (($flags & self::DATA_LENGTH_INDICATOR) == - self::DATA_LENGTH_INDICATOR) { - $writer->writeUInt32BE - ($this->getOption('version', 4) < 4 ? $this->_size : $this->_encodeSynchsafe32($this->_size)); - } - $writer->write($data); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Frame.php 215 2011-04-30 10:37:09Z svollbehr $ + */ +abstract class Zend_Media_Id3_Frame extends Zend_Media_Id3_Object +{ + /** + * This flag tells the tag parser what to do with this frame if it + * unknown and the tag is altered in any way. This applies to all kinds of + * alterations, including adding more padding and reordering the frames. + */ + const DISCARD_ON_TAGCHANGE = 16384; + + /** + * This flag tells the tag parser what to do with this frame if it is + * unknown and the file, excluding the tag, is altered. This does not apply + * when the audio is completely replaced with other audio data. + */ + const DISCARD_ON_FILECHANGE = 8192; + + /** + * This flag, if set, tells the software that the contents of this frame are + * intended to be read only. Changing the contents might break something, + * e.g. a signature. + */ + const READ_ONLY = 4096; + + /** + * This flag indicates whether or not this frame belongs in a group with + * other frames. If set, a group identifier byte is added to the frame. + * Every frame with the same group identifier belongs to the same group. + */ + const GROUPING_IDENTITY = 32; + + /** + * This flag indicates whether or not the frame is compressed. A Data + * Length Indicator byte is included in the frame. + * + * @see DATA_LENGTH_INDICATOR + */ + const COMPRESSION = 8; + + /** + * This flag indicates whether or not the frame is encrypted. If set, one + * byte indicating with which method it was encrypted will be added to the + * frame. See description of the {@link Zend_Media_Id3_Frame_Encr ENCR} + * frame for more information about encryption method registration. + * Encryption should be done after compression. Whether or not setting this + * flag requires the presence of a Data Length Indicator depends on + * the specific algorithm used. + * + * @see DATA_LENGTH_INDICATOR + */ + const ENCRYPTION = 4; + + /** + * This flag indicates whether or not unsynchronisation was applied to this + * frame. + * + * @since ID3v2.4.0 + */ + const UNSYNCHRONISATION = 2; + + /** + * This flag indicates that a data length indicator has been added to the + * frame. + * + * @since ID3v2.4.0 + */ + const DATA_LENGTH_INDICATOR = 1; + + /** @var integer */ + private $_identifier; + + /** @var integer */ + private $_size = 0; + + /** @var integer */ + private $_flags = 0; + + /** + * Constructs the class with given parameters and reads object related data + * from the ID3v2 tag. + * + * Replaces the reader instance with a string reader object instance that + * can be used to further process the data in the frame sub class. + * + * @todo Only limited subset of flags are processed. + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + $this->_identifier = strtoupper(substr(get_class($this), -4)); + } else { + $this->_identifier = + strtoupper($this->_reader->readString8(4, " ")); + + /* ID3v2.3.0 size and flags; convert flags to 2.4.0 format */ + if ($this->getOption('version', 4) < 4) { + $this->_size = $this->_reader->readUInt32BE(); + $flags = $this->_reader->readUInt16BE(); + if (($flags & 0x8000) == 0x8000) { + $this->_flags |= self::DISCARD_ON_TAGCHANGE; + } + if (($flags & 0x4000) == 0x4000) { + $this->_flags |= self::DISCARD_ON_FILECHANGE; + } + if (($flags & 0x2000) == 0x2000) { + $this->_flags |= self::READ_ONLY; + } + if (($flags & 0x80) == 0x80) { + $this->_flags |= self::COMPRESSION; + } + if (($flags & 0x40) == 0x40) { + $this->_flags |= self::ENCRYPTION; + } + if (($flags & 0x20) == 0x20) { + $this->_flags |= self::GROUPING_IDENTITY; + } + } + + /* ID3v2.4.0 size and flags */ + else { + $this->_size = + $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); + $this->_flags = $this->_reader->readUInt16BE(); + } + + $dataLength = $this->_size; + if ($this->hasFlag(self::DATA_LENGTH_INDICATOR)) { + $dataLength = + $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); + $this->_size -= 4; + } + + $data = $this->_reader->read($this->_size); + $this->_size = $dataLength; + + if ($this->hasFlag(self::UNSYNCHRONISATION) || + $this->getOption('unsynchronisation', false) === true) { + $data = $this->_decodeUnsynchronisation($data); + } + + $this->_reader = new Zend_Io_StringReader($data); + } + } + + /** + * Returns the frame identifier string. + * + * @return string + */ + public final function getIdentifier() + { + return $this->_identifier; + } + + /** + * Sets the frame identifier. + * + * @param string $identifier The identifier. + */ + public final function setIdentifier($identifier) + { + $this->_identifier = $identifier; + } + + /** + * Returns the size of the data in the final frame, after encryption, + * compression and unsynchronisation. The size is excluding the frame + * header. + * + * @return integer + */ + public final function getSize() + { + return $this->_size; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public final function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the frame flags byte. + * + * @return integer + */ + public final function getFlags($flags) + { + return $this->_flags; + } + + /** + * Sets the frame flags byte. + * + * @param string $flags The flags byte. + */ + public final function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + abstract protected function _writeData($writer); + + /** + * Writes the frame data with the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + /* ID3v2.3.0 Flags; convert from 2.4.0 format */ + if ($this->getOption('version', 4) < 4) { + $flags = 0; + if ($this->hasFlag(self::DISCARD_ON_TAGCHANGE)) { + $flags = $flags | 0x8000; + } + if ($this->hasFlag(self::DISCARD_ON_FILECHANGE)) { + $flags = $flags | 0x4000; + } + if ($this->hasFlag(self::READ_ONLY)) { + $flags = $flags | 0x2000; + } + if ($this->hasFlag(self::COMPRESSION)) { + $flags = $flags | 0x80; + } + if ($this->hasFlag(self::ENCRYPTION)) { + $flags = $flags | 0x40; + } + if ($this->hasFlag(self::GROUPING_IDENTITY)) { + $flags = $flags | 0x20; + } + } + + /* ID3v2.4.0 Flags */ + else { + $flags = $this->_flags; + } + + $this->_writeData($buffer = new Zend_Io_StringWriter()); + $data = $buffer->toString(); + $size = $this->_size = strlen($data); + + // ID3v2.4.0 supports frame level unsynchronisation. The corresponding + // option is set to true when any of the frames use the + // unsynchronisation scheme. The usage is denoted by + // Zend_Media_Id3_Header flag that is set accordingly upon file write. + if ($this->getOption('version', 4) >= 4) { + $data = $this->_encodeUnsynchronisation($data); + if (($dataLength = strlen($data)) != $size) { + $size = 4 + $dataLength; + $flags |= self::DATA_LENGTH_INDICATOR | self::UNSYNCHRONISATION; + $this->setOption('unsynchronisation', true); + } else { + $flags &= ~(self::DATA_LENGTH_INDICATOR | + self::UNSYNCHRONISATION); + } + } + + $writer->writeString8(substr($this->_identifier, 0, 4), 4, " ") + ->writeUInt32BE($this->getOption('version', 4) < 4 ? $size : $this->_encodeSynchsafe32($size)) + ->writeUInt16BE($flags); + + if (($flags & self::DATA_LENGTH_INDICATOR) == + self::DATA_LENGTH_INDICATOR) { + $writer->writeUInt32BE + ($this->getOption('version', 4) < 4 ? $this->_size : $this->_encodeSynchsafe32($this->_size)); + } + $writer->write($data); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Aenc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Aenc.php index 565c43bc..0764b3dd 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Aenc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Aenc.php @@ -1,178 +1,178 @@ -Audio encryption indicates if the actual audio stream is - * encrypted, and by whom. - * - * The identifier is a URL containing an email address, or a link to a location - * where an email address can be found, that belongs to the organisation - * responsible for this specific encrypted audio file. Questions regarding the - * encrypted audio should be sent to the email address specified. There may be - * more than one AENC frame in a tag, but only one with the same owner - * identifier. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Aenc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Aenc extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var integer */ - private $_previewStart; - - /** @var integer */ - private $_previewLength; - - /** @var string */ - private $_encryptionInfo; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list($this->_owner) = $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(strlen($this->_owner) + 1); - $this->_previewStart = $this->_reader->readUInt16BE(); - $this->_previewLength = $this->_reader->readUInt16BE(); - $this->_encryptionInfo = - $this->_reader->read($this->_reader->getSize()); - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - $this->_owner = $owner; - } - - /** - * Returns the pointer to an unencrypted part of the audio in frames. - * - * @return integer - */ - public function getPreviewStart() - { - return $this->_previewStart; - } - - /** - * Sets the pointer to an unencrypted part of the audio in frames. - * - * @param integer $previewStart The pointer to an unencrypted part. - */ - public function setPreviewStart($previewStart) - { - $this->_previewStart = $previewStart; - } - - /** - * Returns the length of the preview in frames. - * - * @return integer - */ - public function getPreviewLength() - { - return $this->_previewLength; - } - - /** - * Sets the length of the preview in frames. - * - * @param integer $previewLength The length of the preview. - */ - public function setPreviewLength($previewLength) - { - $this->_previewLength = $previewLength; - } - - /** - * Returns the encryption info. - * - * @return string - */ - public function getEncryptionInfo() - { - return $this->_encryptionInfo; - } - - /** - * Sets the encryption info binary string. - * - * @param string $encryptionInfo The data string. - */ - public function setEncryptionInfo($encryptionInfo) - { - $this->_encryptionInfo = $encryptionInfo; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->writeUInt16BE($this->_previewStart) - ->writeUInt16BE($this->_previewLength) - ->write($this->_encryptionInfo); - } -} +Audio encryption indicates if the actual audio stream is + * encrypted, and by whom. + * + * The identifier is a URL containing an email address, or a link to a location + * where an email address can be found, that belongs to the organisation + * responsible for this specific encrypted audio file. Questions regarding the + * encrypted audio should be sent to the email address specified. There may be + * more than one AENC frame in a tag, but only one with the same owner + * identifier. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Aenc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Aenc extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var integer */ + private $_previewStart; + + /** @var integer */ + private $_previewLength; + + /** @var string */ + private $_encryptionInfo; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list($this->_owner) = $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(strlen($this->_owner) + 1); + $this->_previewStart = $this->_reader->readUInt16BE(); + $this->_previewLength = $this->_reader->readUInt16BE(); + $this->_encryptionInfo = + $this->_reader->read($this->_reader->getSize()); + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + $this->_owner = $owner; + } + + /** + * Returns the pointer to an unencrypted part of the audio in frames. + * + * @return integer + */ + public function getPreviewStart() + { + return $this->_previewStart; + } + + /** + * Sets the pointer to an unencrypted part of the audio in frames. + * + * @param integer $previewStart The pointer to an unencrypted part. + */ + public function setPreviewStart($previewStart) + { + $this->_previewStart = $previewStart; + } + + /** + * Returns the length of the preview in frames. + * + * @return integer + */ + public function getPreviewLength() + { + return $this->_previewLength; + } + + /** + * Sets the length of the preview in frames. + * + * @param integer $previewLength The length of the preview. + */ + public function setPreviewLength($previewLength) + { + $this->_previewLength = $previewLength; + } + + /** + * Returns the encryption info. + * + * @return string + */ + public function getEncryptionInfo() + { + return $this->_encryptionInfo; + } + + /** + * Sets the encryption info binary string. + * + * @param string $encryptionInfo The data string. + */ + public function setEncryptionInfo($encryptionInfo) + { + $this->_encryptionInfo = $encryptionInfo; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->writeUInt16BE($this->_previewStart) + ->writeUInt16BE($this->_previewLength) + ->write($this->_encryptionInfo); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Apic.php b/app/libs/vendor/Zend/Media/Id3/Frame/Apic.php index a63696de..bababc3d 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Apic.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Apic.php @@ -1,290 +1,290 @@ -Attached picture frame contains a picture directly related to the - * audio file. Image format is the MIME type and subtype for the image. - * - * There may be several pictures attached to one file, each in their individual - * APIC frame, but only one with the same content descriptor. There may only - * be one picture with the same picture type. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Apic.php 241 2011-06-11 16:46:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Apic extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** - * The list of image types. - * - * @var Array - */ - public static $types = array - ('Other', '32x32 pixels file icon (PNG only)', 'Other file icon', - 'Cover (front)', 'Cover (back)', 'Leaflet page', - 'Media (e.g. label side of CD)', 'Lead artist/lead performer/soloist', - 'Artist/performer', 'Conductor', 'Band/Orchestra', 'Composer', - 'Lyricist/text writer', 'Recording Location', 'During recording', - 'During performance', 'Movie/video screen capture', - 'A bright coloured fish', 'Illustration', 'Band/artist logotype', - 'Publisher/Studio logotype'); - - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_mimeType = 'image/unknown'; - - /** @var integer */ - private $_imageType = 0; - - /** @var string */ - private $_description; - - /** @var string */ - private $_imageData; - - /** @var integer */ - private $_imageSize = 0; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @todo There is the possibility to put only a link to the image file by - * using the MIME type '-->' and having a complete URL instead of picture - * data. Support for such needs further design considerations. - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - list($this->_mimeType) = $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(1 + strlen($this->_mimeType) + 1); - $this->_imageType = $this->_reader->readUInt8(); - - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list ($this->_description, $this->_imageData) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - break; - case self::UTF8: - // break intentionally omitted - default: - list ($this->_description, $this->_imageData) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - break; - } - $this->_description = - $this->_convertString($this->_description, $encoding); - $this->_imageSize = strlen($this->_imageData); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the MIME type. The MIME type is always ISO-8859-1 encoded. - * - * @return string - */ - public function getMimeType() - { - return $this->_mimeType; - } - - /** - * Sets the MIME type. The MIME type is always ISO-8859-1 encoded. - * - * @param string $mimeType The MIME type. - */ - public function setMimeType($mimeType) - { - $this->_mimeType = $mimeType; - } - - /** - * Returns the image type. - * - * @return integer - */ - public function getImageType() - { - return $this->_imageType; - } - - /** - * Sets the image type code. - * - * @param integer $imageType The image type code. - */ - public function setImageType($imageType) - { - $this->_imageType = $imageType; - } - - /** - * Returns the file description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. - * - * @param string $description The content description text. - * @param integer $encoding The text encoding. - */ - public function setDescription($description, $encoding = null) - { - $this->_description = $description; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Returns the embedded image data. - * - * @return string - */ - public function getImageData() - { - return $this->_imageData; - } - - /** - * Sets the embedded image data. Also updates the image size field to - * correspond the new data. - * - * @param string $imageData The image data. - */ - public function setImageData($imageData) - { - $this->_imageData = $imageData; - $this->_imageSize = strlen($imageData); - } - - /** - * Returns the size of the embedded image data. - * - * @return integer - */ - public function getImageSize() - { - return $this->_imageSize; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->writeString8($this->_mimeType, 1) - ->writeUInt8($this->_imageType); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1); - break; - default: - $writer->writeString8($this->_description, 1); - break; - } - $writer->write($this->_imageData); - } -} +Attached picture frame contains a picture directly related to the + * audio file. Image format is the MIME type and subtype for the image. + * + * There may be several pictures attached to one file, each in their individual + * APIC frame, but only one with the same content descriptor. There may only + * be one picture with the same picture type. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Apic.php 241 2011-06-11 16:46:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Apic extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** + * The list of image types. + * + * @var Array + */ + public static $types = array + ('Other', '32x32 pixels file icon (PNG only)', 'Other file icon', + 'Cover (front)', 'Cover (back)', 'Leaflet page', + 'Media (e.g. label side of CD)', 'Lead artist/lead performer/soloist', + 'Artist/performer', 'Conductor', 'Band/Orchestra', 'Composer', + 'Lyricist/text writer', 'Recording Location', 'During recording', + 'During performance', 'Movie/video screen capture', + 'A bright coloured fish', 'Illustration', 'Band/artist logotype', + 'Publisher/Studio logotype'); + + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_mimeType = 'image/unknown'; + + /** @var integer */ + private $_imageType = 0; + + /** @var string */ + private $_description; + + /** @var string */ + private $_imageData; + + /** @var integer */ + private $_imageSize = 0; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @todo There is the possibility to put only a link to the image file by + * using the MIME type '-->' and having a complete URL instead of picture + * data. Support for such needs further design considerations. + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + list($this->_mimeType) = $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(1 + strlen($this->_mimeType) + 1); + $this->_imageType = $this->_reader->readUInt8(); + + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list ($this->_description, $this->_imageData) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + break; + case self::UTF8: + // break intentionally omitted + default: + list ($this->_description, $this->_imageData) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + break; + } + $this->_description = + $this->_convertString($this->_description, $encoding); + $this->_imageSize = strlen($this->_imageData); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the MIME type. The MIME type is always ISO-8859-1 encoded. + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Sets the MIME type. The MIME type is always ISO-8859-1 encoded. + * + * @param string $mimeType The MIME type. + */ + public function setMimeType($mimeType) + { + $this->_mimeType = $mimeType; + } + + /** + * Returns the image type. + * + * @return integer + */ + public function getImageType() + { + return $this->_imageType; + } + + /** + * Sets the image type code. + * + * @param integer $imageType The image type code. + */ + public function setImageType($imageType) + { + $this->_imageType = $imageType; + } + + /** + * Returns the file description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. + * + * @param string $description The content description text. + * @param integer $encoding The text encoding. + */ + public function setDescription($description, $encoding = null) + { + $this->_description = $description; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Returns the embedded image data. + * + * @return string + */ + public function getImageData() + { + return $this->_imageData; + } + + /** + * Sets the embedded image data. Also updates the image size field to + * correspond the new data. + * + * @param string $imageData The image data. + */ + public function setImageData($imageData) + { + $this->_imageData = $imageData; + $this->_imageSize = strlen($imageData); + } + + /** + * Returns the size of the embedded image data. + * + * @return integer + */ + public function getImageSize() + { + return $this->_imageSize; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->writeString8($this->_mimeType, 1) + ->writeUInt8($this->_imageType); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1); + break; + default: + $writer->writeString8($this->_description, 1); + break; + } + $writer->write($this->_imageData); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Aspi.php b/app/libs/vendor/Zend/Media/Id3/Frame/Aspi.php index e45a062e..c1561a8e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Aspi.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Aspi.php @@ -1,160 +1,160 @@ -Audio seek point index or - * ASPI frame makes seeking easier by providing a list a seek points within the - * audio file. The seek points are a fractional offset within the audio data, - * providing a starting point from which to find an appropriate point to start - * decoding. The presence of an ASPI frame requires the existence of a - * {@link Zend_Media_Id3_Frame_Tlen TLEN} frame, indicating the duration of the - * file in milliseconds. There may only be one audio seek point index frame in - * a tag. - * - * @todo Data parsing and write support - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Aspi.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Aspi extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_dataStart; - - /** @var integer */ - private $_dataLength; - - /** @var integer */ - private $_size; - - /** @var Array */ - private $_fractions = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Write not supported yet'); - } - - $this->_dataStart = $this->_reader->readInt32BE(); - $this->_dataLength = $this->_reader->readInt32BE(); - $this->_size = $this->_reader->readInt16BE(); - - $bitsPerPoint = $this->_reader->readInt8($this->_data[10]); - /*for ($i = 0, $offset = 11; $i < $this->_size; $i++) { - if ($bitsPerPoint == 16) { - $this->_fractions[$i] = substr($this->_data, $offset, 2); - $offset += 2; - } else { - $this->_fractions[$i] = substr($this->_data, $offset, 1); - $offset ++; - } - }*/ - } - - /** - * Returns the byte offset from the beginning of the file. - * - * @return integer - */ - public function getDataStart() - { - return $this->_dataStart; - } - - /** - * Sets the byte offset from the beginning of the file. - * - * @param integer $dataStart The offset. - */ - public function setDataStart($dataStart) - { - $this->_dataStart = $dataStart; - } - - /** - * Returns the byte length of the audio data being indexed. - * - * @return integer - */ - public function getDataLength() - { - return $this->_dataLength; - } - - /** - * Sets the byte length of the audio data being indexed. - * - * @param integer $dataLength The length. - */ - public function setDataLength($dataLength) - { - $this->_dataLength = $dataLength; - } - - /** - * Returns the number of index points in the frame. - * - * @return integer - */ - public function getSize() - { - return count($this->_fractions); - } - - /** - * Returns the numerator of the fraction representing a relative position in - * the data or false if index not defined. The denominator is 2 - * to the power of b. - * - * @param integer $index The fraction numerator. - * @return integer - */ - public function getFractionAt($index) - { - if (isset($this->_fractions[$index])) { - return $this->_fractions[$index]; - } - return false; - } -} +Audio seek point index or + * ASPI frame makes seeking easier by providing a list a seek points within the + * audio file. The seek points are a fractional offset within the audio data, + * providing a starting point from which to find an appropriate point to start + * decoding. The presence of an ASPI frame requires the existence of a + * {@link Zend_Media_Id3_Frame_Tlen TLEN} frame, indicating the duration of the + * file in milliseconds. There may only be one audio seek point index frame in + * a tag. + * + * @todo Data parsing and write support + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Aspi.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Aspi extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_dataStart; + + /** @var integer */ + private $_dataLength; + + /** @var integer */ + private $_size; + + /** @var Array */ + private $_fractions = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Write not supported yet'); + } + + $this->_dataStart = $this->_reader->readInt32BE(); + $this->_dataLength = $this->_reader->readInt32BE(); + $this->_size = $this->_reader->readInt16BE(); + + $bitsPerPoint = $this->_reader->readInt8($this->_data[10]); + /*for ($i = 0, $offset = 11; $i < $this->_size; $i++) { + if ($bitsPerPoint == 16) { + $this->_fractions[$i] = substr($this->_data, $offset, 2); + $offset += 2; + } else { + $this->_fractions[$i] = substr($this->_data, $offset, 1); + $offset ++; + } + }*/ + } + + /** + * Returns the byte offset from the beginning of the file. + * + * @return integer + */ + public function getDataStart() + { + return $this->_dataStart; + } + + /** + * Sets the byte offset from the beginning of the file. + * + * @param integer $dataStart The offset. + */ + public function setDataStart($dataStart) + { + $this->_dataStart = $dataStart; + } + + /** + * Returns the byte length of the audio data being indexed. + * + * @return integer + */ + public function getDataLength() + { + return $this->_dataLength; + } + + /** + * Sets the byte length of the audio data being indexed. + * + * @param integer $dataLength The length. + */ + public function setDataLength($dataLength) + { + $this->_dataLength = $dataLength; + } + + /** + * Returns the number of index points in the frame. + * + * @return integer + */ + public function getSize() + { + return count($this->_fractions); + } + + /** + * Returns the numerator of the fraction representing a relative position in + * the data or false if index not defined. The denominator is 2 + * to the power of b. + * + * @param integer $index The fraction numerator. + * @return integer + */ + public function getFractionAt($index) + { + if (isset($this->_fractions[$index])) { + return $this->_fractions[$index]; + } + return false; + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Comm.php b/app/libs/vendor/Zend/Media/Id3/Frame/Comm.php index 235cfc9a..94c9d085 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Comm.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Comm.php @@ -1,155 +1,155 @@ -Comments frame is intended for any kind of full text information - * that does not fit in any other frame. It consists of a frame header followed - * by encoding, language and content descriptors and is ended with the actual - * comment as a text string. Newline characters are allowed in the comment text - * string. There may be more than one comment frame in each tag, but only one - * with the same language and content descriptor. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Comm.php 255 2012-01-21 19:46:18Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Comm extends Zend_Media_Id3_LanguageTextFrame -{ - /** @var string */ - private $_description; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - Zend_Media_Id3_Frame::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_language = strtolower($this->_reader->read(3)); - if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { - $this->_language = 'und'; - } - - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($this->_description, $this->_text) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_description = - $this->_convertString($this->_description, $encoding); - $this->_text = - $this->_convertString($this->_text, $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - list($this->_description, $this->_text) = $this->_convertString - ($this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2), - $encoding); - break; - } - } - - /** - * Returns the short content description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. The description - * language and encoding must be that of the actual text. - * - * @param string $description The content description text. - * @param string $language The language code. - * @param integer $encoding The text encoding. - */ - public function setDescription - ($description, $language = null, $encoding = null) - { - $this->_description = $description; - if ($language !== null) { - $this->setLanguage($language); - } - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_language); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) - ->writeString16 - ($this->_text,Zend_Io_Writer::LITTLE_ENDIAN_ORDER); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1) - ->writeString16($this->_text); - break; - default: - $writer->writeString8($this->_description, 1) - ->writeString8($this->_text); - break; - } - } -} +Comments frame is intended for any kind of full text information + * that does not fit in any other frame. It consists of a frame header followed + * by encoding, language and content descriptors and is ended with the actual + * comment as a text string. Newline characters are allowed in the comment text + * string. There may be more than one comment frame in each tag, but only one + * with the same language and content descriptor. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Comm.php 255 2012-01-21 19:46:18Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Comm extends Zend_Media_Id3_LanguageTextFrame +{ + /** @var string */ + private $_description; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + Zend_Media_Id3_Frame::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_language = strtolower($this->_reader->read(3)); + if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { + $this->_language = 'und'; + } + + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($this->_description, $this->_text) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_description = + $this->_convertString($this->_description, $encoding); + $this->_text = + $this->_convertString($this->_text, $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + list($this->_description, $this->_text) = $this->_convertString + ($this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2), + $encoding); + break; + } + } + + /** + * Returns the short content description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. The description + * language and encoding must be that of the actual text. + * + * @param string $description The content description text. + * @param string $language The language code. + * @param integer $encoding The text encoding. + */ + public function setDescription + ($description, $language = null, $encoding = null) + { + $this->_description = $description; + if ($language !== null) { + $this->setLanguage($language); + } + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_language); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) + ->writeString16 + ($this->_text,Zend_Io_Writer::LITTLE_ENDIAN_ORDER); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1) + ->writeString16($this->_text); + break; + default: + $writer->writeString8($this->_description, 1) + ->writeString8($this->_text); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Comr.php b/app/libs/vendor/Zend/Media/Id3/Frame/Comr.php index a94811fd..7e2d4b39 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Comr.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Comr.php @@ -1,490 +1,490 @@ -Commercial frame enables several competing offers in the same tag - * by bundling all needed information. That makes this frame rather complex but - * it's an easier solution than if one tries to achieve the same result with - * several frames. - * - * There may be more than one commercial frame in a tag, but no two may be - * identical. - * - * @todo The use of Zend_Currency requires design considerations. - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Comr.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Comr extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** - * The delivery types. - * - * @var Array - */ - public static $types = array - ('Other', 'Standard CD album with other songs', - 'Compressed audio on CD', 'File over the Internet', - 'Stream over the Internet', 'As note sheets', - 'As note sheets in a book with other sheets', 'Music on other media', - 'Non-musical merchandise'); - - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_currency = 'EUR'; - - /** @var string */ - private $_price; - - /** @var string */ - private $_date; - - /** @var string */ - private $_contact; - - /** @var integer */ - private $_delivery = 0; - - /** @var string */ - private $_seller; - - /** @var string */ - private $_description; - - /** @var string */ - private $_mimeType = false; - - /** @var string */ - private $_imageData; - - /** @var integer */ - private $_imageSize = 0; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_currency = strtoupper($this->_reader->read(3)); - $offset = $this->_reader->getOffset(); - list ($this->_price) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset($offset + strlen($this->_price) + 1); - $this->_date = $this->_reader->read(8); - $offset = $this->_reader->getOffset(); - list($this->_contact) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset($offset + strlen($this->_contact) + 1); - $this->_delivery = $this->_reader->readUInt8(); - $offset = $this->_reader->getOffset(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list ($this->_seller, $this->_description) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 3); - $this->_reader->setOffset - ($offset + strlen($this->_seller) + - strlen($this->_description) + 4); - break; - case self::UTF8: - // break intentionally omitted - default: - list ($this->_seller, $this->_description) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 3); - $this->_reader->setOffset - ($offset + strlen($this->_seller) + - strlen($this->_description) + 2); - break; - } - $this->_seller = $this->_convertString($this->_seller, $encoding); - $this->_description = $this->_convertString($this->_description, $encoding); - - if (!$this->_reader->available()) - return; - - list($this->_mimeType, $this->_imageData) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_imageSize = strlen($this->_imageData); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the currency code, encoded according to - * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm - * ISO 4217} alphabetic currency code. - * - * @return string - */ - public function getCurrency() - { - return $this->_currency; - } - - /** - * Sets the currency used in transaction, encoded according to - * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm - * ISO 4217} alphabetic currency code. - * - * @param string $currency The currency code. - */ - public function setCurrency($currency) - { - $this->_currency = strtoupper($currency); - } - - /** - * Returns the first price. - * - * @return double - */ - public function getPrice() - { - $array = explode('/', $this->_price); - return doubleval($array[0]); - } - - /** - * Returns the price array. - * - * @return Array - */ - public function getPrices() - { - $array = explode('/', $this->_price); - foreach ($array as $key => $value) { - $array[$key] = doubleval($value); - } - return $array; - } - - /** - * Sets the default price. Multiple prices can be given in the form of an - * array but there may only be one currency of each type. - * - * @param double $price The price. - */ - public function setPrice($price) - { - $this->setPrices($price); - } - - /** - * Sets the default price. Multiple prices can be given in the form of an - * array but there may only be one currency of each type. - * - * @param double|Array $prices The prices. - */ - public function setPrices($prices) - { - if (!is_array($prices)) { - $prices = array($prices); - } - $this->_price = implode('/', $prices); - } - - /** - * Returns the date describing for how long the price is valid. - * - * @internal The ID3v2 standard does not declare the time zone to be used - * in the date. Date must thus be expressed as GMT/UTC. - * @return Zend_Date - */ - public function getDate() - { - require_once 'Zend/Date.php'; - $date = new Zend_Date(0); - $date->setTimezone('UTC'); - $date->set($this->_date, 'yyyyMMdd'); - return $date; - } - - /** - * Sets the date describing for how long the price is valid for. - * - * @internal The ID3v2 standard does not declare the time zone to be used - * in the date. Date must thus be expressed as GMT/UTC. - * @param Zend_Date $date The date. - */ - public function setDate($date) - { - require_once 'Zend/Date.php'; - if ($date === null) { - $date = Zend_Date::now(); - } - $date->setTimezone('UTC'); - $this->_date = $date->toString('yyyyMMdd'); - } - - /** - * Returns the contact URL, with which the user can contact the seller. - * - * @return string - */ - public function getContact() - { - return $this->_contact; - } - - /** - * Sets the contact URL, with which the user can contact the seller. - * - * @param string $contact The contact URL. - */ - public function setContact($contact) - { - $this->_contact = $contact; - } - - /** - * Returns the delivery type with whitch the audio was delivered when - * bought. - * - * @return integer - */ - public function getDelivery() - { - return $this->_delivery; - } - - /** - * Sets the delivery type with whitch the audio was delivered when bought. - * - * @param integer $delivery The delivery type code. - */ - public function setDelivery($delivery) - { - $this->_delivery = $delivery; - } - - /** - * Returns the name of the seller. - * - * @return string - */ - public function getSeller() - { - return $this->_seller; - } - - /** - * Sets the name of the seller using given encoding. The seller text - * encoding must be that of the description text. - * - * @param string $seller The name of the seller. - * @param integer $encoding The text encoding. - */ - public function setSeller($seller, $encoding = null) - { - $this->_seller = $seller; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Returns the short description of the product. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. The description - * encoding must be that of the seller text. - * - * @param string $description The content description text. - * @param integer $encoding The text encoding. - */ - public function setDescription($description, $encoding = null) - { - $this->_description = $description; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Returns the MIME type of the seller's company logo, if attached, or - * false otherwise. Currently only 'image/png' and 'image/jpeg' - * are allowed. - * - * @return string - */ - public function getMimeType() - { - return $this->_mimeType; - } - - /** - * Sets the MIME type. Currently only 'image/png' and 'image/jpeg' are - * allowed. The MIME type is always ISO-8859-1 encoded. - * - * @param string $mimeType The MIME type. - */ - public function setMimeType($mimeType) - { - $this->_mimeType = $mimeType; - } - - /** - * Returns the embedded image binary data. - * - * @return string - */ - public function getImageData() - { - return $this->_imageData; - } - - /** - * Sets the embedded image data. Also updates the image size to correspond - * the new data. - * - * @param string $imageData The image data. - */ - public function setImageData($imageData) - { - $this->_imageData = $imageData; - $this->_imageSize = strlen($imageData); - } - - /** - * Returns the size of the embedded image data. - * - * @return integer - */ - public function getImageSize() - { - return $this->_imageSize; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_currency) - ->writeString8($this->_price, 1) - ->write($this->_date) - ->writeString8($this->_contact, 1) - ->writeUInt8($this->_delivery); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_seller, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) - ->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_seller, null, 1) - ->writeString16($this->_description, null, 1); - break; - default: - $writer->writeString8($this->_seller, 1) - ->writeString8($this->_description, 1); - break; - } - if ($this->_mimeType) { - $writer->writeString8($this->_mimeType, 1) - ->write($this->_imageData); - } - } -} +Commercial frame enables several competing offers in the same tag + * by bundling all needed information. That makes this frame rather complex but + * it's an easier solution than if one tries to achieve the same result with + * several frames. + * + * There may be more than one commercial frame in a tag, but no two may be + * identical. + * + * @todo The use of Zend_Currency requires design considerations. + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Comr.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Comr extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** + * The delivery types. + * + * @var Array + */ + public static $types = array + ('Other', 'Standard CD album with other songs', + 'Compressed audio on CD', 'File over the Internet', + 'Stream over the Internet', 'As note sheets', + 'As note sheets in a book with other sheets', 'Music on other media', + 'Non-musical merchandise'); + + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_currency = 'EUR'; + + /** @var string */ + private $_price; + + /** @var string */ + private $_date; + + /** @var string */ + private $_contact; + + /** @var integer */ + private $_delivery = 0; + + /** @var string */ + private $_seller; + + /** @var string */ + private $_description; + + /** @var string */ + private $_mimeType = false; + + /** @var string */ + private $_imageData; + + /** @var integer */ + private $_imageSize = 0; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_currency = strtoupper($this->_reader->read(3)); + $offset = $this->_reader->getOffset(); + list ($this->_price) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset($offset + strlen($this->_price) + 1); + $this->_date = $this->_reader->read(8); + $offset = $this->_reader->getOffset(); + list($this->_contact) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset($offset + strlen($this->_contact) + 1); + $this->_delivery = $this->_reader->readUInt8(); + $offset = $this->_reader->getOffset(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list ($this->_seller, $this->_description) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 3); + $this->_reader->setOffset + ($offset + strlen($this->_seller) + + strlen($this->_description) + 4); + break; + case self::UTF8: + // break intentionally omitted + default: + list ($this->_seller, $this->_description) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 3); + $this->_reader->setOffset + ($offset + strlen($this->_seller) + + strlen($this->_description) + 2); + break; + } + $this->_seller = $this->_convertString($this->_seller, $encoding); + $this->_description = $this->_convertString($this->_description, $encoding); + + if (!$this->_reader->available()) + return; + + list($this->_mimeType, $this->_imageData) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_imageSize = strlen($this->_imageData); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the currency code, encoded according to + * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm + * ISO 4217} alphabetic currency code. + * + * @return string + */ + public function getCurrency() + { + return $this->_currency; + } + + /** + * Sets the currency used in transaction, encoded according to + * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm + * ISO 4217} alphabetic currency code. + * + * @param string $currency The currency code. + */ + public function setCurrency($currency) + { + $this->_currency = strtoupper($currency); + } + + /** + * Returns the first price. + * + * @return double + */ + public function getPrice() + { + $array = explode('/', $this->_price); + return doubleval($array[0]); + } + + /** + * Returns the price array. + * + * @return Array + */ + public function getPrices() + { + $array = explode('/', $this->_price); + foreach ($array as $key => $value) { + $array[$key] = doubleval($value); + } + return $array; + } + + /** + * Sets the default price. Multiple prices can be given in the form of an + * array but there may only be one currency of each type. + * + * @param double $price The price. + */ + public function setPrice($price) + { + $this->setPrices($price); + } + + /** + * Sets the default price. Multiple prices can be given in the form of an + * array but there may only be one currency of each type. + * + * @param double|Array $prices The prices. + */ + public function setPrices($prices) + { + if (!is_array($prices)) { + $prices = array($prices); + } + $this->_price = implode('/', $prices); + } + + /** + * Returns the date describing for how long the price is valid. + * + * @internal The ID3v2 standard does not declare the time zone to be used + * in the date. Date must thus be expressed as GMT/UTC. + * @return Zend_Date + */ + public function getDate() + { + require_once 'Zend/Date.php'; + $date = new Zend_Date(0); + $date->setTimezone('UTC'); + $date->set($this->_date, 'yyyyMMdd'); + return $date; + } + + /** + * Sets the date describing for how long the price is valid for. + * + * @internal The ID3v2 standard does not declare the time zone to be used + * in the date. Date must thus be expressed as GMT/UTC. + * @param Zend_Date $date The date. + */ + public function setDate($date) + { + require_once 'Zend/Date.php'; + if ($date === null) { + $date = Zend_Date::now(); + } + $date->setTimezone('UTC'); + $this->_date = $date->toString('yyyyMMdd'); + } + + /** + * Returns the contact URL, with which the user can contact the seller. + * + * @return string + */ + public function getContact() + { + return $this->_contact; + } + + /** + * Sets the contact URL, with which the user can contact the seller. + * + * @param string $contact The contact URL. + */ + public function setContact($contact) + { + $this->_contact = $contact; + } + + /** + * Returns the delivery type with whitch the audio was delivered when + * bought. + * + * @return integer + */ + public function getDelivery() + { + return $this->_delivery; + } + + /** + * Sets the delivery type with whitch the audio was delivered when bought. + * + * @param integer $delivery The delivery type code. + */ + public function setDelivery($delivery) + { + $this->_delivery = $delivery; + } + + /** + * Returns the name of the seller. + * + * @return string + */ + public function getSeller() + { + return $this->_seller; + } + + /** + * Sets the name of the seller using given encoding. The seller text + * encoding must be that of the description text. + * + * @param string $seller The name of the seller. + * @param integer $encoding The text encoding. + */ + public function setSeller($seller, $encoding = null) + { + $this->_seller = $seller; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Returns the short description of the product. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. The description + * encoding must be that of the seller text. + * + * @param string $description The content description text. + * @param integer $encoding The text encoding. + */ + public function setDescription($description, $encoding = null) + { + $this->_description = $description; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Returns the MIME type of the seller's company logo, if attached, or + * false otherwise. Currently only 'image/png' and 'image/jpeg' + * are allowed. + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Sets the MIME type. Currently only 'image/png' and 'image/jpeg' are + * allowed. The MIME type is always ISO-8859-1 encoded. + * + * @param string $mimeType The MIME type. + */ + public function setMimeType($mimeType) + { + $this->_mimeType = $mimeType; + } + + /** + * Returns the embedded image binary data. + * + * @return string + */ + public function getImageData() + { + return $this->_imageData; + } + + /** + * Sets the embedded image data. Also updates the image size to correspond + * the new data. + * + * @param string $imageData The image data. + */ + public function setImageData($imageData) + { + $this->_imageData = $imageData; + $this->_imageSize = strlen($imageData); + } + + /** + * Returns the size of the embedded image data. + * + * @return integer + */ + public function getImageSize() + { + return $this->_imageSize; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_currency) + ->writeString8($this->_price, 1) + ->write($this->_date) + ->writeString8($this->_contact, 1) + ->writeUInt8($this->_delivery); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_seller, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) + ->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_seller, null, 1) + ->writeString16($this->_description, null, 1); + break; + default: + $writer->writeString8($this->_seller, 1) + ->writeString8($this->_description, 1); + break; + } + if ($this->_mimeType) { + $writer->writeString8($this->_mimeType, 1) + ->write($this->_imageData); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Encr.php b/app/libs/vendor/Zend/Media/Id3/Frame/Encr.php index 13a19791..ad7307df 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Encr.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Encr.php @@ -1,165 +1,165 @@ -Encryption method - * registration frame. - * - * The owner identifier a URL containing an email address, or a link to a - * location where an email address can be found, that belongs to the - * organisation responsible for this specific encryption method. Questions - * regarding the encryption method should be sent to the indicated email - * address. - * - * The method symbol contains a value that is associated with this method - * throughout the whole tag, in the range 0x80-0xF0. All other values are - * reserved. The method symbol may optionally be followed by encryption - * specific data. - * - * There may be several ENCR frames in a tag but only one containing the same - * symbol and only one containing the same owner identifier. The method must be - * used somewhere in the tag. See {@link Zend_Media_Id3_Frame#ENCRYPTION} for - * more information. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Encr.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Encr extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var integer */ - private $_method; - - /** @var string */ - private $_encryptionData; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list($this->_owner, ) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(strlen($this->_owner) + 1); - $this->_method = $this->_reader->readInt8(); - $this->_encryptionData = - $this->_reader->read($this->_reader->getSize()); - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - $this->_owner = $owner; - } - - /** - * Returns the method symbol. - * - * @return integer - */ - public function getMethod() - { - return $this->_method; - } - - /** - * Sets the method symbol. - * - * @param integer $method The method symbol byte. - */ - public function setMethod($method) - { - $this->_method = $method; - } - - /** - * Returns the encryption data. - * - * @return string - */ - public function getEncryptionData() - { - return $this->_encryptionData; - } - - /** - * Sets the encryption data. - * - * @param string $encryptionData The encryption data string. - */ - public function setEncryptionData($encryptionData) - { - $this->_encryptionData = $encryptionData; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->writeInt8($this->_method) - ->write($this->_encryptionData); - } -} +Encryption method + * registration frame. + * + * The owner identifier a URL containing an email address, or a link to a + * location where an email address can be found, that belongs to the + * organisation responsible for this specific encryption method. Questions + * regarding the encryption method should be sent to the indicated email + * address. + * + * The method symbol contains a value that is associated with this method + * throughout the whole tag, in the range 0x80-0xF0. All other values are + * reserved. The method symbol may optionally be followed by encryption + * specific data. + * + * There may be several ENCR frames in a tag but only one containing the same + * symbol and only one containing the same owner identifier. The method must be + * used somewhere in the tag. See {@link Zend_Media_Id3_Frame#ENCRYPTION} for + * more information. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Encr.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Encr extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var integer */ + private $_method; + + /** @var string */ + private $_encryptionData; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list($this->_owner, ) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(strlen($this->_owner) + 1); + $this->_method = $this->_reader->readInt8(); + $this->_encryptionData = + $this->_reader->read($this->_reader->getSize()); + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + $this->_owner = $owner; + } + + /** + * Returns the method symbol. + * + * @return integer + */ + public function getMethod() + { + return $this->_method; + } + + /** + * Sets the method symbol. + * + * @param integer $method The method symbol byte. + */ + public function setMethod($method) + { + $this->_method = $method; + } + + /** + * Returns the encryption data. + * + * @return string + */ + public function getEncryptionData() + { + return $this->_encryptionData; + } + + /** + * Sets the encryption data. + * + * @param string $encryptionData The encryption data string. + */ + public function setEncryptionData($encryptionData) + { + $this->_encryptionData = $encryptionData; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->writeInt8($this->_method) + ->write($this->_encryptionData); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Equ2.php b/app/libs/vendor/Zend/Media/Id3/Frame/Equ2.php index 7d8f24a5..02372686 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Equ2.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Equ2.php @@ -1,195 +1,195 @@ -Equalisation (2) is another subjective, alignment frame. It allows - * the user to predefine an equalisation curve within the audio file. There may - * be more than one EQU2 frame in each tag, but only one with the same - * identification string. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Equ2.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Equ2 extends Zend_Media_Id3_Frame -{ - /** - * Interpolation type that defines that no interpolation is made. A jump - * from one adjustment level to another occurs in the middle between two - * adjustment points. - */ - const BAND = 0; - - /** - * Interpolation type that defines that interpolation between adjustment - * points is linear. - */ - const LINEAR = 1; - - /** @var integer */ - private $_interpolation; - - /** @var string */ - private $_device; - - /** @var Array */ - private $_adjustments = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_interpolation = $this->_reader->readInt8(); - list ($this->_device) = $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(1 + strlen($this->_device) + 1); - while ($this->_reader->available()) { - $this->_adjustments - [(int)($this->_reader->readUInt16BE() / 2)] = - $this->_reader->readInt16BE() / 512.0; - } - ksort($this->_adjustments); - } - - /** - * Returns the interpolation method. The interpolation method describes - * which method is preferred when an interpolation between the adjustment - * point that follows. - * - * @return integer - */ - public function getInterpolation() - { - return $this->_interpolation; - } - - /** - * Sets the interpolation method. The interpolation method describes which - * method is preferred when an interpolation between the adjustment point - * that follows. - * - * @param integer $interpolation The interpolation method code. - */ - public function setInterpolation($interpolation) - { - $this->_interpolation = $interpolation; - } - - /** - * Returns the device where the adjustments should apply. - * - * @return string - */ - public function getDevice() - { - return $this->_device; - } - - /** - * Sets the device where the adjustments should apply. - * - * @param string $device The device. - */ - public function setDevice($device) - { - $this->_device = $device; - } - - /** - * Returns the array containing adjustments having frequencies as keys and - * their corresponding adjustments as values. - * - * Adjustment points are ordered by frequency. - * - * @return Array - */ - public function getAdjustments() - { - return $this->_adjustments; - } - - /** - * Adds a volume adjustment setting for given frequency. The frequency can - * have a value from 0 to 32767 Hz, and the adjustment +/- 64 dB with a - * precision of 0.001953125 dB. - * - * @param integer $frequency The frequency, in hertz. - * @param integer $adjustment The adjustment, in dB. - */ - public function addAdjustment($frequency, $adjustment) - { - $this->_adjustments[$frequency] = $adjustment; - ksort($this->_adjustments); - } - - /** - * Sets the adjustments array. The array must have frequencies as keys and - * their corresponding adjustments as values. The frequency can have a value - * from 0 to 32767 Hz, and the adjustment +/- 64 dB with a precision of - * 0.001953125 dB. One frequency should only be described once in the frame. - * - * @param Array $adjustments The adjustments array. - */ - public function setAdjustments($adjustments) - { - $this->_adjustments = $adjustments; - ksort($this->_adjustments); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeInt8($this->_interpolation) - ->writeString8($this->_device, 1); - foreach ($this->_adjustments as $frequency => $adjustment) { - $writer->writeUInt16BE($frequency * 2) - ->writeInt16BE($adjustment * 512); - } - } -} +Equalisation (2) is another subjective, alignment frame. It allows + * the user to predefine an equalisation curve within the audio file. There may + * be more than one EQU2 frame in each tag, but only one with the same + * identification string. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Equ2.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Equ2 extends Zend_Media_Id3_Frame +{ + /** + * Interpolation type that defines that no interpolation is made. A jump + * from one adjustment level to another occurs in the middle between two + * adjustment points. + */ + const BAND = 0; + + /** + * Interpolation type that defines that interpolation between adjustment + * points is linear. + */ + const LINEAR = 1; + + /** @var integer */ + private $_interpolation; + + /** @var string */ + private $_device; + + /** @var Array */ + private $_adjustments = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_interpolation = $this->_reader->readInt8(); + list ($this->_device) = $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(1 + strlen($this->_device) + 1); + while ($this->_reader->available()) { + $this->_adjustments + [(int)($this->_reader->readUInt16BE() / 2)] = + $this->_reader->readInt16BE() / 512.0; + } + ksort($this->_adjustments); + } + + /** + * Returns the interpolation method. The interpolation method describes + * which method is preferred when an interpolation between the adjustment + * point that follows. + * + * @return integer + */ + public function getInterpolation() + { + return $this->_interpolation; + } + + /** + * Sets the interpolation method. The interpolation method describes which + * method is preferred when an interpolation between the adjustment point + * that follows. + * + * @param integer $interpolation The interpolation method code. + */ + public function setInterpolation($interpolation) + { + $this->_interpolation = $interpolation; + } + + /** + * Returns the device where the adjustments should apply. + * + * @return string + */ + public function getDevice() + { + return $this->_device; + } + + /** + * Sets the device where the adjustments should apply. + * + * @param string $device The device. + */ + public function setDevice($device) + { + $this->_device = $device; + } + + /** + * Returns the array containing adjustments having frequencies as keys and + * their corresponding adjustments as values. + * + * Adjustment points are ordered by frequency. + * + * @return Array + */ + public function getAdjustments() + { + return $this->_adjustments; + } + + /** + * Adds a volume adjustment setting for given frequency. The frequency can + * have a value from 0 to 32767 Hz, and the adjustment +/- 64 dB with a + * precision of 0.001953125 dB. + * + * @param integer $frequency The frequency, in hertz. + * @param integer $adjustment The adjustment, in dB. + */ + public function addAdjustment($frequency, $adjustment) + { + $this->_adjustments[$frequency] = $adjustment; + ksort($this->_adjustments); + } + + /** + * Sets the adjustments array. The array must have frequencies as keys and + * their corresponding adjustments as values. The frequency can have a value + * from 0 to 32767 Hz, and the adjustment +/- 64 dB with a precision of + * 0.001953125 dB. One frequency should only be described once in the frame. + * + * @param Array $adjustments The adjustments array. + */ + public function setAdjustments($adjustments) + { + $this->_adjustments = $adjustments; + ksort($this->_adjustments); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeInt8($this->_interpolation) + ->writeString8($this->_device, 1); + foreach ($this->_adjustments as $frequency => $adjustment) { + $writer->writeUInt16BE($frequency * 2) + ->writeInt16BE($adjustment * 512); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Equa.php b/app/libs/vendor/Zend/Media/Id3/Frame/Equa.php index 83bb2572..44a81600 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Equa.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Equa.php @@ -1,133 +1,133 @@ -Equalisation frame is another subjective, alignment frame. It - * allows the user to predefine an equalisation curve within the audio file. - * There may only be one EQUA frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Equa.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Equa extends Zend_Media_Id3_Frame -{ - /** @var Array */ - private $_adjustments; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $adjustmentBits = $this->_reader->readInt8(); - if ($adjustmentBits <= 8 || $adjustmentBits > 16) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('Unsupported adjustment bit size of: ' . $adjustmentBits); - } - - while ($this->_reader->available()) { - $frequency = $this->_reader->readUInt16BE(); - $this->_adjustments[($frequency & 0x7fff)] = - ($frequency & 0x8000) == 0x8000 ? - $this->_reader->readUInt16BE() : - -$this->_reader->readUInt16BE(); - } - ksort($this->_adjustments); - } - - /** - * Returns the array containing adjustments having frequencies as keys and - * their corresponding adjustments as values. - * - * @return Array - */ - public function getAdjustments() - { - return $this->_adjustments; - } - - /** - * Adds a volume adjustment setting for given frequency. The frequency can - * have a value from 0 to 32767 Hz. - * - * @param integer $frequency The frequency, in hertz. - * @param integer $adjustment The adjustment, in dB. - */ - public function addAdjustment($frequency, $adjustment) - { - $this->_adjustments[$frequency] = $adjustment; - ksort($this->_adjustments); - } - - /** - * Sets the adjustments array. The array must have frequencies as keys and - * their corresponding adjustments as values. The frequency can have a value - * from 0 to 32767 Hz. One frequency should only be described once in the - * frame. - * - * @param Array $adjustments The adjustments array. - */ - public function setAdjustments($adjustments) - { - $this->_adjustments = $adjustments; - ksort($this->_adjustments); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeInt8(16); - foreach ($this->_adjustments as $frequency => $adjustment) { - $writer->writeUInt16BE - ($adjustment > 0 ? $frequency | 0x8000 : $frequency & ~0x8000) - ->writeUInt16BE(abs($adjustment)); - } - } -} +Equalisation frame is another subjective, alignment frame. It + * allows the user to predefine an equalisation curve within the audio file. + * There may only be one EQUA frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Equa.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Equa extends Zend_Media_Id3_Frame +{ + /** @var Array */ + private $_adjustments; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $adjustmentBits = $this->_reader->readInt8(); + if ($adjustmentBits <= 8 || $adjustmentBits > 16) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('Unsupported adjustment bit size of: ' . $adjustmentBits); + } + + while ($this->_reader->available()) { + $frequency = $this->_reader->readUInt16BE(); + $this->_adjustments[($frequency & 0x7fff)] = + ($frequency & 0x8000) == 0x8000 ? + $this->_reader->readUInt16BE() : + -$this->_reader->readUInt16BE(); + } + ksort($this->_adjustments); + } + + /** + * Returns the array containing adjustments having frequencies as keys and + * their corresponding adjustments as values. + * + * @return Array + */ + public function getAdjustments() + { + return $this->_adjustments; + } + + /** + * Adds a volume adjustment setting for given frequency. The frequency can + * have a value from 0 to 32767 Hz. + * + * @param integer $frequency The frequency, in hertz. + * @param integer $adjustment The adjustment, in dB. + */ + public function addAdjustment($frequency, $adjustment) + { + $this->_adjustments[$frequency] = $adjustment; + ksort($this->_adjustments); + } + + /** + * Sets the adjustments array. The array must have frequencies as keys and + * their corresponding adjustments as values. The frequency can have a value + * from 0 to 32767 Hz. One frequency should only be described once in the + * frame. + * + * @param Array $adjustments The adjustments array. + */ + public function setAdjustments($adjustments) + { + $this->_adjustments = $adjustments; + ksort($this->_adjustments); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeInt8(16); + foreach ($this->_adjustments as $frequency => $adjustment) { + $writer->writeUInt16BE + ($adjustment > 0 ? $frequency | 0x8000 : $frequency & ~0x8000) + ->writeUInt16BE(abs($adjustment)); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Etco.php b/app/libs/vendor/Zend/Media/Id3/Frame/Etco.php index ae4c0a64..9d6532e6 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Etco.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Etco.php @@ -1,168 +1,168 @@ -Event timing codes allows synchronisation with key events in the - * audio. - * - * The events are an array of timestamp and type pairs. The time stamp is set to - * zero if directly at the beginning of the sound or after the previous event. - * All events are sorted in chronological order. - * - * The events 0xe0-ef are for user events. You might want to synchronise your - * music to something, like setting off an explosion on-stage, activating a - * screensaver etc. - * - * There may only be one ETCO frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Etco.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Etco extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Timing -{ - /** - * The list of event types. - * - * @var Array - */ - public static $types = array - ('Padding', 'End of initial silence', 'Intro start', 'Main part start', - 'Outro start', 'Outro end', 'Verse start','Refrain start', - 'Interlude start', 'Theme start', 'Variation start', 'Key change', - 'Time change', 'Momentary unwanted noise', 'Sustained noise', - 'Sustained noise end', 'Intro end', 'Main part end', 'Verse end', - 'Refrain end', 'Theme end', 'Profanity', 'Profanity end', - - 0xe0 => 'User event', 'User event', 'User event', 'User event', - 'User event', 'User event', 'User event', 'User event', 'User event', - 'User event', 'User event', 'User event', 'User event', 'User event', - - 0xfd => 'Audio end (start of silence)', 'Audio file ends', - 'One more byte of events follows'); - - /** @var integer */ - private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; - - /** @var Array */ - private $_events = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_format = $this->_reader->readUInt8(); - while ($this->_reader->available()) { - $data = $this->_reader->readUInt8(); - $this->_events[$this->_reader->readUInt32BE()] = $data; - if ($data == 0xff) { - break; - } - } - ksort($this->_events); - } - - /** - * Returns the timing format. - * - * @return integer - */ - public function getFormat() - { - return $this->_format; - } - - /** - * Sets the timing format. - * - * @see Zend_Media_Id3_Timing - * @param integer $format The timing format. - */ - public function setFormat($format) - { - $this->_format = $format; - } - - /** - * Returns the events as an associated array having the timestamps as keys - * and the event types as values. - * - * @return Array - */ - public function getEvents() - { - return $this->_events; - } - - /** - * Sets the events using given format. The value must be an associated array - * having the timestamps as keys and the event types as values. - * - * @param Array $events The events array. - * @param integer $format The timing format. - */ - public function setEvents($events, $format = null) - { - $this->_events = $events; - if ($format !== null) { - $this->setFormat($format); - } - ksort($this->_events); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_format); - foreach ($this->_events as $timestamp => $type) { - $writer->writeUInt8($type) - ->writeUInt32BE($timestamp); - } - } -} +Event timing codes allows synchronisation with key events in the + * audio. + * + * The events are an array of timestamp and type pairs. The time stamp is set to + * zero if directly at the beginning of the sound or after the previous event. + * All events are sorted in chronological order. + * + * The events 0xe0-ef are for user events. You might want to synchronise your + * music to something, like setting off an explosion on-stage, activating a + * screensaver etc. + * + * There may only be one ETCO frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Etco.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Etco extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Timing +{ + /** + * The list of event types. + * + * @var Array + */ + public static $types = array + ('Padding', 'End of initial silence', 'Intro start', 'Main part start', + 'Outro start', 'Outro end', 'Verse start','Refrain start', + 'Interlude start', 'Theme start', 'Variation start', 'Key change', + 'Time change', 'Momentary unwanted noise', 'Sustained noise', + 'Sustained noise end', 'Intro end', 'Main part end', 'Verse end', + 'Refrain end', 'Theme end', 'Profanity', 'Profanity end', + + 0xe0 => 'User event', 'User event', 'User event', 'User event', + 'User event', 'User event', 'User event', 'User event', 'User event', + 'User event', 'User event', 'User event', 'User event', 'User event', + + 0xfd => 'Audio end (start of silence)', 'Audio file ends', + 'One more byte of events follows'); + + /** @var integer */ + private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; + + /** @var Array */ + private $_events = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_format = $this->_reader->readUInt8(); + while ($this->_reader->available()) { + $data = $this->_reader->readUInt8(); + $this->_events[$this->_reader->readUInt32BE()] = $data; + if ($data == 0xff) { + break; + } + } + ksort($this->_events); + } + + /** + * Returns the timing format. + * + * @return integer + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the timing format. + * + * @see Zend_Media_Id3_Timing + * @param integer $format The timing format. + */ + public function setFormat($format) + { + $this->_format = $format; + } + + /** + * Returns the events as an associated array having the timestamps as keys + * and the event types as values. + * + * @return Array + */ + public function getEvents() + { + return $this->_events; + } + + /** + * Sets the events using given format. The value must be an associated array + * having the timestamps as keys and the event types as values. + * + * @param Array $events The events array. + * @param integer $format The timing format. + */ + public function setEvents($events, $format = null) + { + $this->_events = $events; + if ($format !== null) { + $this->setFormat($format); + } + ksort($this->_events); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_format); + foreach ($this->_events as $timestamp => $type) { + $writer->writeUInt8($type) + ->writeUInt32BE($timestamp); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Geob.php b/app/libs/vendor/Zend/Media/Id3/Frame/Geob.php index 645372fa..0e8e1175 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Geob.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Geob.php @@ -1,264 +1,264 @@ -General encapsulated object frame any type of file can be - * encapsulated. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Geob.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Geob extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_mimeType; - - /** @var string */ - private $_filename; - - /** @var string */ - private $_description; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - list($this->_mimeType) = $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(1 + strlen($this->_mimeType) + 1); - - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list ($this->_filename, $this->_description, - $this->_data) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 3); - break; - case self::UTF8: - // break intentionally omitted - default: - list ($this->_filename, $this->_description, - $this->_data) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 3); - break; - } - $this->_filename = - $this->_convertString($this->_filename, $encoding); - $this->_description = - $this->_convertString($this->_description, $encoding); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the MIME type. The MIME type is always encoded with ISO-8859-1. - * - * @return string - */ - public function getMimeType() - { - return $this->_mimeType; - } - - /** - * Sets the MIME type. The MIME type is always ISO-8859-1 encoded. - * - * @param string $mimeType The MIME type. - */ - public function setMimeType($mimeType) - { - $this->_mimeType = $mimeType; - } - - /** - * Returns the file name. - * - * @return string - */ - public function getFilename() - { - return $this->_filename; - } - - /** - * Sets the file name using given encoding. The file name encoding must be - * that of the description text. - * - * @param string $description The file description text. - * @param integer $encoding The text encoding. - */ - public function setFilename($filename, $encoding = null) - { - $this->_filename = $filename; - if ($encoding !== null) { - $this->_encoding = $encoding; - } - } - - /** - * Returns the file description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the file description text using given encoding. The description - * encoding must be that of the file name. - * - * @param string $description The file description text. - * @param integer $encoding The text encoding. - */ - public function setDescription($description, $encoding = null) - { - $this->_description = $description; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Returns the embedded object binary data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the embedded object binary data. - * - * @param string $data The object data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->writeString8($this->_mimeType, 1); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_filename, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) - ->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_filename, null, 1) - ->writeString16($this->_description, null, 1); - break; - default: - $writer->writeString8($this->_filename, 1) - ->writeString8($this->_description, 1); - break; - } - $writer->write($this->_data); - } -} +General encapsulated object frame any type of file can be + * encapsulated. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Geob.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Geob extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_mimeType; + + /** @var string */ + private $_filename; + + /** @var string */ + private $_description; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + list($this->_mimeType) = $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(1 + strlen($this->_mimeType) + 1); + + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list ($this->_filename, $this->_description, + $this->_data) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 3); + break; + case self::UTF8: + // break intentionally omitted + default: + list ($this->_filename, $this->_description, + $this->_data) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 3); + break; + } + $this->_filename = + $this->_convertString($this->_filename, $encoding); + $this->_description = + $this->_convertString($this->_description, $encoding); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the MIME type. The MIME type is always encoded with ISO-8859-1. + * + * @return string + */ + public function getMimeType() + { + return $this->_mimeType; + } + + /** + * Sets the MIME type. The MIME type is always ISO-8859-1 encoded. + * + * @param string $mimeType The MIME type. + */ + public function setMimeType($mimeType) + { + $this->_mimeType = $mimeType; + } + + /** + * Returns the file name. + * + * @return string + */ + public function getFilename() + { + return $this->_filename; + } + + /** + * Sets the file name using given encoding. The file name encoding must be + * that of the description text. + * + * @param string $description The file description text. + * @param integer $encoding The text encoding. + */ + public function setFilename($filename, $encoding = null) + { + $this->_filename = $filename; + if ($encoding !== null) { + $this->_encoding = $encoding; + } + } + + /** + * Returns the file description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the file description text using given encoding. The description + * encoding must be that of the file name. + * + * @param string $description The file description text. + * @param integer $encoding The text encoding. + */ + public function setDescription($description, $encoding = null) + { + $this->_description = $description; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Returns the embedded object binary data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the embedded object binary data. + * + * @param string $data The object data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->writeString8($this->_mimeType, 1); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_filename, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) + ->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_filename, null, 1) + ->writeString16($this->_description, null, 1); + break; + default: + $writer->writeString8($this->_filename, 1) + ->writeString8($this->_description, 1); + break; + } + $writer->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Grid.php b/app/libs/vendor/Zend/Media/Id3/Frame/Grid.php index 951e0991..f8561066 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Grid.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Grid.php @@ -1,160 +1,160 @@ -Group identification registration frame enables grouping of - * otherwise unrelated frames. This can be used when some frames are to be - * signed. To identify which frames belongs to a set of frames a group - * identifier must be registered in the tag with this frame. - * - * The owner identifier is a URL containing an email address, or a link to a - * location where an email address can be found, that belongs to the - * organisation responsible for this grouping. Questions regarding the grouping - * should be sent to the indicated email address. - * - * The group symbol contains a value that associates the frame with this group - * throughout the whole tag, in the range 0x80-0xf0. All other values are - * reserved. The group symbol may optionally be followed by some group specific - * data, e.g. a digital signature. There may be several GRID frames in a tag - * but only one containing the same symbol and only one containing the same - * owner identifier. The group symbol must be used somewhere in the tag. See - * {@link Zend_Media_Id3_Frame#GROUPING_IDENTITY} for more information. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Grid.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Grid extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var integer */ - private $_group; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list($this->_owner) = $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(strlen($this->_owner) + 1); - $this->_group = $this->_reader->readUInt8(); - $this->_data = $this->_reader->read($this->_reader->getSize()); - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - $this->_owner = $owner; - } - - /** - * Returns the group symbol. - * - * @return integer - */ - public function getGroup() - { - return $this->_group; - } - - /** - * Sets the group symbol. - * - * @param integer $group The group symbol. - */ - public function setGroup($group) - { - $this->_group = $group; - } - - /** - * Returns the group dependent data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the group dependent data. - * - * @param string $data The data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->writeUInt8($this->_group) - ->write($this->_data); - } -} +Group identification registration frame enables grouping of + * otherwise unrelated frames. This can be used when some frames are to be + * signed. To identify which frames belongs to a set of frames a group + * identifier must be registered in the tag with this frame. + * + * The owner identifier is a URL containing an email address, or a link to a + * location where an email address can be found, that belongs to the + * organisation responsible for this grouping. Questions regarding the grouping + * should be sent to the indicated email address. + * + * The group symbol contains a value that associates the frame with this group + * throughout the whole tag, in the range 0x80-0xf0. All other values are + * reserved. The group symbol may optionally be followed by some group specific + * data, e.g. a digital signature. There may be several GRID frames in a tag + * but only one containing the same symbol and only one containing the same + * owner identifier. The group symbol must be used somewhere in the tag. See + * {@link Zend_Media_Id3_Frame#GROUPING_IDENTITY} for more information. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Grid.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Grid extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var integer */ + private $_group; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list($this->_owner) = $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(strlen($this->_owner) + 1); + $this->_group = $this->_reader->readUInt8(); + $this->_data = $this->_reader->read($this->_reader->getSize()); + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + $this->_owner = $owner; + } + + /** + * Returns the group symbol. + * + * @return integer + */ + public function getGroup() + { + return $this->_group; + } + + /** + * Sets the group symbol. + * + * @param integer $group The group symbol. + */ + public function setGroup($group) + { + $this->_group = $group; + } + + /** + * Returns the group dependent data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the group dependent data. + * + * @param string $data The data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->writeUInt8($this->_group) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Ipls.php b/app/libs/vendor/Zend/Media/Id3/Frame/Ipls.php index 8b4ca41b..83df4605 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Ipls.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Ipls.php @@ -1,200 +1,200 @@ -Involved people list is a frame containing the names of those - * involved, and how they were involved. There may only be one IPLS frame in - * each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ipls.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Ipls extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** @var integer */ - private $_encoding; - - /** @var Array */ - private $_people = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $data = array(); - $encoding = $this->_reader->readUInt8(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $data = $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize())); - foreach ($data as &$str) - $str = $this->_convertString($str, $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - $data = $this->_convertString - ($this->_explodeString8 - ($this->_reader->read($this->_reader->getSize())), - $encoding); - break; - } - - for ($i = 0; $i < count($data) - 1; $i += 2) { - $this->_people[] = array($data[$i] => @$data[$i + 1]); - } - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the involved people list as an array. For each person, the array - * contains an entry, which too is an associate array with involvement as - * its key and involvee as its value. - * - * @return Array - */ - public function getPeople() - { - return $this->_people; - } - - /** - * Adds a person with his involvement. - * - * @return string - */ - public function addPerson($involvement, $person) - { - $this->_people[] = array($involvement => $person); - } - - /** - * Sets the involved people list array. For each person, the array must - * contain an associate array with involvement as its key and involvee as - * its value. - * - * @param Array $people The involved people list. - */ - public function setPeople($people) - { - $this->_people = $people; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding); - foreach ($this->_people as $entry) { - foreach ($entry as $key => $val) { - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($key, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) - ->writeString16 - ($val, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($key, null, 1) - ->writeString16($val, null, 1); - break; - default: - $writer->writeString8($key, 1) - ->writeString8($val, 1); - break; - } - } - } - } -} +Involved people list is a frame containing the names of those + * involved, and how they were involved. There may only be one IPLS frame in + * each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ipls.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Ipls extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** @var integer */ + private $_encoding; + + /** @var Array */ + private $_people = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $data = array(); + $encoding = $this->_reader->readUInt8(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $data = $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize())); + foreach ($data as &$str) + $str = $this->_convertString($str, $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + $data = $this->_convertString + ($this->_explodeString8 + ($this->_reader->read($this->_reader->getSize())), + $encoding); + break; + } + + for ($i = 0; $i < count($data) - 1; $i += 2) { + $this->_people[] = array($data[$i] => @$data[$i + 1]); + } + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the involved people list as an array. For each person, the array + * contains an entry, which too is an associate array with involvement as + * its key and involvee as its value. + * + * @return Array + */ + public function getPeople() + { + return $this->_people; + } + + /** + * Adds a person with his involvement. + * + * @return string + */ + public function addPerson($involvement, $person) + { + $this->_people[] = array($involvement => $person); + } + + /** + * Sets the involved people list array. For each person, the array must + * contain an associate array with involvement as its key and involvee as + * its value. + * + * @param Array $people The involved people list. + */ + public function setPeople($people) + { + $this->_people = $people; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding); + foreach ($this->_people as $entry) { + foreach ($entry as $key => $val) { + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($key, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) + ->writeString16 + ($val, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($key, null, 1) + ->writeString16($val, null, 1); + break; + default: + $writer->writeString8($key, 1) + ->writeString8($val, 1); + break; + } + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Link.php b/app/libs/vendor/Zend/Media/Id3/Frame/Link.php index cfa32f94..b0b44267 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Link.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Link.php @@ -1,188 +1,188 @@ -Linked information frame is used to keep information duplication - * as low as possible by linking information from another ID3v2 tag that might - * reside in another audio file or alone in a binary file. It is recommended - * that this method is only used when the files are stored on a CD-ROM or other - * circumstances when the risk of file separation is low. - * - * Data should be retrieved from the first tag found in the file to which this - * link points. There may be more than one LINK frame in a tag, but only one - * with the same contents. - * - * A linked frame is to be considered as part of the tag and has the same - * restrictions as if it was a physical part of the tag (i.e. only one - * {@link Zend_Media_Id3_Frame_Rvrb RVRB} frame allowed, whether it's linked or - * not). - * - * Frames that may be linked and need no additional data are - * {@link Zend_Media_Id3_Frame_Aspi ASPI}, - * {@link Zend_Media_Id3_Frame_Etco ETCO}, - * {@link Zend_Media_Id3_Frame_Equ2 EQU2}, - * {@link Zend_Media_Id3_Frame_Mcdi MCDI}, - * {@link Zend_Media_Id3_Frame_Mllt MLLT}, - * {@link Zend_Media_Id3_Frame_Owne OWNE}, - * {@link Zend_Media_Id3_Frame_Rva2 RVA2}, - * {@link Zend_Media_Id3_Frame_Rvrb RVRB}, - * {@link Zend_Media_Id3_Frame_Sytc SYTC}, the text information frames (ie - * frames descendats of {@link Zend_Media_Id3_TextFrame}) and the URL - * link frames (ie frames descendants of - * {@link Zend_Media_Id3_LinkFrame}). - * - * The {@link Zend_Media_Id3_Frame_Aenc AENC}, - * {@link Zend_Media_Id3_Frame_Apic APIC}, - * {@link Zend_Media_Id3_Frame_Geob GEOB} - * and {@link Zend_Media_Id3_Frame_Txxx TXXX} frames may be linked with the - * content descriptor as additional ID data. - * - * The {@link Zend_Media_Id3_Frame_User USER} frame may be linked with the - * language field as additional ID data. - * - * The {@link Zend_Media_Id3_Frame_Priv PRIV} frame may be linked with the owner - * identifier as additional ID data. - * - * The {@link Zend_Media_Id3_Frame_Comm COMM}, - * {@link Zend_Media_Id3_Frame_Sylt SYLT} and - * {@link Zend_Media_Id3_Frame_Uslt USLT} frames may be linked with three bytes - * of language descriptor directly followed by a content descriptor as - * additional ID data. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Link.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Link extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_target; - - /** @var string */ - private $_url; - - /** @var string */ - private $_qualifier; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_target = $this->_reader->read(4); - list($this->_url, $this->_qualifier) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - } - - /** - * Returns the target tag identifier. - * - * @return string - */ - public function getTarget() - { - return $this->_target; - } - - /** - * Sets the target tag identifier. - * - * @param string $target The target tag identifier. - */ - public function setTarget($target) - { - $this->_target = $target; - } - - /** - * Returns the target tag URL. - * - * @return string - */ - public function getUrl() - { - return $this->_url; - } - - /** - * Sets the target tag URL. - * - * @param string $url The target URL. - */ - public function setUrl($url) - { - $this->_url = $url; - } - - /** - * Returns the additional data to identify further the tag. - * - * @return string - */ - public function getQualifier() - { - return $this->_qualifier; - } - - /** - * Sets the additional data to be used in tag identification. - * - * @param string $identifier The qualifier. - */ - public function setQualifier($qualifier) - { - $this->_qualifier = $qualifier; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8(substr($this->_target, 0, 4), 4) - ->writeString8($this->_url, 1) - ->writeString8($this->_qualifier); - } -} +Linked information frame is used to keep information duplication + * as low as possible by linking information from another ID3v2 tag that might + * reside in another audio file or alone in a binary file. It is recommended + * that this method is only used when the files are stored on a CD-ROM or other + * circumstances when the risk of file separation is low. + * + * Data should be retrieved from the first tag found in the file to which this + * link points. There may be more than one LINK frame in a tag, but only one + * with the same contents. + * + * A linked frame is to be considered as part of the tag and has the same + * restrictions as if it was a physical part of the tag (i.e. only one + * {@link Zend_Media_Id3_Frame_Rvrb RVRB} frame allowed, whether it's linked or + * not). + * + * Frames that may be linked and need no additional data are + * {@link Zend_Media_Id3_Frame_Aspi ASPI}, + * {@link Zend_Media_Id3_Frame_Etco ETCO}, + * {@link Zend_Media_Id3_Frame_Equ2 EQU2}, + * {@link Zend_Media_Id3_Frame_Mcdi MCDI}, + * {@link Zend_Media_Id3_Frame_Mllt MLLT}, + * {@link Zend_Media_Id3_Frame_Owne OWNE}, + * {@link Zend_Media_Id3_Frame_Rva2 RVA2}, + * {@link Zend_Media_Id3_Frame_Rvrb RVRB}, + * {@link Zend_Media_Id3_Frame_Sytc SYTC}, the text information frames (ie + * frames descendats of {@link Zend_Media_Id3_TextFrame}) and the URL + * link frames (ie frames descendants of + * {@link Zend_Media_Id3_LinkFrame}). + * + * The {@link Zend_Media_Id3_Frame_Aenc AENC}, + * {@link Zend_Media_Id3_Frame_Apic APIC}, + * {@link Zend_Media_Id3_Frame_Geob GEOB} + * and {@link Zend_Media_Id3_Frame_Txxx TXXX} frames may be linked with the + * content descriptor as additional ID data. + * + * The {@link Zend_Media_Id3_Frame_User USER} frame may be linked with the + * language field as additional ID data. + * + * The {@link Zend_Media_Id3_Frame_Priv PRIV} frame may be linked with the owner + * identifier as additional ID data. + * + * The {@link Zend_Media_Id3_Frame_Comm COMM}, + * {@link Zend_Media_Id3_Frame_Sylt SYLT} and + * {@link Zend_Media_Id3_Frame_Uslt USLT} frames may be linked with three bytes + * of language descriptor directly followed by a content descriptor as + * additional ID data. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Link.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Link extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_target; + + /** @var string */ + private $_url; + + /** @var string */ + private $_qualifier; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_target = $this->_reader->read(4); + list($this->_url, $this->_qualifier) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + } + + /** + * Returns the target tag identifier. + * + * @return string + */ + public function getTarget() + { + return $this->_target; + } + + /** + * Sets the target tag identifier. + * + * @param string $target The target tag identifier. + */ + public function setTarget($target) + { + $this->_target = $target; + } + + /** + * Returns the target tag URL. + * + * @return string + */ + public function getUrl() + { + return $this->_url; + } + + /** + * Sets the target tag URL. + * + * @param string $url The target URL. + */ + public function setUrl($url) + { + $this->_url = $url; + } + + /** + * Returns the additional data to identify further the tag. + * + * @return string + */ + public function getQualifier() + { + return $this->_qualifier; + } + + /** + * Sets the additional data to be used in tag identification. + * + * @param string $identifier The qualifier. + */ + public function setQualifier($qualifier) + { + $this->_qualifier = $qualifier; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8(substr($this->_target, 0, 4), 4) + ->writeString8($this->_url, 1) + ->writeString8($this->_qualifier); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Mcdi.php b/app/libs/vendor/Zend/Media/Id3/Frame/Mcdi.php index cfa6f57a..aa0d41db 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Mcdi.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Mcdi.php @@ -1,102 +1,102 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mcdi.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Mcdi extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_data = $this->_reader->read($this->_reader->getSize()); - } - - /** - * Returns the CD TOC binary dump. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the CD TOC binary dump. - * - * @param string $data The CD TOC binary dump string. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->write($this->_data); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mcdi.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Mcdi extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_data = $this->_reader->read($this->_reader->getSize()); + } + + /** + * Returns the CD TOC binary dump. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the CD TOC binary dump. + * + * @param string $data The CD TOC binary dump string. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Mllt.php b/app/libs/vendor/Zend/Media/Id3/Frame/Mllt.php index 559bae98..7d43eb23 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Mllt.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Mllt.php @@ -1,187 +1,187 @@ -MPEG location lookup table frame includes references that the - * software can use to calculate positions in the file. - * - * The MPEG frames between reference describes how much the frame counter should - * be increased for every reference. If this value is two then the first - * reference points out the second frame, the 2nd reference the 4th frame, the - * 3rd reference the 6th frame etc. In a similar way the bytes between reference - * and milliseconds between reference points out bytes and milliseconds - * respectively. - * - * Each reference consists of two parts; a certain number of bits that describes - * the difference between what is said in bytes between reference and the - * reality and a certain number of bits that describes the difference between - * what is said in milliseconds between reference and the reality. - * - * There may only be one MLLT frame in each tag. - * - * @todo Data parsing and write support - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mllt.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Mllt extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_frames; - - /** @var integer */ - private $_bytes; - - /** @var integer */ - private $_milliseconds; - - /** @var Array */ - private $_deviation = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Write not supported yet'); - } - - $this->_frames = Transform::fromInt16BE(substr($this->_data, 0, 2)); - $this->_bytes = Transform::fromInt32BE(substr($this->_data, 2, 3)); - $this->_milliseconds = Transform::fromInt32BE(substr($this->_data, 5, 3)); - - $byteDevBits = Transform::fromInt8($this->_data[8]); - $millisDevBits = Transform::fromInt8($this->_data[9]); - - // $data = substr($this->_data, 10); - } - - /** - * Returns the number of MPEG frames between reference. - * - - * @return integer - */ - public function getFrames() - { - return $this->_frames; - } - - /** - * Sets the number of MPEG frames between reference. - * - - * @param integer $frames The number of MPEG frames. - */ - public function setFrames($frames) - { - $this->_frames = $frames; - } - - /** - * Returns the number of bytes between reference. - * - - * @return integer - */ - public function getBytes() - { - return $this->_bytes; - } - - /** - * Sets the number of bytes between reference. - * - - * @param integer $bytes The number of bytes. - */ - public function setBytes($bytes) - { - $this->_bytes = $bytes; - } - - /** - * Returns the number of milliseconds between references. - * - - * @return integer - */ - public function getMilliseconds() - { - return $this->_milliseconds; - } - - /** - * Sets the number of milliseconds between references. - * - - * @param integer $milliseconds The number of milliseconds. - */ - public function setMilliseconds($milliseconds) - { - return $this->_milliseconds; - } - - /** - * Returns the deviations as an array. Each value is an array containing two - * values, ie the deviation in bytes, and the deviation in milliseconds, - * respectively. - * - - * @return Array - */ - public function getDeviation() - { - return $this->_deviation; - } - - /** - * Sets the deviations array. The array must consist of arrays, each of - * which having two values, the deviation in bytes, and the deviation in - * milliseconds, respectively. - * - - * @param Array $deviation The deviations array. - */ - public function setDeviation($deviation) - { - $this->_deviation = $deviation; - } -} +MPEG location lookup table frame includes references that the + * software can use to calculate positions in the file. + * + * The MPEG frames between reference describes how much the frame counter should + * be increased for every reference. If this value is two then the first + * reference points out the second frame, the 2nd reference the 4th frame, the + * 3rd reference the 6th frame etc. In a similar way the bytes between reference + * and milliseconds between reference points out bytes and milliseconds + * respectively. + * + * Each reference consists of two parts; a certain number of bits that describes + * the difference between what is said in bytes between reference and the + * reality and a certain number of bits that describes the difference between + * what is said in milliseconds between reference and the reality. + * + * There may only be one MLLT frame in each tag. + * + * @todo Data parsing and write support + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mllt.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Mllt extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_frames; + + /** @var integer */ + private $_bytes; + + /** @var integer */ + private $_milliseconds; + + /** @var Array */ + private $_deviation = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Write not supported yet'); + } + + $this->_frames = Transform::fromInt16BE(substr($this->_data, 0, 2)); + $this->_bytes = Transform::fromInt32BE(substr($this->_data, 2, 3)); + $this->_milliseconds = Transform::fromInt32BE(substr($this->_data, 5, 3)); + + $byteDevBits = Transform::fromInt8($this->_data[8]); + $millisDevBits = Transform::fromInt8($this->_data[9]); + + // $data = substr($this->_data, 10); + } + + /** + * Returns the number of MPEG frames between reference. + * + + * @return integer + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Sets the number of MPEG frames between reference. + * + + * @param integer $frames The number of MPEG frames. + */ + public function setFrames($frames) + { + $this->_frames = $frames; + } + + /** + * Returns the number of bytes between reference. + * + + * @return integer + */ + public function getBytes() + { + return $this->_bytes; + } + + /** + * Sets the number of bytes between reference. + * + + * @param integer $bytes The number of bytes. + */ + public function setBytes($bytes) + { + $this->_bytes = $bytes; + } + + /** + * Returns the number of milliseconds between references. + * + + * @return integer + */ + public function getMilliseconds() + { + return $this->_milliseconds; + } + + /** + * Sets the number of milliseconds between references. + * + + * @param integer $milliseconds The number of milliseconds. + */ + public function setMilliseconds($milliseconds) + { + return $this->_milliseconds; + } + + /** + * Returns the deviations as an array. Each value is an array containing two + * values, ie the deviation in bytes, and the deviation in milliseconds, + * respectively. + * + + * @return Array + */ + public function getDeviation() + { + return $this->_deviation; + } + + /** + * Sets the deviations array. The array must consist of arrays, each of + * which having two values, the deviation in bytes, and the deviation in + * milliseconds, respectively. + * + + * @param Array $deviation The deviations array. + */ + public function setDeviation($deviation) + { + $this->_deviation = $deviation; + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Owne.php b/app/libs/vendor/Zend/Media/Id3/Frame/Owne.php index 342cc4a1..71aca16c 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Owne.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Owne.php @@ -1,258 +1,258 @@ -Ownership frame might be used as a reminder of a made transaction - * or, if signed, as proof. Note that the {@link Zend_Media_Id3_Frame_User USER} - * and {@link Zend_Media_Id3_Frame_Town TOWN} frames are good to use in - * conjunction with this one. - * - * There may only be one OWNE frame in a tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Owne.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Owne extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_currency = 'EUR'; - - /** @var string */ - private $_price; - - /** @var string */ - private $_date; - - /** @var string */ - private $_seller; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_currency = strtoupper($this->_reader->read(3)); - $offset = $this->_reader->getOffset(); - list ($this->_price) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset($offset + strlen($this->_price) + 1); - $this->_date = $this->_reader->read(8); - $this->_seller = $this->_convertString - ($this->_reader->read($this->_reader->getSize()), $encoding); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the currency code, encoded according to - * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm - * ISO 4217} alphabetic currency code. - * - * @return string - */ - public function getCurrency() - { - return $this->_currency; - } - - /** - * Sets the currency used in transaction, encoded according to - * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm - * ISO 4217} alphabetic currency code. - * - * @param string $currency The currency code. - */ - public function setCurrency($currency) - { - $this->_currency = strtoupper($currency); - } - - /** - * Returns the price. - * - * @return double - */ - public function getPrice() - { - return doubleval($this->_price); - } - - /** - * Sets the price. - * - * @param integer $price The price. - */ - public function setPrice($price) - { - $this->_price = number_format($price, 2, '.', ''); - } - - /** - * Returns the date describing for how long the price is valid. - * - * @internal The ID3v2 standard does not declare the time zone to be used - * in the date. Date must thus be expressed as GMT/UTC. - * @return Zend_Date - */ - public function getDate() - { - require_once 'Zend/Date.php'; - $date = new Zend_Date(0); - $date->setTimezone('UTC'); - $date->set($this->_date, 'yyyyMMdd'); - return $date; - } - - /** - * Sets the date describing for how long the price is valid for. - * - * @internal The ID3v2 standard does not declare the time zone to be used - * in the date. Date must thus be expressed as GMT/UTC. - * @param Zend_Date $date The date. - */ - public function setDate($date) - { - require_once 'Zend/Date.php'; - if ($date === null) { - $date = Zend_Date::now(); - } - $date->setTimezone('UTC'); - $this->_date = $date->toString('yyyyMMdd'); - } - - /** - * Returns the name of the seller. - * - * @return string - */ - public function getSeller() - { - return $this->_seller; - } - - /** - * Sets the name of the seller using given encoding. - * - * @param string $seller The name of the seller. - * @param integer $encoding The text encoding. - */ - public function setSeller($seller, $encoding = null) - { - $this->_seller = $seller; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_currency) - ->writeString8($this->_price, 1) - ->write($this->_date); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_seller, Zend_Io_Writer::LITTLE_ENDIAN_ORDER); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_seller); - break; - default: - $writer->writeString8($this->_seller); - break; - } - } -} +Ownership frame might be used as a reminder of a made transaction + * or, if signed, as proof. Note that the {@link Zend_Media_Id3_Frame_User USER} + * and {@link Zend_Media_Id3_Frame_Town TOWN} frames are good to use in + * conjunction with this one. + * + * There may only be one OWNE frame in a tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Owne.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Owne extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_currency = 'EUR'; + + /** @var string */ + private $_price; + + /** @var string */ + private $_date; + + /** @var string */ + private $_seller; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_currency = strtoupper($this->_reader->read(3)); + $offset = $this->_reader->getOffset(); + list ($this->_price) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset($offset + strlen($this->_price) + 1); + $this->_date = $this->_reader->read(8); + $this->_seller = $this->_convertString + ($this->_reader->read($this->_reader->getSize()), $encoding); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the currency code, encoded according to + * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm + * ISO 4217} alphabetic currency code. + * + * @return string + */ + public function getCurrency() + { + return $this->_currency; + } + + /** + * Sets the currency used in transaction, encoded according to + * {@link http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm + * ISO 4217} alphabetic currency code. + * + * @param string $currency The currency code. + */ + public function setCurrency($currency) + { + $this->_currency = strtoupper($currency); + } + + /** + * Returns the price. + * + * @return double + */ + public function getPrice() + { + return doubleval($this->_price); + } + + /** + * Sets the price. + * + * @param integer $price The price. + */ + public function setPrice($price) + { + $this->_price = number_format($price, 2, '.', ''); + } + + /** + * Returns the date describing for how long the price is valid. + * + * @internal The ID3v2 standard does not declare the time zone to be used + * in the date. Date must thus be expressed as GMT/UTC. + * @return Zend_Date + */ + public function getDate() + { + require_once 'Zend/Date.php'; + $date = new Zend_Date(0); + $date->setTimezone('UTC'); + $date->set($this->_date, 'yyyyMMdd'); + return $date; + } + + /** + * Sets the date describing for how long the price is valid for. + * + * @internal The ID3v2 standard does not declare the time zone to be used + * in the date. Date must thus be expressed as GMT/UTC. + * @param Zend_Date $date The date. + */ + public function setDate($date) + { + require_once 'Zend/Date.php'; + if ($date === null) { + $date = Zend_Date::now(); + } + $date->setTimezone('UTC'); + $this->_date = $date->toString('yyyyMMdd'); + } + + /** + * Returns the name of the seller. + * + * @return string + */ + public function getSeller() + { + return $this->_seller; + } + + /** + * Sets the name of the seller using given encoding. + * + * @param string $seller The name of the seller. + * @param integer $encoding The text encoding. + */ + public function setSeller($seller, $encoding = null) + { + $this->_seller = $seller; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_currency) + ->writeString8($this->_price, 1) + ->write($this->_date); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_seller, Zend_Io_Writer::LITTLE_ENDIAN_ORDER); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_seller); + break; + default: + $writer->writeString8($this->_seller); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Pcnt.php b/app/libs/vendor/Zend/Media/Id3/Frame/Pcnt.php index 37a08314..e4a76f5e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Pcnt.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Pcnt.php @@ -1,110 +1,110 @@ -Play counter is simply a counter of the number of times a file has - * been played. The value is increased by one every time the file begins to - * play. There may only be one PCNT frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Pcnt.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Pcnt extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_counter = 0; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - if ($this->_reader->getSize() > 4) { - $this->_counter = $this->_reader->readInt64BE(); // UInt64 - } else { - $this->_counter = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns the counter. - * - * @return integer - */ - public function getCounter() - { - return $this->_counter; - } - - /** - * Adds counter by one. - */ - public function addCounter() - { - $this->_counter++; - } - - /** - * Sets the counter value. - * - * @param integer $counter The counter value. - */ - public function setCounter($counter) - { - $this->_counter = $counter; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - if ($this->_counter > 4294967295) { - $writer->writeInt64BE($this->_counter); // UInt64 - } else { - $writer->writeUInt32BE($this->_counter); - } - } -} +Play counter is simply a counter of the number of times a file has + * been played. The value is increased by one every time the file begins to + * play. There may only be one PCNT frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Pcnt.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Pcnt extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_counter = 0; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + if ($this->_reader->getSize() > 4) { + $this->_counter = $this->_reader->readInt64BE(); // UInt64 + } else { + $this->_counter = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns the counter. + * + * @return integer + */ + public function getCounter() + { + return $this->_counter; + } + + /** + * Adds counter by one. + */ + public function addCounter() + { + $this->_counter++; + } + + /** + * Sets the counter value. + * + * @param integer $counter The counter value. + */ + public function setCounter($counter) + { + $this->_counter = $counter; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + if ($this->_counter > 4294967295) { + $writer->writeInt64BE($this->_counter); // UInt64 + } else { + $writer->writeUInt32BE($this->_counter); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Popm.php b/app/libs/vendor/Zend/Media/Id3/Frame/Popm.php index 9e2aed16..3d5e2d6a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Popm.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Popm.php @@ -1,176 +1,176 @@ -Popularimeter frame is to specify how good an audio - * file is. Many interesting applications could be found to this frame such as a - * playlist that features better audio files more often than others or it could - * be used to profile a person's taste and find other good files by comparing - * people's profiles. The frame contains the email address to the user, one - * rating byte and a four byte play counter, intended to be increased with one - * for every time the file is played. - * - * The rating is 1-255 where 1 is worst and 255 is best. 0 is unknown. If no - * personal counter is wanted it may be omitted. When the counter reaches all - * one's, one byte is inserted in front of the counter thus making the counter - * eight bits bigger in the same away as the play counter - * {@link Zend_Media_Id3_Frame_Pcnt PCNT}. There may be more than one POPM frame - * in each tag, but only one with the same email address. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Popm.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Popm extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var integer */ - private $_rating = 0; - - /** @var integer */ - private $_counter = 0; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list ($this->_owner) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(strlen($this->_owner) + 1); - $this->_rating = $this->_reader->readUInt8(); - - if ($this->_reader->getSize() - strlen($this->_owner) - 2 > 4) { - $this->_counter = - $this->_reader->readInt64BE(); // UInt64 - } else if ($this->_reader->available() > 0) { - $this->_counter = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - return $this->_owner = $owner; - } - - /** - * Returns the user rating. - * - * @return integer - */ - public function getRating() - { - return $this->_rating; - } - - /** - * Sets the user rating. - * - * @param integer $rating The user rating. - */ - public function setRating($rating) - { - $this->_rating = $rating; - } - - /** - * Returns the counter. - * - * @return integer - */ - public function getCounter() - { - return $this->_counter; - } - - /** - * Adds counter by one. - */ - public function addCounter() - { - $this->_counter++; - } - - /** - * Sets the counter value. - * - * @param integer $counter The counter value. - */ - public function setCounter($counter) - { - $this->_counter = $counter; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->writeInt8($this->_rating); - if ($this->_counter > 0xffffffff) { - $writer->writeInt64BE($this->_counter); - } else if ($this->_counter > 0) { - $writer->writeUInt32BE($this->_counter); - } - } -} +Popularimeter frame is to specify how good an audio + * file is. Many interesting applications could be found to this frame such as a + * playlist that features better audio files more often than others or it could + * be used to profile a person's taste and find other good files by comparing + * people's profiles. The frame contains the email address to the user, one + * rating byte and a four byte play counter, intended to be increased with one + * for every time the file is played. + * + * The rating is 1-255 where 1 is worst and 255 is best. 0 is unknown. If no + * personal counter is wanted it may be omitted. When the counter reaches all + * one's, one byte is inserted in front of the counter thus making the counter + * eight bits bigger in the same away as the play counter + * {@link Zend_Media_Id3_Frame_Pcnt PCNT}. There may be more than one POPM frame + * in each tag, but only one with the same email address. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Popm.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Popm extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var integer */ + private $_rating = 0; + + /** @var integer */ + private $_counter = 0; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list ($this->_owner) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(strlen($this->_owner) + 1); + $this->_rating = $this->_reader->readUInt8(); + + if ($this->_reader->getSize() - strlen($this->_owner) - 2 > 4) { + $this->_counter = + $this->_reader->readInt64BE(); // UInt64 + } else if ($this->_reader->available() > 0) { + $this->_counter = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + return $this->_owner = $owner; + } + + /** + * Returns the user rating. + * + * @return integer + */ + public function getRating() + { + return $this->_rating; + } + + /** + * Sets the user rating. + * + * @param integer $rating The user rating. + */ + public function setRating($rating) + { + $this->_rating = $rating; + } + + /** + * Returns the counter. + * + * @return integer + */ + public function getCounter() + { + return $this->_counter; + } + + /** + * Adds counter by one. + */ + public function addCounter() + { + $this->_counter++; + } + + /** + * Sets the counter value. + * + * @param integer $counter The counter value. + */ + public function setCounter($counter) + { + $this->_counter = $counter; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->writeInt8($this->_rating); + if ($this->_counter > 0xffffffff) { + $writer->writeInt64BE($this->_counter); + } else if ($this->_counter > 0) { + $writer->writeUInt32BE($this->_counter); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Poss.php b/app/libs/vendor/Zend/Media/Id3/Frame/Poss.php index 5dd15c92..a5c7feba 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Poss.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Poss.php @@ -1,129 +1,129 @@ -Position synchronisation frame delivers information to the - * listener of how far into the audio stream he picked up; in effect, it states - * the time offset from the first frame in the stream. There may only be one - * POSS frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Poss.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Poss extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Timing -{ - /** @var integer */ - private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; - - /** @var integer */ - private $_position; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_format = $this->_reader->readUInt8(); - $this->_position = $this->_reader->readUInt32BE(); - } - - /** - * Returns the timing format. - * - * @return integer - */ - public function getFormat() - { - return $this->_format; - } - - /** - * Sets the timing format. - * - * @see Zend_Media_Id3_Timing - * @param integer $format The timing format. - */ - public function setFormat($format) - { - $this->_format = $format; - } - - /** - * Returns the position where in the audio the listener starts to receive, - * i.e. the beginning of the next frame. - * - * @return integer - */ - public function getPosition() - { - return $this->_position; - } - - /** - * Sets the position where in the audio the listener starts to receive, - * i.e. the beginning of the next frame, using given format. - * - * @param integer $position The position. - * @param integer $format The timing format. - */ - public function setPosition($position, $format = null) - { - $this->_position = $position; - if ($format !== null) { - $this->setFormat($format); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_format) - ->writeUInt32BE($this->_position); - } -} +Position synchronisation frame delivers information to the + * listener of how far into the audio stream he picked up; in effect, it states + * the time offset from the first frame in the stream. There may only be one + * POSS frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Poss.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Poss extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Timing +{ + /** @var integer */ + private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; + + /** @var integer */ + private $_position; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_format = $this->_reader->readUInt8(); + $this->_position = $this->_reader->readUInt32BE(); + } + + /** + * Returns the timing format. + * + * @return integer + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the timing format. + * + * @see Zend_Media_Id3_Timing + * @param integer $format The timing format. + */ + public function setFormat($format) + { + $this->_format = $format; + } + + /** + * Returns the position where in the audio the listener starts to receive, + * i.e. the beginning of the next frame. + * + * @return integer + */ + public function getPosition() + { + return $this->_position; + } + + /** + * Sets the position where in the audio the listener starts to receive, + * i.e. the beginning of the next frame, using given format. + * + * @param integer $position The position. + * @param integer $format The timing format. + */ + public function setPosition($position, $format = null) + { + $this->_position = $position; + if ($format !== null) { + $this->setFormat($format); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_format) + ->writeUInt32BE($this->_position); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Priv.php b/app/libs/vendor/Zend/Media/Id3/Frame/Priv.php index 3e533000..954857be 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Priv.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Priv.php @@ -1,125 +1,125 @@ -Private frame is used to contain information from a software - * producer that its program uses and does not fit into the other frames. The - * frame consists of an owner identifier string and the binary data. The owner - * identifier is URL containing an email address, or a link to a location where - * an email address can be found, that belongs to the organisation responsible - * for the frame. Questions regarding the frame should be sent to the indicated - * email address. The tag may contain more than one PRIV frame but only with - * different contents. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Priv.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Priv extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var string */ - private $_data; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list($this->_owner, $this->_data) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - $this->_owner = $owner; - } - - /** - * Returns the private binary data associated with the frame. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the private binary data associated with the frame. - * - * @param string $data The private binary data string. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->write($this->_data); - } -} +Private frame is used to contain information from a software + * producer that its program uses and does not fit into the other frames. The + * frame consists of an owner identifier string and the binary data. The owner + * identifier is URL containing an email address, or a link to a location where + * an email address can be found, that belongs to the organisation responsible + * for the frame. Questions regarding the frame should be sent to the indicated + * email address. The tag may contain more than one PRIV frame but only with + * different contents. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Priv.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Priv extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var string */ + private $_data; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list($this->_owner, $this->_data) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + $this->_owner = $owner; + } + + /** + * Returns the private binary data associated with the frame. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the private binary data associated with the frame. + * + * @param string $data The private binary data string. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Rbuf.php b/app/libs/vendor/Zend/Media/Id3/Frame/Rbuf.php index 0f9192fa..104c54c3 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Rbuf.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Rbuf.php @@ -1,190 +1,190 @@ -Recommended buffer size frame. If the embedded info - * flag is set then this indicates that an ID3 tag with the maximum size - * described in buffer size may occur in the audio stream. In such case the tag - * should reside between two MPEG frames, if the audio is MPEG encoded. If the - * position of the next tag is known, offset to next tag may be used. The offset - * is calculated from the end of tag in which this frame resides to the first - * byte of the header in the next. This field may be omitted. Embedded tags are - * generally not recommended since this could render unpredictable behaviour - * from present software/hardware. - * - * For applications like streaming audio it might be an idea to embed tags into - * the audio stream though. If the clients connects to individual connections - * like HTTP and there is a possibility to begin every transmission with a tag, - * then this tag should include a recommended buffer size frame. If the client - * is connected to a arbitrary point in the stream, such as radio or multicast, - * then the recommended buffer size frame should be included in every tag. - * - * The buffer size should be kept to a minimum. There may only be one RBUF - * frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rbuf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Rbuf extends Zend_Media_Id3_Frame -{ - /** - * A flag to denote that an ID3 tag with the maximum size described in - * buffer size may occur in the audio stream. - */ - const EMBEDDED = 0x1; - - /** @var integer */ - private $_bufferSize; - - /** @var integer */ - private $_infoFlags; - - /** @var integer */ - private $_offset = 0; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - // Who designs frames with 3 byte integers?? - $this->_reader = new Zend_Io_StringReader - ("\0" . $this->_reader->read($this->_reader->getSize())); - - $this->_bufferSize = $this->_reader->readUInt32BE(); - $this->_infoFlags = $this->_reader->readInt8(); - if ($this->_reader->available()) { - $this->_offset = $this->_reader->readInt32BE(); - } - } - - /** - * Returns the buffer size. - * - * @return integer - */ - public function getBufferSize() - { - return $this->_bufferSize; - } - - /** - * Sets the buffer size. - * - * @param integer $size The buffer size. - */ - public function setBufferSize($bufferSize) - { - $this->_bufferSize = $bufferSize; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasInfoFlag($flag) - { - return ($this->_infoFlags & $flag) == $flag; - } - - /** - * Returns the flags byte. - * - * @return integer - */ - public function getInfoFlags() - { - return $this->_infoFlags; - } - - /** - * Sets the flags byte. - * - * @param string $flags The flags byte. - */ - public function setInfoFlags($infoFlags) - { - $this->_infoFlags = $infoFlags; - } - - /** - * Returns the offset to next tag. - * - * @return integer - */ - public function getOffset() - { - return $this->_offset; - } - - /** - * Sets the offset to next tag. - * - * @param integer $offset The offset. - */ - public function setOffset($offset) - { - $this->_offset = $offset; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $tmp = new Zend_Io_StringWriter(); - $tmp->writeUInt32BE($this->_bufferSize); - - $writer->write(substr($tmp->toString(), 1, 3)) - ->writeInt8($this->_infoFlags) - ->writeInt32BE($this->_offset); - } -} +Recommended buffer size frame. If the embedded info + * flag is set then this indicates that an ID3 tag with the maximum size + * described in buffer size may occur in the audio stream. In such case the tag + * should reside between two MPEG frames, if the audio is MPEG encoded. If the + * position of the next tag is known, offset to next tag may be used. The offset + * is calculated from the end of tag in which this frame resides to the first + * byte of the header in the next. This field may be omitted. Embedded tags are + * generally not recommended since this could render unpredictable behaviour + * from present software/hardware. + * + * For applications like streaming audio it might be an idea to embed tags into + * the audio stream though. If the clients connects to individual connections + * like HTTP and there is a possibility to begin every transmission with a tag, + * then this tag should include a recommended buffer size frame. If the client + * is connected to a arbitrary point in the stream, such as radio or multicast, + * then the recommended buffer size frame should be included in every tag. + * + * The buffer size should be kept to a minimum. There may only be one RBUF + * frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rbuf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Rbuf extends Zend_Media_Id3_Frame +{ + /** + * A flag to denote that an ID3 tag with the maximum size described in + * buffer size may occur in the audio stream. + */ + const EMBEDDED = 0x1; + + /** @var integer */ + private $_bufferSize; + + /** @var integer */ + private $_infoFlags; + + /** @var integer */ + private $_offset = 0; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + // Who designs frames with 3 byte integers?? + $this->_reader = new Zend_Io_StringReader + ("\0" . $this->_reader->read($this->_reader->getSize())); + + $this->_bufferSize = $this->_reader->readUInt32BE(); + $this->_infoFlags = $this->_reader->readInt8(); + if ($this->_reader->available()) { + $this->_offset = $this->_reader->readInt32BE(); + } + } + + /** + * Returns the buffer size. + * + * @return integer + */ + public function getBufferSize() + { + return $this->_bufferSize; + } + + /** + * Sets the buffer size. + * + * @param integer $size The buffer size. + */ + public function setBufferSize($bufferSize) + { + $this->_bufferSize = $bufferSize; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasInfoFlag($flag) + { + return ($this->_infoFlags & $flag) == $flag; + } + + /** + * Returns the flags byte. + * + * @return integer + */ + public function getInfoFlags() + { + return $this->_infoFlags; + } + + /** + * Sets the flags byte. + * + * @param string $flags The flags byte. + */ + public function setInfoFlags($infoFlags) + { + $this->_infoFlags = $infoFlags; + } + + /** + * Returns the offset to next tag. + * + * @return integer + */ + public function getOffset() + { + return $this->_offset; + } + + /** + * Sets the offset to next tag. + * + * @param integer $offset The offset. + */ + public function setOffset($offset) + { + $this->_offset = $offset; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $tmp = new Zend_Io_StringWriter(); + $tmp->writeUInt32BE($this->_bufferSize); + + $writer->write(substr($tmp->toString(), 1, 3)) + ->writeInt8($this->_infoFlags) + ->writeInt32BE($this->_offset); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Rva2.php b/app/libs/vendor/Zend/Media/Id3/Frame/Rva2.php index 9acb7703..b1f280fa 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Rva2.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Rva2.php @@ -1,213 +1,213 @@ -Relative volume adjustment (2) frame is a more subjective frame - * than the previous ones. It allows the user to say how much he wants to - * increase/decrease the volume on each channel when the file is played. The - * purpose is to be able to align all files to a reference volume, so that you - * don't have to change the volume constantly. This frame may also be used to - * balance adjust the audio. - * - * The volume adjustment is encoded in a way giving the scale of +/- 64 dB with - * a precision of 0.001953125 dB. - * - * There may be more than one RVA2 frame in each tag, but only one with the same - * identification string. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rva2.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Rva2 extends Zend_Media_Id3_Frame -{ - /** - * The channel type key. - * - * @see $types - * @var string - */ - const channelType = 'channelType'; - - /** - * The volume adjustment key. Adjustments are +/- 64 dB with a precision of - * 0.001953125 dB. - * - * @var string - */ - const volumeAdjustment = 'volumeAdjustment'; - - /** - * The peak volume key. - * - * @var string - */ - const peakVolume = 'peakVolume'; - - /** - * The list of channel types. - * - * @var Array - */ - public static $types = array - ('Other', 'Master volume', 'Front right', 'Front left', 'Back right', - 'Back left', 'Front centre', 'Back centre', 'Subwoofer'); - - /** @var string */ - private $_device; - - /** @var Array */ - private $_adjustments; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list ($this->_device) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_reader->setOffset(strlen($this->_device) + 1); - - for ($i = $j = 0; $i < 9; $i++) { - $this->_adjustments[$i] = array - (self::channelType => $this->_reader->readInt8(), - self::volumeAdjustment => - $this->_reader->readInt16BE() / 512.0); - $bitsInPeak = $this->_reader->readInt8(); - $bytesInPeak = $bitsInPeak > 0 ? ceil($bitsInPeak / 8) : 0; - switch ($bytesInPeak) { - case 8: - $this->_adjustments[$i][self::peakVolume] = - $this->_reader->readInt64BE(); - break; - case 4: - $this->_adjustments[$i][self::peakVolume] = - $this->_reader->readUInt32BE(); - break; - case 2: - $this->_adjustments[$i][self::peakVolume] = - $this->_reader->readUInt16BE(); - break; - case 1: - $this->_adjustments[$i][self::peakVolume] = - $this->_reader->readUInt8(); - break; - default: - break; - } - } - } - - /** - * Returns the device where the adjustments should apply. - * - * @return string - */ - public function getDevice() - { - return $this->_device; - } - - /** - * Sets the device where the adjustments should apply. - * - * @param string $device The device. - */ - public function setDevice($device) - { - $this->_device = $device; - } - - /** - * Returns the array containing volume adjustments for each channel. Volume - * adjustments are arrays themselves containing the following keys: - * channelType, volumeAdjustment, peakVolume. - * - * @return Array - */ - public function getAdjustments() - { - return $this->_adjustments; - } - - /** - * Sets the array of volume adjustments for each channel. Each volume - * adjustment is an array too containing the following keys: channelType, - * volumeAdjustment, peakVolume. - * - * @param Array $adjustments The volume adjustments array. - */ - public function setAdjustments($adjustments) - { - $this->_adjustments = $adjustments; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_device, 1); - foreach ($this->_adjustments as $channel) { - $writer->writeInt8($channel[self::channelType]) - ->writeInt16BE($channel[self::volumeAdjustment] * 512); - if (abs($channel[self::peakVolume]) <= 0xff) { - $writer->writeInt8(8) - ->writeUInt8($channel[self::peakVolume]); - } else if (abs($channel[self::peakVolume]) <= 0xffff) { - $writer->writeInt8(16) - ->writeUInt16BE($channel[self::peakVolume]); - } else if (abs($channel[self::peakVolume]) <= 0xffffffff) { - $writer->writeInt8(32) - ->writeUInt32BE($channel[self::peakVolume]); - } else { - $writer->writeInt8(64) - ->writeInt64BE($channel[self::peakVolume]); // UInt64 - } - } - } -} +Relative volume adjustment (2) frame is a more subjective frame + * than the previous ones. It allows the user to say how much he wants to + * increase/decrease the volume on each channel when the file is played. The + * purpose is to be able to align all files to a reference volume, so that you + * don't have to change the volume constantly. This frame may also be used to + * balance adjust the audio. + * + * The volume adjustment is encoded in a way giving the scale of +/- 64 dB with + * a precision of 0.001953125 dB. + * + * There may be more than one RVA2 frame in each tag, but only one with the same + * identification string. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rva2.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Rva2 extends Zend_Media_Id3_Frame +{ + /** + * The channel type key. + * + * @see $types + * @var string + */ + const channelType = 'channelType'; + + /** + * The volume adjustment key. Adjustments are +/- 64 dB with a precision of + * 0.001953125 dB. + * + * @var string + */ + const volumeAdjustment = 'volumeAdjustment'; + + /** + * The peak volume key. + * + * @var string + */ + const peakVolume = 'peakVolume'; + + /** + * The list of channel types. + * + * @var Array + */ + public static $types = array + ('Other', 'Master volume', 'Front right', 'Front left', 'Back right', + 'Back left', 'Front centre', 'Back centre', 'Subwoofer'); + + /** @var string */ + private $_device; + + /** @var Array */ + private $_adjustments; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list ($this->_device) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_reader->setOffset(strlen($this->_device) + 1); + + for ($i = $j = 0; $i < 9; $i++) { + $this->_adjustments[$i] = array + (self::channelType => $this->_reader->readInt8(), + self::volumeAdjustment => + $this->_reader->readInt16BE() / 512.0); + $bitsInPeak = $this->_reader->readInt8(); + $bytesInPeak = $bitsInPeak > 0 ? ceil($bitsInPeak / 8) : 0; + switch ($bytesInPeak) { + case 8: + $this->_adjustments[$i][self::peakVolume] = + $this->_reader->readInt64BE(); + break; + case 4: + $this->_adjustments[$i][self::peakVolume] = + $this->_reader->readUInt32BE(); + break; + case 2: + $this->_adjustments[$i][self::peakVolume] = + $this->_reader->readUInt16BE(); + break; + case 1: + $this->_adjustments[$i][self::peakVolume] = + $this->_reader->readUInt8(); + break; + default: + break; + } + } + } + + /** + * Returns the device where the adjustments should apply. + * + * @return string + */ + public function getDevice() + { + return $this->_device; + } + + /** + * Sets the device where the adjustments should apply. + * + * @param string $device The device. + */ + public function setDevice($device) + { + $this->_device = $device; + } + + /** + * Returns the array containing volume adjustments for each channel. Volume + * adjustments are arrays themselves containing the following keys: + * channelType, volumeAdjustment, peakVolume. + * + * @return Array + */ + public function getAdjustments() + { + return $this->_adjustments; + } + + /** + * Sets the array of volume adjustments for each channel. Each volume + * adjustment is an array too containing the following keys: channelType, + * volumeAdjustment, peakVolume. + * + * @param Array $adjustments The volume adjustments array. + */ + public function setAdjustments($adjustments) + { + $this->_adjustments = $adjustments; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_device, 1); + foreach ($this->_adjustments as $channel) { + $writer->writeInt8($channel[self::channelType]) + ->writeInt16BE($channel[self::volumeAdjustment] * 512); + if (abs($channel[self::peakVolume]) <= 0xff) { + $writer->writeInt8(8) + ->writeUInt8($channel[self::peakVolume]); + } else if (abs($channel[self::peakVolume]) <= 0xffff) { + $writer->writeInt8(16) + ->writeUInt16BE($channel[self::peakVolume]); + } else if (abs($channel[self::peakVolume]) <= 0xffffffff) { + $writer->writeInt8(32) + ->writeUInt32BE($channel[self::peakVolume]); + } else { + $writer->writeInt8(64) + ->writeInt64BE($channel[self::peakVolume]); // UInt64 + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Rvad.php b/app/libs/vendor/Zend/Media/Id3/Frame/Rvad.php index 889f979b..baa14d29 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Rvad.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Rvad.php @@ -1,238 +1,238 @@ -Relative volume adjustment frame is a more subjective function - * than the previous ones. It allows the user to say how much he wants to - * increase/decrease the volume on each channel while the file is played. The - * purpose is to be able to align all files to a reference volume, so that you - * don't have to change the volume constantly. This frame may also be used to - * balance adjust the audio. - * - * There may only be one RVAD frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rvad.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Rvad extends Zend_Media_Id3_Frame -{ - /* The required keys. */ - - /** @var string */ - const right = 'right'; - - /** @var string */ - const left = 'left'; - - /** @var string */ - const peakRight = 'peakRight'; - - /** @var string */ - const peakLeft = 'peakLeft'; - - /* The optional keys. */ - - /** @var string */ - const rightBack = 'rightBack'; - - /** @var string */ - const leftBack = 'leftBack'; - - /** @var string */ - const peakRightBack = 'peakRightBack'; - - /** @var string */ - const peakLeftBack = 'peakLeftBack'; - - /** @var string */ - const center = 'center'; - - /** @var string */ - const peakCenter = 'peakCenter'; - - /** @var string */ - const bass = 'bass'; - - /** @var string */ - const peakBass = 'peakBass'; - - /** @var Array */ - private $_adjustments; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $flags = $this->_reader->readInt8(); - $descriptionBits = $this->_reader->readInt8(); - if ($descriptionBits <= 8 || $descriptionBits > 16) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('Unsupported description bit size of: ' . $descriptionBits); - } - - $this->_adjustments[self::right] = - ($flags & 0x1) == 0x1 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::left] = - ($flags & 0x2) == 0x2 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::peakRight] = $this->_reader->readUInt16BE(); - $this->_adjustments[self::peakLeft] = $this->_reader->readUInt16BE(); - - if (!$this->_reader->available()) { - return; - } - - $this->_adjustments[self::rightBack] = - ($flags & 0x4) == 0x4 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::leftBack] = - ($flags & 0x8) == 0x8 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::peakRightBack] = - $this->_reader->readUInt16BE(); - $this->_adjustments[self::peakLeftBack] = - $this->_reader->readUInt16BE(); - - if (!$this->_reader->available()) { - return; - } - - $this->_adjustments[self::center] = - ($flags & 0x10) == 0x10 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::peakCenter] = $this->_reader->readUInt16BE(); - - if (!$this->_reader->available()) { - return; - } - - $this->_adjustments[self::bass] = - ($flags & 0x20) == 0x20 ? - $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); - $this->_adjustments[self::peakBass] = $this->_reader->readUInt16BE(); - } - - /** - * Returns the array containing the volume adjustments. The array must - * contain the following keys: right, left, peakRight, peakLeft. It may - * optionally contain the following keys: rightBack, leftBack, - * peakRightBack, peakLeftBack, center, peakCenter, bass, and peakBass. - * - * @return Array - */ - public function getAdjustments() - { - return $this->_adjustments; - } - - /** - * Sets the array of volume adjustments. The array must contain the - * following keys: right, left, peakRight, peakLeft. It may optionally - * contain the following keys: rightBack, leftBack, peakRightBack, - * peakLeftBack, center, peakCenter, bass, and peakBass. - * - * @param Array $adjustments The volume adjustments array. - */ - public function setAdjustments($adjustments) - { - $this->_adjustments = $adjustments; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeInt8($flags = 0); - if ($this->_adjustments[self::right] > 0) - $flags = $flags | 0x1; - if ($this->_adjustments[self::left] > 0) - $flags = $flags | 0x2; - $writer->writeInt8(16) - ->writeUInt16BE(abs($this->_adjustments[self::right])) - ->writeUInt16BE(abs($this->_adjustments[self::left])) - ->writeUInt16BE(abs($this->_adjustments[self::peakRight])) - ->writeUInt16BE(abs($this->_adjustments[self::peakLeft])); - - if (isset($this->_adjustments[self::rightBack]) && - isset($this->_adjustments[self::leftBack]) && - isset($this->_adjustments[self::peakRightBack]) && - isset($this->_adjustments[self::peakLeftBack])) { - if ($this->_adjustments[self::rightBack] > 0) - $flags = $flags | 0x4; - if ($this->_adjustments[self::leftBack] > 0) - $flags = $flags | 0x8; - $writer->writeUInt16BE(abs($this->_adjustments[self::rightBack])) - ->writeUInt16BE(abs($this->_adjustments[self::leftBack])) - ->writeUInt16BE - (abs($this->_adjustments[self::peakRightBack])) - ->writeUInt16BE - (abs($this->_adjustments[self::peakLeftBack])); - } - - if (isset($this->_adjustments[self::center]) && - isset($this->_adjustments[self::peakCenter])) { - if ($this->_adjustments[self::center] > 0) - $flags = $flags | 0x10; - $writer->writeUInt16BE(abs($this->_adjustments[self::center])) - ->writeUInt16BE(abs($this->_adjustments[self::peakCenter])); - } - - if (isset($this->_adjustments[self::bass]) && - isset($this->_adjustments[self::peakBass])) { - if ($this->_adjustments[self::bass] > 0) - $flags = $flags | 0x20; - $writer->writeUInt16BE(abs($this->_adjustments[self::bass])) - ->writeUInt16BE(abs($this->_adjustments[self::peakBass])); - } - $writer->setOffset(0); - $writer->writeInt8($flags); - } -} +Relative volume adjustment frame is a more subjective function + * than the previous ones. It allows the user to say how much he wants to + * increase/decrease the volume on each channel while the file is played. The + * purpose is to be able to align all files to a reference volume, so that you + * don't have to change the volume constantly. This frame may also be used to + * balance adjust the audio. + * + * There may only be one RVAD frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rvad.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Rvad extends Zend_Media_Id3_Frame +{ + /* The required keys. */ + + /** @var string */ + const right = 'right'; + + /** @var string */ + const left = 'left'; + + /** @var string */ + const peakRight = 'peakRight'; + + /** @var string */ + const peakLeft = 'peakLeft'; + + /* The optional keys. */ + + /** @var string */ + const rightBack = 'rightBack'; + + /** @var string */ + const leftBack = 'leftBack'; + + /** @var string */ + const peakRightBack = 'peakRightBack'; + + /** @var string */ + const peakLeftBack = 'peakLeftBack'; + + /** @var string */ + const center = 'center'; + + /** @var string */ + const peakCenter = 'peakCenter'; + + /** @var string */ + const bass = 'bass'; + + /** @var string */ + const peakBass = 'peakBass'; + + /** @var Array */ + private $_adjustments; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $flags = $this->_reader->readInt8(); + $descriptionBits = $this->_reader->readInt8(); + if ($descriptionBits <= 8 || $descriptionBits > 16) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('Unsupported description bit size of: ' . $descriptionBits); + } + + $this->_adjustments[self::right] = + ($flags & 0x1) == 0x1 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::left] = + ($flags & 0x2) == 0x2 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::peakRight] = $this->_reader->readUInt16BE(); + $this->_adjustments[self::peakLeft] = $this->_reader->readUInt16BE(); + + if (!$this->_reader->available()) { + return; + } + + $this->_adjustments[self::rightBack] = + ($flags & 0x4) == 0x4 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::leftBack] = + ($flags & 0x8) == 0x8 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::peakRightBack] = + $this->_reader->readUInt16BE(); + $this->_adjustments[self::peakLeftBack] = + $this->_reader->readUInt16BE(); + + if (!$this->_reader->available()) { + return; + } + + $this->_adjustments[self::center] = + ($flags & 0x10) == 0x10 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::peakCenter] = $this->_reader->readUInt16BE(); + + if (!$this->_reader->available()) { + return; + } + + $this->_adjustments[self::bass] = + ($flags & 0x20) == 0x20 ? + $this->_reader->readUInt16BE() : -$this->_reader->readUInt16BE(); + $this->_adjustments[self::peakBass] = $this->_reader->readUInt16BE(); + } + + /** + * Returns the array containing the volume adjustments. The array must + * contain the following keys: right, left, peakRight, peakLeft. It may + * optionally contain the following keys: rightBack, leftBack, + * peakRightBack, peakLeftBack, center, peakCenter, bass, and peakBass. + * + * @return Array + */ + public function getAdjustments() + { + return $this->_adjustments; + } + + /** + * Sets the array of volume adjustments. The array must contain the + * following keys: right, left, peakRight, peakLeft. It may optionally + * contain the following keys: rightBack, leftBack, peakRightBack, + * peakLeftBack, center, peakCenter, bass, and peakBass. + * + * @param Array $adjustments The volume adjustments array. + */ + public function setAdjustments($adjustments) + { + $this->_adjustments = $adjustments; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeInt8($flags = 0); + if ($this->_adjustments[self::right] > 0) + $flags = $flags | 0x1; + if ($this->_adjustments[self::left] > 0) + $flags = $flags | 0x2; + $writer->writeInt8(16) + ->writeUInt16BE(abs($this->_adjustments[self::right])) + ->writeUInt16BE(abs($this->_adjustments[self::left])) + ->writeUInt16BE(abs($this->_adjustments[self::peakRight])) + ->writeUInt16BE(abs($this->_adjustments[self::peakLeft])); + + if (isset($this->_adjustments[self::rightBack]) && + isset($this->_adjustments[self::leftBack]) && + isset($this->_adjustments[self::peakRightBack]) && + isset($this->_adjustments[self::peakLeftBack])) { + if ($this->_adjustments[self::rightBack] > 0) + $flags = $flags | 0x4; + if ($this->_adjustments[self::leftBack] > 0) + $flags = $flags | 0x8; + $writer->writeUInt16BE(abs($this->_adjustments[self::rightBack])) + ->writeUInt16BE(abs($this->_adjustments[self::leftBack])) + ->writeUInt16BE + (abs($this->_adjustments[self::peakRightBack])) + ->writeUInt16BE + (abs($this->_adjustments[self::peakLeftBack])); + } + + if (isset($this->_adjustments[self::center]) && + isset($this->_adjustments[self::peakCenter])) { + if ($this->_adjustments[self::center] > 0) + $flags = $flags | 0x10; + $writer->writeUInt16BE(abs($this->_adjustments[self::center])) + ->writeUInt16BE(abs($this->_adjustments[self::peakCenter])); + } + + if (isset($this->_adjustments[self::bass]) && + isset($this->_adjustments[self::peakBass])) { + if ($this->_adjustments[self::bass] > 0) + $flags = $flags | 0x20; + $writer->writeUInt16BE(abs($this->_adjustments[self::bass])) + ->writeUInt16BE(abs($this->_adjustments[self::peakBass])); + } + $writer->setOffset(0); + $writer->writeInt8($flags); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Rvrb.php b/app/libs/vendor/Zend/Media/Id3/Frame/Rvrb.php index 93904471..87705347 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Rvrb.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Rvrb.php @@ -1,331 +1,331 @@ -Reverb is yet another subjective frame, with which you can adjust - * echoes of different kinds. Reverb left/right is the delay between every - * bounce in milliseconds. Reverb bounces left/right is the number of bounces - * that should be made. $FF equals an infinite number of bounces. Feedback is - * the amount of volume that should be returned to the next echo bounce. $00 is - * 0%, $FF is 100%. If this value were $7F, there would be 50% volume reduction - * on the first bounce, 50% of that on the second and so on. Left to left means - * the sound from the left bounce to be played in the left speaker, while left - * to right means sound from the left bounce to be played in the right speaker. - * - * Premix left to right is the amount of left sound to be mixed in the right - * before any reverb is applied, where $00 id 0% and $FF is 100%. Premix right - * to left does the same thing, but right to left. Setting both premix to $FF - * would result in a mono output (if the reverb is applied symmetric). There - * may only be one RVRB frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Rvrb.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Rvrb extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_reverbLeft; - - /** @var integer */ - private $_reverbRight; - - /** @var integer */ - private $_reverbBouncesLeft; - - /** @var integer */ - private $_reverbBouncesRight; - - /** @var integer */ - private $_reverbFeedbackLtoL; - - /** @var integer */ - private $_reverbFeedbackLtoR; - - /** @var integer */ - private $_reverbFeedbackRtoR; - - /** @var integer */ - private $_reverbFeedbackRtoL; - - /** @var integer */ - private $_premixLtoR; - - /** @var integer */ - private $_premixRtoL; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_reverbLeft = $this->_reader->readUInt16BE(); - $this->_reverbRight = $this->_reader->readUInt16BE(); - $this->_reverbBouncesLeft = $this->_reader->readUInt8(); - $this->_reverbBouncesRight = $this->_reader->readUInt8(); - $this->_reverbFeedbackLtoL = $this->_reader->readUInt8(); - $this->_reverbFeedbackLtoR = $this->_reader->readUInt8(); - $this->_reverbFeedbackRtoR = $this->_reader->readUInt8(); - $this->_reverbFeedbackRtoL = $this->_reader->readUInt8(); - $this->_premixLtoR = $this->_reader->readUInt8(); - $this->_premixRtoL = $this->_reader->readUInt8(); - } - - /** - * Returns the left reverb. - * - * @return integer - */ - public function getReverbLeft() - { - return $this->_reverbLeft; - } - - /** - * Sets the left reverb. - * - * @param integer $reverbLeft The left reverb. - */ - public function setReverbLeft($reverbLeft) - { - return $this->_reverbLeft = $reverbLeft; - } - - /** - * Returns the right reverb. - * - * @return integer - */ - public function getReverbRight() - { - return $this->_reverbRight; - } - - /** - * Sets the right reverb. - * - * @param integer $reverbRight The right reverb. - */ - public function setReverbRight($reverbRight) - { - return $this->_reverbRight = $reverbRight; - } - - /** - * Returns the left reverb bounces. - * - * @return integer - */ - public function getReverbBouncesLeft() - { - return $this->_reverbBouncesLeft; - } - - /** - * Sets the left reverb bounces. - * - * @param integer $reverbBouncesLeft The left reverb bounces. - */ - public function setReverbBouncesLeft($reverbBouncesLeft) - { - $this->_reverbBouncesLeft = $reverbBouncesLeft; - } - - /** - * Returns the right reverb bounces. - * - * @return integer - */ - public function getReverbBouncesRight() - { - return $this->_reverbBouncesRight; - } - - /** - * Sets the right reverb bounces. - * - * @param integer $reverbBouncesRight The right reverb bounces. - */ - public function setReverbBouncesRight($reverbBouncesRight) - { - $this->_reverbBouncesRight = $reverbBouncesRight; - } - - /** - * Returns the left-to-left reverb feedback. - * - * @return integer - */ - public function getReverbFeedbackLtoL() - { - return $this->_reverbFeedbackLtoL; - } - - /** - * Sets the left-to-left reverb feedback. - * - * @param integer $reverbFeedbackLtoL The left-to-left reverb feedback. - */ - public function setReverbFeedbackLtoL($reverbFeedbackLtoL) - { - $this->_reverbFeedbackLtoL = $reverbFeedbackLtoL; - } - - /** - * Returns the left-to-right reverb feedback. - * - * @return integer - */ - public function getReverbFeedbackLtoR() - { - return $this->_reverbFeedbackLtoR; - } - - /** - * Sets the left-to-right reverb feedback. - * - * @param integer $reverbFeedbackLtoR The left-to-right reverb feedback. - */ - public function setReverbFeedbackLtoR($reverbFeedbackLtoR) - { - $this->_reverbFeedbackLtoR = $reverbFeedbackLtoR; - } - - /** - * Returns the right-to-right reverb feedback. - * - * @return integer - */ - public function getReverbFeedbackRtoR() - { - return $this->_reverbFeedbackRtoR; - } - - /** - * Sets the right-to-right reverb feedback. - * - * @param integer $reverbFeedbackRtoR The right-to-right reverb feedback. - */ - public function setReverbFeedbackRtoR($reverbFeedbackRtoR) - { - $this->_reverbFeedbackRtoR = $reverbFeedbackRtoR; - } - - /** - * Returns the right-to-left reverb feedback. - * - * @return integer - */ - public function getReverbFeedbackRtoL() - { - return $this->_reverbFeedbackRtoL; - } - - /** - * Sets the right-to-left reverb feedback. - * - * @param integer $reverbFeedbackRtoL The right-to-left reverb feedback. - */ - public function setReverbFeedbackRtoL($reverbFeedbackRtoL) - { - $this->_reverbFeedbackRtoL = $reverbFeedbackRtoL; - } - - /** - * Returns the left-to-right premix. - * - * @return integer - */ - public function getPremixLtoR() - { - return $this->_premixLtoR; - } - - /** - * Sets the left-to-right premix. - * - * @param integer $premixLtoR The left-to-right premix. - */ - public function setPremixLtoR($premixLtoR) - { - $this->_premixLtoR = $premixLtoR; - } - - /** - * Returns the right-to-left premix. - * - * @return integer - */ - public function getPremixRtoL() - { - return $this->_premixRtoL; - } - - /** - * Sets the right-to-left premix. - * - * @param integer $premixRtoL The right-to-left premix. - */ - public function setPremixRtoL($premixRtoL) - { - $this->_premixRtoL = $premixRtoL; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt16BE($this->_reverbLeft) - ->writeUInt16BE($this->_reverbRight) - ->writeUInt8($this->_reverbBouncesLeft) - ->writeUInt8($this->_reverbBouncesRight) - ->writeUInt8($this->_reverbFeedbackLtoL) - ->writeUInt8($this->_reverbFeedbackLtoR) - ->writeUInt8($this->_reverbFeedbackRtoR) - ->writeUInt8($this->_reverbFeedbackRtoL) - ->writeUInt8($this->_premixLtoR) - ->writeUInt8($this->_premixRtoL); - } -} +Reverb is yet another subjective frame, with which you can adjust + * echoes of different kinds. Reverb left/right is the delay between every + * bounce in milliseconds. Reverb bounces left/right is the number of bounces + * that should be made. $FF equals an infinite number of bounces. Feedback is + * the amount of volume that should be returned to the next echo bounce. $00 is + * 0%, $FF is 100%. If this value were $7F, there would be 50% volume reduction + * on the first bounce, 50% of that on the second and so on. Left to left means + * the sound from the left bounce to be played in the left speaker, while left + * to right means sound from the left bounce to be played in the right speaker. + * + * Premix left to right is the amount of left sound to be mixed in the right + * before any reverb is applied, where $00 id 0% and $FF is 100%. Premix right + * to left does the same thing, but right to left. Setting both premix to $FF + * would result in a mono output (if the reverb is applied symmetric). There + * may only be one RVRB frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Rvrb.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Rvrb extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_reverbLeft; + + /** @var integer */ + private $_reverbRight; + + /** @var integer */ + private $_reverbBouncesLeft; + + /** @var integer */ + private $_reverbBouncesRight; + + /** @var integer */ + private $_reverbFeedbackLtoL; + + /** @var integer */ + private $_reverbFeedbackLtoR; + + /** @var integer */ + private $_reverbFeedbackRtoR; + + /** @var integer */ + private $_reverbFeedbackRtoL; + + /** @var integer */ + private $_premixLtoR; + + /** @var integer */ + private $_premixRtoL; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_reverbLeft = $this->_reader->readUInt16BE(); + $this->_reverbRight = $this->_reader->readUInt16BE(); + $this->_reverbBouncesLeft = $this->_reader->readUInt8(); + $this->_reverbBouncesRight = $this->_reader->readUInt8(); + $this->_reverbFeedbackLtoL = $this->_reader->readUInt8(); + $this->_reverbFeedbackLtoR = $this->_reader->readUInt8(); + $this->_reverbFeedbackRtoR = $this->_reader->readUInt8(); + $this->_reverbFeedbackRtoL = $this->_reader->readUInt8(); + $this->_premixLtoR = $this->_reader->readUInt8(); + $this->_premixRtoL = $this->_reader->readUInt8(); + } + + /** + * Returns the left reverb. + * + * @return integer + */ + public function getReverbLeft() + { + return $this->_reverbLeft; + } + + /** + * Sets the left reverb. + * + * @param integer $reverbLeft The left reverb. + */ + public function setReverbLeft($reverbLeft) + { + return $this->_reverbLeft = $reverbLeft; + } + + /** + * Returns the right reverb. + * + * @return integer + */ + public function getReverbRight() + { + return $this->_reverbRight; + } + + /** + * Sets the right reverb. + * + * @param integer $reverbRight The right reverb. + */ + public function setReverbRight($reverbRight) + { + return $this->_reverbRight = $reverbRight; + } + + /** + * Returns the left reverb bounces. + * + * @return integer + */ + public function getReverbBouncesLeft() + { + return $this->_reverbBouncesLeft; + } + + /** + * Sets the left reverb bounces. + * + * @param integer $reverbBouncesLeft The left reverb bounces. + */ + public function setReverbBouncesLeft($reverbBouncesLeft) + { + $this->_reverbBouncesLeft = $reverbBouncesLeft; + } + + /** + * Returns the right reverb bounces. + * + * @return integer + */ + public function getReverbBouncesRight() + { + return $this->_reverbBouncesRight; + } + + /** + * Sets the right reverb bounces. + * + * @param integer $reverbBouncesRight The right reverb bounces. + */ + public function setReverbBouncesRight($reverbBouncesRight) + { + $this->_reverbBouncesRight = $reverbBouncesRight; + } + + /** + * Returns the left-to-left reverb feedback. + * + * @return integer + */ + public function getReverbFeedbackLtoL() + { + return $this->_reverbFeedbackLtoL; + } + + /** + * Sets the left-to-left reverb feedback. + * + * @param integer $reverbFeedbackLtoL The left-to-left reverb feedback. + */ + public function setReverbFeedbackLtoL($reverbFeedbackLtoL) + { + $this->_reverbFeedbackLtoL = $reverbFeedbackLtoL; + } + + /** + * Returns the left-to-right reverb feedback. + * + * @return integer + */ + public function getReverbFeedbackLtoR() + { + return $this->_reverbFeedbackLtoR; + } + + /** + * Sets the left-to-right reverb feedback. + * + * @param integer $reverbFeedbackLtoR The left-to-right reverb feedback. + */ + public function setReverbFeedbackLtoR($reverbFeedbackLtoR) + { + $this->_reverbFeedbackLtoR = $reverbFeedbackLtoR; + } + + /** + * Returns the right-to-right reverb feedback. + * + * @return integer + */ + public function getReverbFeedbackRtoR() + { + return $this->_reverbFeedbackRtoR; + } + + /** + * Sets the right-to-right reverb feedback. + * + * @param integer $reverbFeedbackRtoR The right-to-right reverb feedback. + */ + public function setReverbFeedbackRtoR($reverbFeedbackRtoR) + { + $this->_reverbFeedbackRtoR = $reverbFeedbackRtoR; + } + + /** + * Returns the right-to-left reverb feedback. + * + * @return integer + */ + public function getReverbFeedbackRtoL() + { + return $this->_reverbFeedbackRtoL; + } + + /** + * Sets the right-to-left reverb feedback. + * + * @param integer $reverbFeedbackRtoL The right-to-left reverb feedback. + */ + public function setReverbFeedbackRtoL($reverbFeedbackRtoL) + { + $this->_reverbFeedbackRtoL = $reverbFeedbackRtoL; + } + + /** + * Returns the left-to-right premix. + * + * @return integer + */ + public function getPremixLtoR() + { + return $this->_premixLtoR; + } + + /** + * Sets the left-to-right premix. + * + * @param integer $premixLtoR The left-to-right premix. + */ + public function setPremixLtoR($premixLtoR) + { + $this->_premixLtoR = $premixLtoR; + } + + /** + * Returns the right-to-left premix. + * + * @return integer + */ + public function getPremixRtoL() + { + return $this->_premixRtoL; + } + + /** + * Sets the right-to-left premix. + * + * @param integer $premixRtoL The right-to-left premix. + */ + public function setPremixRtoL($premixRtoL) + { + $this->_premixRtoL = $premixRtoL; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt16BE($this->_reverbLeft) + ->writeUInt16BE($this->_reverbRight) + ->writeUInt8($this->_reverbBouncesLeft) + ->writeUInt8($this->_reverbBouncesRight) + ->writeUInt8($this->_reverbFeedbackLtoL) + ->writeUInt8($this->_reverbFeedbackLtoR) + ->writeUInt8($this->_reverbFeedbackRtoR) + ->writeUInt8($this->_reverbFeedbackRtoL) + ->writeUInt8($this->_premixLtoR) + ->writeUInt8($this->_premixRtoL); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Seek.php b/app/libs/vendor/Zend/Media/Id3/Frame/Seek.php index 090a9952..d2f5e95f 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Seek.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Seek.php @@ -1,95 +1,95 @@ -Seek frame indicates where other tags in a file/stream can be - * found. The minimum offset to next tag is calculated from the end of this tag - * to the beginning of the next. There may only be one seek frame in a tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Seek.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Seek extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_minOffset; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_minOffset = $this->_reader->readInt32BE(); - } - - /** - * Returns the minimum offset to next tag in bytes. - * - * @return integer - */ - public function getMinimumOffset() - { - return $this->_minOffset; - } - - /** - * Sets the minimum offset to next tag in bytes. - * - * @param integer $minOffset The minimum offset. - */ - public function setMinimumOffset($minOffset) - { - $this->_minOffset = $minOffset; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeInt32BE($this->_minOffset); - } -} +Seek frame indicates where other tags in a file/stream can be + * found. The minimum offset to next tag is calculated from the end of this tag + * to the beginning of the next. There may only be one seek frame in a tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Seek.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Seek extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_minOffset; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_minOffset = $this->_reader->readInt32BE(); + } + + /** + * Returns the minimum offset to next tag in bytes. + * + * @return integer + */ + public function getMinimumOffset() + { + return $this->_minOffset; + } + + /** + * Sets the minimum offset to next tag in bytes. + * + * @param integer $minOffset The minimum offset. + */ + public function setMinimumOffset($minOffset) + { + $this->_minOffset = $minOffset; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeInt32BE($this->_minOffset); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Sign.php b/app/libs/vendor/Zend/Media/Id3/Frame/Sign.php index d6796b3e..034b406a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Sign.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Sign.php @@ -1,123 +1,123 @@ -Group identification registration, to be signed. Although signatures - * can reside inside the registration frame, it might be desired to store the - * signature elsewhere, e.g. in watermarks. There may be more than one signature - * frame in a tag, but no two may be identical. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sign.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Sign extends Zend_Media_Id3_Frame -{ - /** @var integer */ - private $_group; - - /** @var string */ - private $_signature; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_group = $this->_reader->readUInt8(); - $this->_signature = $this->_reader->read($this->_reader->getSize()); - } - - /** - * Returns the group symbol byte. - * - * @return integer - */ - public function getGroup() - { - return $this->_group; - } - - /** - * Sets the group symbol byte. - * - * @param integer $group The group symbol byte. - */ - public function setGroup($group) - { - $this->_group = $group; - } - - /** - * Returns the signature binary data. - * - * @return string - */ - public function getSignature() - { - return $this->_signature; - } - - /** - * Sets the signature binary data. - * - * @param string $signature The signature binary data string. - */ - public function setSignature($signature) - { - $this->_signature = $signature; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_group) - ->write($this->_signature); - } -} +Group identification registration, to be signed. Although signatures + * can reside inside the registration frame, it might be desired to store the + * signature elsewhere, e.g. in watermarks. There may be more than one signature + * frame in a tag, but no two may be identical. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sign.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Sign extends Zend_Media_Id3_Frame +{ + /** @var integer */ + private $_group; + + /** @var string */ + private $_signature; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_group = $this->_reader->readUInt8(); + $this->_signature = $this->_reader->read($this->_reader->getSize()); + } + + /** + * Returns the group symbol byte. + * + * @return integer + */ + public function getGroup() + { + return $this->_group; + } + + /** + * Sets the group symbol byte. + * + * @param integer $group The group symbol byte. + */ + public function setGroup($group) + { + $this->_group = $group; + } + + /** + * Returns the signature binary data. + * + * @return string + */ + public function getSignature() + { + return $this->_signature; + } + + /** + * Sets the signature binary data. + * + * @param string $signature The signature binary data string. + */ + public function setSignature($signature) + { + $this->_signature = $signature; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_group) + ->write($this->_signature); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Sylt.php b/app/libs/vendor/Zend/Media/Id3/Frame/Sylt.php index d832b394..7937a5e1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Sylt.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Sylt.php @@ -1,374 +1,374 @@ -Synchronised lyrics/text frame is another way of incorporating the - * words, said or sung lyrics, in the audio file as text, this time, however, - * in sync with the audio. It might also be used to describing events e.g. - * occurring on a stage or on the screen in sync with the audio. - * - * There may be more than one SYLT frame in each tag, but only one with the - * same language and content descriptor. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sylt.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Sylt extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding, Zend_Media_Id3_Language, - Zend_Media_Id3_Timing -{ - /** - * The list of content types. - * - * @var Array - */ - public static $types = array - ('Other', 'Lyrics', 'Text transcription', 'Movement/Part name', - 'Events', 'Chord', 'Trivia', 'URLs to webpages', 'URLs to images'); - - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_language = 'und'; - - /** @var integer */ - private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; - - /** @var integer */ - private $_type = 0; - - /** @var string */ - private $_description; - - /** @var Array */ - private $_events = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_language = strtolower($this->_reader->read(3)); - if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { - $this->_language = 'und'; - } - $this->_format = $this->_reader->readUInt8(); - $this->_type = $this->_reader->readUInt8(); - - $offset = $this->_reader->getOffset(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($this->_description) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - if ($this->_reader->getSize() >= $offset + strlen($this->_description) + 2) { - $this->_reader->setOffset - ($offset + strlen($this->_description) + 2); - } - break; - case self::UTF8: - // break intentionally omitted - default: - list($this->_description) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - if ($this->_reader->getSize() >= $offset + strlen($this->_description) + 1) { - $this->_reader->setOffset - ($offset + strlen($this->_description) + 1); - } - break; - } - $this->_description = $this->_convertString($this->_description, $encoding); - - while ($this->_reader->available()) { - $offset = $this->_reader->getOffset(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($syllable) = - $this->_explodeString16 - ($this->_reader->read - ($this->_reader->getSize()), 2); - $this->_reader->setOffset - ($offset + strlen($syllable) + 2); - break; - case self::UTF8: - // break intentionally omitted - default: - list($syllable) = - $this->_explodeString8 - ($this->_reader->read - ($this->_reader->getSize()), 2); - $this->_reader->setOffset - ($offset + strlen($syllable) + 1); - break; - } - $this->_events - [$this->_reader->readUInt32BE()] = - $this->_convertString($syllable, $encoding); - } - ksort($this->_events); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the language code as specified in the - * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. - * - * @return string - */ - public function getLanguage() - { - return $this->_language; - } - - /** - * Sets the text language code as specified in the - * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. - * - * @see Zend_Media_Id3_Language - * @param string $language The language code. - */ - public function setLanguage($language) - { - $language = strtolower($language); - if ($language == 'xxx') { - $language = 'und'; - } - $this->_language = substr($language, 0, 3); - } - - /** - * Returns the timing format. - * - * @return integer - */ - public function getFormat() - { - return $this->_format; - } - - /** - * Sets the timing format. - * - * @see Zend_Media_Id3_Timing - * @param integer $format The timing format. - */ - public function setFormat($format) - { - $this->_format = $format; - } - - /** - * Returns the content type code. - * - * @return integer - */ - public function getType() - { - return $this->_type; - } - - /** - * Sets the content type code. - * - * @param integer $type The content type code. - */ - public function setType($type) - { - $this->_type = $type; - } - - /** - * Returns the content description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. The description - * language and encoding must be that of the actual text. - * - * @param string $description The content description text. - * @param string $language The language code. - * @param integer $encoding The text encoding. - */ - public function setDescription - ($description, $language = null, $encoding = null) - { - $this->_description = $description; - if ($language !== null) { - $this->setLanguage($language); - } - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Returns the syllable events with their timestamps. - * - * @return Array - */ - public function getEvents() - { - return $this->_events; - } - - /** - * Sets the syllable events with their timestamps using given encoding. - * - * The text language and encoding must be that of the description text. - * - * @param Array $text The test string. - * @param string $language The language code. - * @param integer $encoding The text encoding. - */ - public function setEvents($events, $language = null, $encoding = null) - { - $this->_events = $events; - if ($language !== null) { - $this->setLanguage($language); - } - if ($encoding !== null) { - $this->setEncoding($encoding); - } - ksort($this->_events); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_language) - ->writeUInt8($this->_format) - ->writeUInt8($this->_type); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1); - break; - default: - $writer->writeString8($this->_description, 1); - break; - } - foreach ($this->_events as $timestamp => $syllable) { - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($syllable, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($syllable, null, 1); - break; - default: - $writer->writeString8($syllable, 1); - break; - } - $writer->writeUInt32BE($timestamp); - } - } -} +Synchronised lyrics/text frame is another way of incorporating the + * words, said or sung lyrics, in the audio file as text, this time, however, + * in sync with the audio. It might also be used to describing events e.g. + * occurring on a stage or on the screen in sync with the audio. + * + * There may be more than one SYLT frame in each tag, but only one with the + * same language and content descriptor. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sylt.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Sylt extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding, Zend_Media_Id3_Language, + Zend_Media_Id3_Timing +{ + /** + * The list of content types. + * + * @var Array + */ + public static $types = array + ('Other', 'Lyrics', 'Text transcription', 'Movement/Part name', + 'Events', 'Chord', 'Trivia', 'URLs to webpages', 'URLs to images'); + + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_language = 'und'; + + /** @var integer */ + private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; + + /** @var integer */ + private $_type = 0; + + /** @var string */ + private $_description; + + /** @var Array */ + private $_events = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_language = strtolower($this->_reader->read(3)); + if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { + $this->_language = 'und'; + } + $this->_format = $this->_reader->readUInt8(); + $this->_type = $this->_reader->readUInt8(); + + $offset = $this->_reader->getOffset(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($this->_description) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + if ($this->_reader->getSize() >= $offset + strlen($this->_description) + 2) { + $this->_reader->setOffset + ($offset + strlen($this->_description) + 2); + } + break; + case self::UTF8: + // break intentionally omitted + default: + list($this->_description) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + if ($this->_reader->getSize() >= $offset + strlen($this->_description) + 1) { + $this->_reader->setOffset + ($offset + strlen($this->_description) + 1); + } + break; + } + $this->_description = $this->_convertString($this->_description, $encoding); + + while ($this->_reader->available()) { + $offset = $this->_reader->getOffset(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($syllable) = + $this->_explodeString16 + ($this->_reader->read + ($this->_reader->getSize()), 2); + $this->_reader->setOffset + ($offset + strlen($syllable) + 2); + break; + case self::UTF8: + // break intentionally omitted + default: + list($syllable) = + $this->_explodeString8 + ($this->_reader->read + ($this->_reader->getSize()), 2); + $this->_reader->setOffset + ($offset + strlen($syllable) + 1); + break; + } + $this->_events + [$this->_reader->readUInt32BE()] = + $this->_convertString($syllable, $encoding); + } + ksort($this->_events); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the language code as specified in the + * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. + * + * @return string + */ + public function getLanguage() + { + return $this->_language; + } + + /** + * Sets the text language code as specified in the + * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. + * + * @see Zend_Media_Id3_Language + * @param string $language The language code. + */ + public function setLanguage($language) + { + $language = strtolower($language); + if ($language == 'xxx') { + $language = 'und'; + } + $this->_language = substr($language, 0, 3); + } + + /** + * Returns the timing format. + * + * @return integer + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the timing format. + * + * @see Zend_Media_Id3_Timing + * @param integer $format The timing format. + */ + public function setFormat($format) + { + $this->_format = $format; + } + + /** + * Returns the content type code. + * + * @return integer + */ + public function getType() + { + return $this->_type; + } + + /** + * Sets the content type code. + * + * @param integer $type The content type code. + */ + public function setType($type) + { + $this->_type = $type; + } + + /** + * Returns the content description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. The description + * language and encoding must be that of the actual text. + * + * @param string $description The content description text. + * @param string $language The language code. + * @param integer $encoding The text encoding. + */ + public function setDescription + ($description, $language = null, $encoding = null) + { + $this->_description = $description; + if ($language !== null) { + $this->setLanguage($language); + } + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Returns the syllable events with their timestamps. + * + * @return Array + */ + public function getEvents() + { + return $this->_events; + } + + /** + * Sets the syllable events with their timestamps using given encoding. + * + * The text language and encoding must be that of the description text. + * + * @param Array $text The test string. + * @param string $language The language code. + * @param integer $encoding The text encoding. + */ + public function setEvents($events, $language = null, $encoding = null) + { + $this->_events = $events; + if ($language !== null) { + $this->setLanguage($language); + } + if ($encoding !== null) { + $this->setEncoding($encoding); + } + ksort($this->_events); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_language) + ->writeUInt8($this->_format) + ->writeUInt8($this->_type); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1); + break; + default: + $writer->writeString8($this->_description, 1); + break; + } + foreach ($this->_events as $timestamp => $syllable) { + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($syllable, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($syllable, null, 1); + break; + default: + $writer->writeString8($syllable, 1); + break; + } + $writer->writeUInt32BE($timestamp); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Sytc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Sytc.php index c3cc9623..7e6f2719 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Sytc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Sytc.php @@ -1,157 +1,157 @@ -Synchronised tempo codes frame might be used. - * - * The tempo data consists of one or more tempo codes. Each tempo code consists - * of one tempo part and one time part. The tempo is in BPM described with one - * or two bytes. If the first byte has the value $FF, one more byte follows, - * which is added to the first giving a range from 2 - 510 BPM, since $00 and - * $01 is reserved. $00 is used to describe a beat-free time period, which is - * not the same as a music-free time period. $01 is used to indicate one single - * beat-stroke followed by a beat-free period. - * - * The tempo descriptor is followed by a time stamp. Every time the tempo in the - * music changes, a tempo descriptor may indicate this for the player. All tempo - * descriptors must be sorted in chronological order. The first beat-stroke in - * a time-period is at the same time as the beat description occurs. There may - * only be one SYTC frame in each tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sytc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Sytc extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Timing -{ - /** Describes a beat-free time period. */ - const BEAT_FREE = 0x00; - - /** Indicate one single beat-stroke followed by a beat-free period. */ - const SINGLE_BEAT = 0x01; - - /** @var integer */ - private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; - - /** @var Array */ - private $_events = array(); - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $offset = 0; - $this->_format = $this->_reader->readUInt8(); - while ($this->_reader->available()) { - $tempo = $this->_reader->readUInt8(); - if ($tempo == 0xff) - $tempo += $this->_reader->readUInt8(); - $this->_events[$this->_reader->readUInt32BE()] = $tempo; - } - ksort($this->_events); - } - - /** - * Returns the timing format. - * - * @return integer - */ - public function getFormat() - { - return $this->_format; - } - - /** - * Sets the timing format. - * - * @see Zend_Media_Id3_Timing - * @param integer $format The timing format. - */ - public function setFormat($format) - { - $this->_format = $format; - } - - /** - * Returns the time-bpm tempo events. - * - * @return Array - */ - public function getEvents() - { - return $this->_events; - } - - /** - * Sets the time-bpm tempo events. - * - * @param Array $events The time-bpm tempo events. - */ - public function setEvents($events) - { - $this->_events = $events; - ksort($this->_events); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_format); - foreach ($this->_events as $timestamp => $tempo) { - if ($tempo >= 0xff) { - $writer->writeUInt8(0xff) - ->writeUInt8($tempo - 0xff); - } else { - $writer->writeUInt8($tempo); - } - $writer->writeUInt32BE($timestamp); - } - } -} +Synchronised tempo codes frame might be used. + * + * The tempo data consists of one or more tempo codes. Each tempo code consists + * of one tempo part and one time part. The tempo is in BPM described with one + * or two bytes. If the first byte has the value $FF, one more byte follows, + * which is added to the first giving a range from 2 - 510 BPM, since $00 and + * $01 is reserved. $00 is used to describe a beat-free time period, which is + * not the same as a music-free time period. $01 is used to indicate one single + * beat-stroke followed by a beat-free period. + * + * The tempo descriptor is followed by a time stamp. Every time the tempo in the + * music changes, a tempo descriptor may indicate this for the player. All tempo + * descriptors must be sorted in chronological order. The first beat-stroke in + * a time-period is at the same time as the beat description occurs. There may + * only be one SYTC frame in each tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sytc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Sytc extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Timing +{ + /** Describes a beat-free time period. */ + const BEAT_FREE = 0x00; + + /** Indicate one single beat-stroke followed by a beat-free period. */ + const SINGLE_BEAT = 0x01; + + /** @var integer */ + private $_format = Zend_Media_Id3_Timing::MPEG_FRAMES; + + /** @var Array */ + private $_events = array(); + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $offset = 0; + $this->_format = $this->_reader->readUInt8(); + while ($this->_reader->available()) { + $tempo = $this->_reader->readUInt8(); + if ($tempo == 0xff) + $tempo += $this->_reader->readUInt8(); + $this->_events[$this->_reader->readUInt32BE()] = $tempo; + } + ksort($this->_events); + } + + /** + * Returns the timing format. + * + * @return integer + */ + public function getFormat() + { + return $this->_format; + } + + /** + * Sets the timing format. + * + * @see Zend_Media_Id3_Timing + * @param integer $format The timing format. + */ + public function setFormat($format) + { + $this->_format = $format; + } + + /** + * Returns the time-bpm tempo events. + * + * @return Array + */ + public function getEvents() + { + return $this->_events; + } + + /** + * Sets the time-bpm tempo events. + * + * @param Array $events The time-bpm tempo events. + */ + public function setEvents($events) + { + $this->_events = $events; + ksort($this->_events); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_format); + foreach ($this->_events as $timestamp => $tempo) { + if ($tempo >= 0xff) { + $writer->writeUInt8(0xff) + ->writeUInt8($tempo - 0xff); + } else { + $writer->writeUInt8($tempo); + } + $writer->writeUInt32BE($timestamp); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Talb.php b/app/libs/vendor/Zend/Media/Id3/Frame/Talb.php index 2d4ccebf..c0646574 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Talb.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Talb.php @@ -1,40 +1,40 @@ -Album/Movie/Show title frame is intended for the title of the - * recording (or source of sound) from which the audio in the file is taken. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Talb.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Talb extends Zend_Media_Id3_TextFrame -{} +Album/Movie/Show title frame is intended for the title of the + * recording (or source of sound) from which the audio in the file is taken. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Talb.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Talb extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tbpm.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tbpm.php index 80ccecb2..229f7ab3 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tbpm.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tbpm.php @@ -1,40 +1,40 @@ -BPM frame contains the number of beats per minute in the main part - * of the audio. The BPM is an integer and represented as a numerical string. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tbpm.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tbpm extends Zend_Media_Id3_NumberFrame -{} +BPM frame contains the number of beats per minute in the main part + * of the audio. The BPM is an integer and represented as a numerical string. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tbpm.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tbpm extends Zend_Media_Id3_NumberFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tcmp.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tcmp.php index 4275ca06..5d59fcf9 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tcmp.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tcmp.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tcmp.php 204 2010-10-14 05:58:51Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tcmp extends Zend_Media_Id3_NumberFrame -{} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tcmp.php 204 2010-10-14 05:58:51Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tcmp extends Zend_Media_Id3_NumberFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tcom.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tcom.php index a3a533e3..9bf3e9a1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tcom.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tcom.php @@ -1,39 +1,39 @@ -Composer frame is intended for the name of the composer. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tcom.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tcom extends Zend_Media_Id3_TextFrame -{} +Composer frame is intended for the name of the composer. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tcom.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tcom extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tcon.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tcon.php index a982986b..391e9f59 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tcon.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tcon.php @@ -1,49 +1,49 @@ -Content type, which ID3v1 was stored as a one byte numeric value - * only, is now a string. You may use one or several of the ID3v1 types as - * numerical strings, or, since the category list would be impossible to - * maintain with accurate and up to date categories, define your own. - * - * You may also use any of the following keywords: - * - *
    - *  RX  Remix
    - *  CR  Cover
    - * 
    - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tcon.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tcon extends Zend_Media_Id3_TextFrame -{} +Content type, which ID3v1 was stored as a one byte numeric value + * only, is now a string. You may use one or several of the ID3v1 types as + * numerical strings, or, since the category list would be impossible to + * maintain with accurate and up to date categories, define your own. + * + * You may also use any of the following keywords: + * + *
    + *  RX  Remix
    + *  CR  Cover
    + * 
    + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tcon.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tcon extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tcop.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tcop.php index f3eff69c..6a97b436 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tcop.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tcop.php @@ -1,46 +1,46 @@ -Copyright message frame, in which the string must begin with a - * year and a space character (making five characters), is intended for the - * copyright holder of the original sound, not the audio file itself. The - * absence of this frame means only that the copyright information is - * unavailable or has been removed, and must not be interpreted to mean that the - * audio is public domain. Every time this field is displayed the field must be - * preceded with 'Copyright ' (C) ' ', where (C) is one character showing a C in - * a circle. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tcop.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tcop extends Zend_Media_Id3_TextFrame -{} +Copyright message frame, in which the string must begin with a + * year and a space character (making five characters), is intended for the + * copyright holder of the original sound, not the audio file itself. The + * absence of this frame means only that the copyright information is + * unavailable or has been removed, and must not be interpreted to mean that the + * audio is public domain. Every time this field is displayed the field must be + * preceded with 'Copyright ' (C) ' ', where (C) is one character showing a C in + * a circle. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tcop.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tcop extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdat.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdat.php index c264ee71..270f296a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdat.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdat.php @@ -1,42 +1,42 @@ -Date frame is a numeric string in the DDMM format containing the - * date for the recording. This field is always four characters long. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdat.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Tdat extends Zend_Media_Id3_TextFrame -{} +Date frame is a numeric string in the DDMM format containing the + * date for the recording. This field is always four characters long. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdat.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Tdat extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tden.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tden.php index f2d9a496..5978c219 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tden.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tden.php @@ -1,42 +1,42 @@ -Encoding time frame contains a timestamp describing when the audio - * was encoded. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tden.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tden extends Zend_Media_Id3_DateFrame -{} +Encoding time frame contains a timestamp describing when the audio + * was encoded. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tden.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tden extends Zend_Media_Id3_DateFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdly.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdly.php index 5dfe579f..d070ffb3 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdly.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdly.php @@ -1,41 +1,41 @@ -Playlist delay defines the numbers of milliseconds of silence that - * should be inserted before this audio. The value zero indicates that this is a - * part of a multifile audio track that should be played continuously. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdly.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tdly extends Zend_Media_Id3_NumberFrame -{} +Playlist delay defines the numbers of milliseconds of silence that + * should be inserted before this audio. The value zero indicates that this is a + * part of a multifile audio track that should be played continuously. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdly.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tdly extends Zend_Media_Id3_NumberFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdor.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdor.php index 82bfdc21..563571a8 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdor.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdor.php @@ -1,42 +1,42 @@ -Original release time frame contains a timestamp describing when - * the original recording of the audio was released. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdor.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tdor extends Zend_Media_Id3_DateFrame -{} +Original release time frame contains a timestamp describing when + * the original recording of the audio was released. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdor.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tdor extends Zend_Media_Id3_DateFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdrc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdrc.php index cd3821a4..235bc654 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdrc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdrc.php @@ -1,43 +1,43 @@ -Recording time frame contains a timestamp describing when the - * audio was recorded. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdrc.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tdrc extends Zend_Media_Id3_DateFrame -{ -} +Recording time frame contains a timestamp describing when the + * audio was recorded. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdrc.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tdrc extends Zend_Media_Id3_DateFrame +{ +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdrl.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdrl.php index b9c9b859..bcdc19bf 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdrl.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdrl.php @@ -1,42 +1,42 @@ -Release time frame contains a timestamp describing when the audio - * was first released. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdrl.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tdrl extends Zend_Media_Id3_DateFrame -{} +Release time frame contains a timestamp describing when the audio + * was first released. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdrl.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tdrl extends Zend_Media_Id3_DateFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tdtg.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tdtg.php index 0ef8ffe4..ac40c80a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tdtg.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tdtg.php @@ -1,42 +1,42 @@ -Tagging time frame contains a timestamp describing then the audio - * was tagged. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tdtg.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tdtg extends Zend_Media_Id3_DateFrame -{} +Tagging time frame contains a timestamp describing then the audio + * was tagged. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tdtg.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tdtg extends Zend_Media_Id3_DateFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tenc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tenc.php index 54762d36..c43c9432 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tenc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tenc.php @@ -1,41 +1,41 @@ -Encoded by frame contains the name of the person or organisation - * that encoded the audio file. This field may contain a copyright message, if - * the audio file also is copyrighted by the encoder. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tenc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tenc extends Zend_Media_Id3_TextFrame -{} +Encoded by frame contains the name of the person or organisation + * that encoded the audio file. This field may contain a copyright message, if + * the audio file also is copyrighted by the encoder. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tenc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tenc extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Text.php b/app/libs/vendor/Zend/Media/Id3/Frame/Text.php index 2d24ca36..c9e2bd5f 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Text.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Text.php @@ -1,40 +1,40 @@ -Lyricist/Text writer frame is intended for the writer of the text - * or lyrics in the recording. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Text.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Text extends Zend_Media_Id3_TextFrame -{} +Lyricist/Text writer frame is intended for the writer of the text + * or lyrics in the recording. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Text.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Text extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tflt.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tflt.php index 4e270089..b70b0f46 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tflt.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tflt.php @@ -1,57 +1,57 @@ -File type frame indicates which type of audio this tag defines. - * The following types and refinements are defined: - * - *
    - * MIME   MIME type follows
    - *  MPG    MPEG Audio
    - *    /1     MPEG 1/2 layer I
    - *    /2     MPEG 1/2 layer II
    - *    /3     MPEG 1/2 layer III
    - *    /2.5   MPEG 2.5
    - *    /AAC   Advanced audio compression
    - *  VQF    Transform-domain Weighted Interleave Vector Quantisation
    - *  PCM    Pulse Code Modulated audio
    - * 
    - * - * but other types may be used, but not for these types though. This is used in - * a similar way to the predefined types in the - * {@link Zend_Media_Id3_Frame_Tmed TMED} frame. If this frame is not present - * audio type is assumed to be MPG. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tflt.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tflt extends Zend_Media_Id3_TextFrame -{} +File type frame indicates which type of audio this tag defines. + * The following types and refinements are defined: + * + *
    + * MIME   MIME type follows
    + *  MPG    MPEG Audio
    + *    /1     MPEG 1/2 layer I
    + *    /2     MPEG 1/2 layer II
    + *    /3     MPEG 1/2 layer III
    + *    /2.5   MPEG 2.5
    + *    /AAC   Advanced audio compression
    + *  VQF    Transform-domain Weighted Interleave Vector Quantisation
    + *  PCM    Pulse Code Modulated audio
    + * 
    + * + * but other types may be used, but not for these types though. This is used in + * a similar way to the predefined types in the + * {@link Zend_Media_Id3_Frame_Tmed TMED} frame. If this frame is not present + * audio type is assumed to be MPG. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tflt.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tflt extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Time.php b/app/libs/vendor/Zend/Media/Id3/Frame/Time.php index 545dfc17..69cf4c72 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Time.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Time.php @@ -1,105 +1,105 @@ -Time frame contains the time for the recording in the HHMM format. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Time.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Time extends Zend_Media_Id3_DateFrame -{ - private $_hours; - private $_minutes; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options, 'HHmm'); - $this->_hours = substr($this->getText(), 0, 2); - $this->_minutes = substr($this->getText(), 2, 2); - } - - /** - * Returns the hour. - * - * @return integer - */ - public function getHour() - { - return intval($this->_hours); - } - - /** - * Sets the hour. - * - * @param integer $hours The hours. - */ - public function setHour($hours) - { - $this->setText - (($this->_hours = str_pad(strval($hours), 2, "0", STR_PAD_LEFT)) . - ($this->_minutes ? $this->_minutes : '00'), - Zend_Media_Id3_Encoding::ISO88591); - } - - /** - * Returns the minutes. - * - * @return integer - */ - public function getMinute() - { - return intval($this->_minutes); - } - - /** - * Sets the minutes. - * - * @param integer $minutes The minutes. - */ - public function setMinute($minutes) - { - $this->setText - (($this->_hours ? $this->_hours : '00') . - ($this->_minutes = - str_pad(strval($minutes), 2, "0", STR_PAD_LEFT)), - Zend_Media_Id3_Encoding::ISO88591); - } -} +Time frame contains the time for the recording in the HHMM format. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Time.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Time extends Zend_Media_Id3_DateFrame +{ + private $_hours; + private $_minutes; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options, 'HHmm'); + $this->_hours = substr($this->getText(), 0, 2); + $this->_minutes = substr($this->getText(), 2, 2); + } + + /** + * Returns the hour. + * + * @return integer + */ + public function getHour() + { + return intval($this->_hours); + } + + /** + * Sets the hour. + * + * @param integer $hours The hours. + */ + public function setHour($hours) + { + $this->setText + (($this->_hours = str_pad(strval($hours), 2, "0", STR_PAD_LEFT)) . + ($this->_minutes ? $this->_minutes : '00'), + Zend_Media_Id3_Encoding::ISO88591); + } + + /** + * Returns the minutes. + * + * @return integer + */ + public function getMinute() + { + return intval($this->_minutes); + } + + /** + * Sets the minutes. + * + * @param integer $minutes The minutes. + */ + public function setMinute($minutes) + { + $this->setText + (($this->_hours ? $this->_hours : '00') . + ($this->_minutes = + str_pad(strval($minutes), 2, "0", STR_PAD_LEFT)), + Zend_Media_Id3_Encoding::ISO88591); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tipl.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tipl.php index 4f83b75d..e26e4ab9 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tipl.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tipl.php @@ -1,43 +1,43 @@ -Involved people list is very similar to the musician credits list, - * but maps between functions, like producer, and names. - * - * @todo Implement better support - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tipl.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tipl extends Zend_Media_Id3_TextFrame -{} +Involved people list is very similar to the musician credits list, + * but maps between functions, like producer, and names. + * + * @todo Implement better support + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tipl.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tipl extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tit1.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tit1.php index 72ee4893..c4df6d6e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tit1.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tit1.php @@ -1,41 +1,41 @@ -Content group description frame is used if the sound belongs to a - * larger category of sounds/music. For example, classical music is often sorted - * in different musical sections (e.g. 'Piano Concerto', 'Weather - Hurricane'). - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tit1.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tit1 extends Zend_Media_Id3_TextFrame -{} +Content group description frame is used if the sound belongs to a + * larger category of sounds/music. For example, classical music is often sorted + * in different musical sections (e.g. 'Piano Concerto', 'Weather - Hurricane'). + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tit1.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tit1 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tit2.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tit2.php index 204b529a..90e94c2e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tit2.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tit2.php @@ -1,40 +1,40 @@ -Title/Songname/Content description frame is the actual name of the - * piece (e.g. 'Adagio', 'Hurricane Donna'). - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tit2.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tit2 extends Zend_Media_Id3_TextFrame -{} +Title/Songname/Content description frame is the actual name of the + * piece (e.g. 'Adagio', 'Hurricane Donna'). + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tit2.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tit2 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tit3.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tit3.php index c7937952..4c623eac 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tit3.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tit3.php @@ -1,41 +1,41 @@ -Subtitle/Description refinement frame is used for information - * directly related to the contents title (e.g. 'Op. 16' or 'Performed live at - * Wembley'). - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tit3.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tit3 extends Zend_Media_Id3_TextFrame -{} +Subtitle/Description refinement frame is used for information + * directly related to the contents title (e.g. 'Op. 16' or 'Performed live at + * Wembley'). + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tit3.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tit3 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tkey.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tkey.php index 392616b0..64cf5af9 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tkey.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tkey.php @@ -1,43 +1,43 @@ -Initial key frame contains the musical key in which the sound - * starts. It is represented as a string with a maximum length of three - * characters. The ground keys are represented with 'A', 'B', 'C', 'D', 'E', 'F' - * and 'G' and halfkeys represented with 'b' and '#'. Minor is represented as - * 'm', e.g. 'Dbm'. Off key is represented with an 'o' only. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tkey.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tkey extends Zend_Media_Id3_TextFrame -{} +Initial key frame contains the musical key in which the sound + * starts. It is represented as a string with a maximum length of three + * characters. The ground keys are represented with 'A', 'B', 'C', 'D', 'E', 'F' + * and 'G' and halfkeys represented with 'b' and '#'. Minor is represented as + * 'm', e.g. 'Dbm'. Off key is represented with an 'o' only. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tkey.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tkey extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tlan.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tlan.php index 2b2d22df..dee8e380 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tlan.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tlan.php @@ -1,43 +1,43 @@ -Language frame should contain the languages of the text or lyrics - * spoken or sung in the audio. The language is represented with three - * characters according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO-639-2}. If more than one language is used in the text their language - * codes should follow according to the amount of their usage. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tlan.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tlan extends Zend_Media_Id3_TextFrame -{} +Language frame should contain the languages of the text or lyrics + * spoken or sung in the audio. The language is represented with three + * characters according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO-639-2}. If more than one language is used in the text their language + * codes should follow according to the amount of their usage. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tlan.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tlan extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tlen.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tlen.php index 8d2e81ab..c4784609 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tlen.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tlen.php @@ -1,40 +1,40 @@ -Length frame contains the length of the audio file in - * milliseconds. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tlen.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tlen extends Zend_Media_Id3_NumberFrame -{} +Length frame contains the length of the audio file in + * milliseconds. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tlen.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tlen extends Zend_Media_Id3_NumberFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tmcl.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tmcl.php index c79487d0..75d2600a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tmcl.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tmcl.php @@ -1,44 +1,44 @@ -Musician credits list is intended as a mapping between instruments - * and the musician that played it. Every odd field is an instrument and every - * even is an artist or a comma delimited list of artists. - * - * @todo Implement better support - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tmcl.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tmcl extends Zend_Media_Id3_TextFrame -{} +Musician credits list is intended as a mapping between instruments + * and the musician that played it. Every odd field is an instrument and every + * even is an artist or a comma delimited list of artists. + * + * @todo Implement better support + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tmcl.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tmcl extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tmed.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tmed.php index 2f5adc5d..6d868127 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tmed.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tmed.php @@ -1,124 +1,124 @@ -Media type frame describes from which media the sound originated. - * This may be a text string or a reference to the predefined media types found - * in the list below. Example: 'VID/PAL/VHS'. - * - *
    - *  DIG    Other digital media
    - *    /A    Analogue transfer from media
    - *
    - *  ANA    Other analogue media
    - *    /WAC  Wax cylinder
    - *    /8CA  8-track tape cassette
    - *
    - *  CD     CD
    - *    /A    Analogue transfer from media
    - *    /DD   DDD
    - *    /AD   ADD
    - *    /AA   AAD
    - *
    - *  LD     Laserdisc
    - *
    - *  TT     Turntable records
    - *    /33    33.33 rpm
    - *    /45    45 rpm
    - *    /71    71.29 rpm
    - *    /76    76.59 rpm
    - *    /78    78.26 rpm
    - *    /80    80 rpm
    - *
    - *  MD     MiniDisc
    - *    /A    Analogue transfer from media
    - *
    - *  DAT    DAT
    - *    /A    Analogue transfer from media
    - *    /1    standard, 48 kHz/16 bits, linear
    - *    /2    mode 2, 32 kHz/16 bits, linear
    - *    /3    mode 3, 32 kHz/12 bits, non-linear, low speed
    - *    /4    mode 4, 32 kHz/12 bits, 4 channels
    - *    /5    mode 5, 44.1 kHz/16 bits, linear
    - *    /6    mode 6, 44.1 kHz/16 bits, 'wide track' play
    - *
    - *  DCC    DCC
    - *    /A    Analogue transfer from media
    - *
    - *  DVD    DVD
    - *    /A    Analogue transfer from media
    - *
    - *  TV     Television
    - *    /PAL    PAL
    - *    /NTSC   NTSC
    - *    /SECAM  SECAM
    - *
    - *  VID    Video
    - *    /PAL    PAL
    - *    /NTSC   NTSC
    - *    /SECAM  SECAM
    - *    /VHS    VHS
    - *    /SVHS   S-VHS
    - *    /BETA   BETAMAX
    - *
    - *  RAD    Radio
    - *    /FM   FM
    - *    /AM   AM
    - *    /LW   LW
    - *    /MW   MW
    - *
    - *  TEL    Telephone
    - *    /I    ISDN
    - *
    - *  MC     MC (normal cassette)
    - *    /4    4.75 cm/s (normal speed for a two sided cassette)
    - *    /9    9.5 cm/s
    - *    /I    Type I cassette (ferric/normal)
    - *    /II   Type II cassette (chrome)
    - *    /III  Type III cassette (ferric chrome)
    - *    /IV   Type IV cassette (metal)
    - *
    - *  REE    Reel
    - *    /9    9.5 cm/s
    - *    /19   19 cm/s
    - *    /38   38 cm/s
    - *    /76   76 cm/s
    - *    /I    Type I cassette (ferric/normal)
    - *    /II   Type II cassette (chrome)
    - *    /III  Type III cassette (ferric chrome)
    - *    /IV   Type IV cassette (metal)
    - * 
    - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tmed.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tmed extends Zend_Media_Id3_TextFrame -{} +Media type frame describes from which media the sound originated. + * This may be a text string or a reference to the predefined media types found + * in the list below. Example: 'VID/PAL/VHS'. + * + *
    + *  DIG    Other digital media
    + *    /A    Analogue transfer from media
    + *
    + *  ANA    Other analogue media
    + *    /WAC  Wax cylinder
    + *    /8CA  8-track tape cassette
    + *
    + *  CD     CD
    + *    /A    Analogue transfer from media
    + *    /DD   DDD
    + *    /AD   ADD
    + *    /AA   AAD
    + *
    + *  LD     Laserdisc
    + *
    + *  TT     Turntable records
    + *    /33    33.33 rpm
    + *    /45    45 rpm
    + *    /71    71.29 rpm
    + *    /76    76.59 rpm
    + *    /78    78.26 rpm
    + *    /80    80 rpm
    + *
    + *  MD     MiniDisc
    + *    /A    Analogue transfer from media
    + *
    + *  DAT    DAT
    + *    /A    Analogue transfer from media
    + *    /1    standard, 48 kHz/16 bits, linear
    + *    /2    mode 2, 32 kHz/16 bits, linear
    + *    /3    mode 3, 32 kHz/12 bits, non-linear, low speed
    + *    /4    mode 4, 32 kHz/12 bits, 4 channels
    + *    /5    mode 5, 44.1 kHz/16 bits, linear
    + *    /6    mode 6, 44.1 kHz/16 bits, 'wide track' play
    + *
    + *  DCC    DCC
    + *    /A    Analogue transfer from media
    + *
    + *  DVD    DVD
    + *    /A    Analogue transfer from media
    + *
    + *  TV     Television
    + *    /PAL    PAL
    + *    /NTSC   NTSC
    + *    /SECAM  SECAM
    + *
    + *  VID    Video
    + *    /PAL    PAL
    + *    /NTSC   NTSC
    + *    /SECAM  SECAM
    + *    /VHS    VHS
    + *    /SVHS   S-VHS
    + *    /BETA   BETAMAX
    + *
    + *  RAD    Radio
    + *    /FM   FM
    + *    /AM   AM
    + *    /LW   LW
    + *    /MW   MW
    + *
    + *  TEL    Telephone
    + *    /I    ISDN
    + *
    + *  MC     MC (normal cassette)
    + *    /4    4.75 cm/s (normal speed for a two sided cassette)
    + *    /9    9.5 cm/s
    + *    /I    Type I cassette (ferric/normal)
    + *    /II   Type II cassette (chrome)
    + *    /III  Type III cassette (ferric chrome)
    + *    /IV   Type IV cassette (metal)
    + *
    + *  REE    Reel
    + *    /9    9.5 cm/s
    + *    /19   19 cm/s
    + *    /38   38 cm/s
    + *    /76   76 cm/s
    + *    /I    Type I cassette (ferric/normal)
    + *    /II   Type II cassette (chrome)
    + *    /III  Type III cassette (ferric chrome)
    + *    /IV   Type IV cassette (metal)
    + * 
    + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tmed.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tmed extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tmoo.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tmoo.php index dae1c079..5b54ae87 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tmoo.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tmoo.php @@ -1,42 +1,42 @@ -Mood frame is intended to reflect the mood of the audio with a few - * keywords, e.g. 'Romantic' or 'Sad'. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tmoo.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tmoo extends Zend_Media_Id3_TextFrame -{} +Mood frame is intended to reflect the mood of the audio with a few + * keywords, e.g. 'Romantic' or 'Sad'. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tmoo.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tmoo extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Toal.php b/app/libs/vendor/Zend/Media/Id3/Frame/Toal.php index 85fc6897..6280b793 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Toal.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Toal.php @@ -1,41 +1,41 @@ -Original album/movie/show title frame is intended for the title of - * the original recording (or source of sound), if for example the music in the - * file should be a cover of a previously released song. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Toal.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Toal extends Zend_Media_Id3_TextFrame -{} +Original album/movie/show title frame is intended for the title of + * the original recording (or source of sound), if for example the music in the + * file should be a cover of a previously released song. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Toal.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Toal extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tofn.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tofn.php index e5acd6ab..e6badda1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tofn.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tofn.php @@ -1,41 +1,41 @@ -Original filename frame contains the preferred filename for the - * file, since some media doesn't allow the desired length of the filename. The - * filename is case sensitive and includes its suffix. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tofn.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tofn extends Zend_Media_Id3_TextFrame -{} +Original filename frame contains the preferred filename for the + * file, since some media doesn't allow the desired length of the filename. The + * filename is case sensitive and includes its suffix. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tofn.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tofn extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Toly.php b/app/libs/vendor/Zend/Media/Id3/Frame/Toly.php index 13ba2fd1..d6b8776c 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Toly.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Toly.php @@ -1,41 +1,41 @@ -Original lyricist/text writer frame is intended for the text - * writer of the original recording, if for example the music in the file should - * be a cover of a previously released song. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Toly.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Toly extends Zend_Media_Id3_TextFrame -{} +Original lyricist/text writer frame is intended for the text + * writer of the original recording, if for example the music in the file should + * be a cover of a previously released song. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Toly.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Toly extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tope.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tope.php index 89e0a42b..478fdd31 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tope.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tope.php @@ -1,41 +1,41 @@ -Original artist/performer frame is intended for the performer of - * the original recording, if for example the music in the file should be a - * cover of a previously released song. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tope.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tope extends Zend_Media_Id3_TextFrame -{} +Original artist/performer frame is intended for the performer of + * the original recording, if for example the music in the file should be a + * cover of a previously released song. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tope.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tope extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tory.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tory.php index 782c0300..7fb50fba 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tory.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tory.php @@ -1,76 +1,76 @@ -Original release year frame is intended for the year when the - * original recording, if for example the music in the file should be a cover of - * a previously released song, was released. The field is formatted as in the - * {@link Zend_Media_Id3_Frame_Tyer TYER} frame. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tory.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Tory extends Zend_Media_Id3_DateFrame -{ - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options, 'Y'); - } - - /** - * Returns the year. - * - * @return integer - */ - public function getYear() - { - return intval($this->getText()); - } - - /** - * Sets the year. - * - * @param integer $year The year given in four digits. - */ - public function setYear($year) - { - $this->setText(strval($year)); - } -} +Original release year frame is intended for the year when the + * original recording, if for example the music in the file should be a cover of + * a previously released song, was released. The field is formatted as in the + * {@link Zend_Media_Id3_Frame_Tyer TYER} frame. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tory.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Tory extends Zend_Media_Id3_DateFrame +{ + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options, 'Y'); + } + + /** + * Returns the year. + * + * @return integer + */ + public function getYear() + { + return intval($this->getText()); + } + + /** + * Sets the year. + * + * @param integer $year The year given in four digits. + */ + public function setYear($year) + { + $this->setText(strval($year)); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Town.php b/app/libs/vendor/Zend/Media/Id3/Frame/Town.php index 919e65b8..4dc18a27 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Town.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Town.php @@ -1,40 +1,40 @@ -File owner/licensee frame contains the name of the owner or - * licensee of the file and it's contents. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Town.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Town extends Zend_Media_Id3_TextFrame -{} +File owner/licensee frame contains the name of the owner or + * licensee of the file and it's contents. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Town.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Town extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe1.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe1.php index 409c95e9..10504ab1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe1.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe1.php @@ -1,40 +1,40 @@ -Lead artist/Lead performer/Soloist/Performing group is used for - * the main artist. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpe1.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpe1 extends Zend_Media_Id3_TextFrame -{} +Lead artist/Lead performer/Soloist/Performing group is used for + * the main artist. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpe1.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpe1 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe2.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe2.php index d903b6af..4ac9cef9 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe2.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe2.php @@ -1,40 +1,40 @@ -Band/Orchestra/Accompaniment frame is used for additional - * information about the performers in the recording. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpe2.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpe2 extends Zend_Media_Id3_TextFrame -{} +Band/Orchestra/Accompaniment frame is used for additional + * information about the performers in the recording. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpe2.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpe2 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe3.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe3.php index bd1a1e82..34ca96ae 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe3.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe3.php @@ -1,39 +1,39 @@ -Conductor frame is used for the name of the conductor. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpe3.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpe3 extends Zend_Media_Id3_TextFrame -{} +Conductor frame is used for the name of the conductor. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpe3.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpe3 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe4.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe4.php index 5026a9fb..591ea38a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpe4.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpe4.php @@ -1,41 +1,41 @@ -Interpreted, remixed, or otherwise modified by frame contains more - * information about the people behind a remix and similar interpretations of - * another existing piece. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpe4.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpe4 extends Zend_Media_Id3_TextFrame -{} +Interpreted, remixed, or otherwise modified by frame contains more + * information about the people behind a remix and similar interpretations of + * another existing piece. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpe4.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpe4 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpos.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpos.php index 3a4a0d0e..815253ce 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpos.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpos.php @@ -1,110 +1,110 @@ -Number of a set frame is a numeric string that describes which part - * of a set the audio came from. This frame is used if the source described in - * the {@link Zend_Media_Id3_Frame_Talb TALB} frame is divided into several - * mediums, e.g. a double CD. The value may be extended with a '/' character and - * a numeric string containing the total number of parts in the set. E.g. '1/2'. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpos.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpos extends Zend_Media_Id3_TextFrame -{ - private $_number; - private $_total; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - @list ($this->_number, $this->_total) = explode("/", $this->getText()); - } - - /** - * Returns the number. - * - * @return integer - */ - public function getNumber() - { - return intval($this->_number); - } - - /** - * Sets the number. - * - * @param integer $number The number. - */ - public function setNumber($part) - { - $this->setText - ($this->_number = strval($part) . - ($this->_total ? '/' . $this->_total : ''), - Zend_Media_Id3_Encoding::ISO88591); - } - - /** - * Returns the total number. - * - * @return integer - */ - public function getTotal() - { - return intval($this->_total); - } - - /** - * Sets the total number. - * - * @param integer $total The total number. - */ - public function setTotal($total) - { - $this->setText - (($this->_number ? $this->_number : '?') . "/" . - ($this->_total = strval($total)), - Zend_Media_Id3_Encoding::ISO88591); - } -} +Number of a set frame is a numeric string that describes which part + * of a set the audio came from. This frame is used if the source described in + * the {@link Zend_Media_Id3_Frame_Talb TALB} frame is divided into several + * mediums, e.g. a double CD. The value may be extended with a '/' character and + * a numeric string containing the total number of parts in the set. E.g. '1/2'. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpos.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpos extends Zend_Media_Id3_TextFrame +{ + private $_number; + private $_total; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + @list ($this->_number, $this->_total) = explode("/", $this->getText()); + } + + /** + * Returns the number. + * + * @return integer + */ + public function getNumber() + { + return intval($this->_number); + } + + /** + * Sets the number. + * + * @param integer $number The number. + */ + public function setNumber($part) + { + $this->setText + ($this->_number = strval($part) . + ($this->_total ? '/' . $this->_total : ''), + Zend_Media_Id3_Encoding::ISO88591); + } + + /** + * Returns the total number. + * + * @return integer + */ + public function getTotal() + { + return intval($this->_total); + } + + /** + * Sets the total number. + * + * @param integer $total The total number. + */ + public function setTotal($total) + { + $this->setText + (($this->_number ? $this->_number : '?') . "/" . + ($this->_total = strval($total)), + Zend_Media_Id3_Encoding::ISO88591); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpro.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpro.php index 9b3d3345..7882cbf1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpro.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpro.php @@ -1,48 +1,48 @@ -Produced notice frame, in which the string must begin with a year - * and a space character (making five characters), is intended for the - * production copyright holder of the original sound, not the audio file itself. - * The absence of this frame means only that the production copyright - * information is unavailable or has been removed, and must not be interpreted - * to mean that the audio is public domain. Every time this field is displayed - * the field must be preceded with 'Produced ' (P) ' ', where (P) is one - * character showing a P in a circle. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpro.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tpro extends Zend_Media_Id3_TextFrame -{} +Produced notice frame, in which the string must begin with a year + * and a space character (making five characters), is intended for the + * production copyright holder of the original sound, not the audio file itself. + * The absence of this frame means only that the production copyright + * information is unavailable or has been removed, and must not be interpreted + * to mean that the audio is public domain. Every time this field is displayed + * the field must be preceded with 'Produced ' (P) ' ', where (P) is one + * character showing a P in a circle. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpro.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tpro extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tpub.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tpub.php index 3a798510..aea47edb 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tpub.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tpub.php @@ -1,40 +1,40 @@ -Publisher frame simply contains the name of the label or - * publisher. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tpub.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tpub extends Zend_Media_Id3_TextFrame -{} +Publisher frame simply contains the name of the label or + * publisher. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tpub.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tpub extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Trck.php b/app/libs/vendor/Zend/Media/Id3/Frame/Trck.php index 65f9c1b4..d87c99a3 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Trck.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Trck.php @@ -1,109 +1,109 @@ -Track number/Position in set frame is a numeric string containing - * the order number of the audio-file on its original recording. This may be - * extended with a '/' character and a numeric string containing the total - * number of tracks/elements on the original recording. E.g. '4/9'. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trck.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Trck extends Zend_Media_Id3_TextFrame -{ - private $_number; - private $_total; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - @list ($this->_number, $this->_total) = explode("/", $this->getText()); - } - - /** - * Returns the number. - * - * @return integer - */ - public function getNumber() - { - return intval($this->_number); - } - - /** - * Sets the number. - * - * @param integer $number The number. - */ - public function setNumber($part) - { - $this->setText - ($this->_number = strval($part) . - ($this->_total ? '/' . $this->_total : ''), - Zend_Media_Id3_Encoding::ISO88591); - } - - /** - * Returns the total number. - * - * @return integer - */ - public function getTotal() - { - return intval($this->_total); - } - - /** - * Sets the total number. - * - * @param integer $total The total number. - */ - public function setTotal($total) - { - $this->setText - (($this->_number ? $this->_number : '?') . "/" . - ($this->_total = strval($total)), - Zend_Media_Id3_Encoding::ISO88591); - } -} +Track number/Position in set frame is a numeric string containing + * the order number of the audio-file on its original recording. This may be + * extended with a '/' character and a numeric string containing the total + * number of tracks/elements on the original recording. E.g. '4/9'. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trck.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Trck extends Zend_Media_Id3_TextFrame +{ + private $_number; + private $_total; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + @list ($this->_number, $this->_total) = explode("/", $this->getText()); + } + + /** + * Returns the number. + * + * @return integer + */ + public function getNumber() + { + return intval($this->_number); + } + + /** + * Sets the number. + * + * @param integer $number The number. + */ + public function setNumber($part) + { + $this->setText + ($this->_number = strval($part) . + ($this->_total ? '/' . $this->_total : ''), + Zend_Media_Id3_Encoding::ISO88591); + } + + /** + * Returns the total number. + * + * @return integer + */ + public function getTotal() + { + return intval($this->_total); + } + + /** + * Sets the total number. + * + * @param integer $total The total number. + */ + public function setTotal($total) + { + $this->setText + (($this->_number ? $this->_number : '?') . "/" . + ($this->_total = strval($total)), + Zend_Media_Id3_Encoding::ISO88591); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Trda.php b/app/libs/vendor/Zend/Media/Id3/Frame/Trda.php index 5e335f80..d75ddb1f 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Trda.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Trda.php @@ -1,45 +1,45 @@ -Recording dates frame is intended to be used as complement to - * the {@link Zend_Media_Id3_Frame_Tyer TYER}, - * {@link Zend_Media_Id3_Frame_Tdat TDAT} and - * {@link Zend_Media_Id3_Frame_Time TIME} frames. E.g. '4th-7th June, 12th June' - * in combination with the {@link Zend_Media_Id3_Frame_Tyer TYER} frame. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trda.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Trda extends Zend_Media_Id3_TextFrame -{} +Recording dates frame is intended to be used as complement to + * the {@link Zend_Media_Id3_Frame_Tyer TYER}, + * {@link Zend_Media_Id3_Frame_Tdat TDAT} and + * {@link Zend_Media_Id3_Frame_Time TIME} frames. E.g. '4th-7th June, 12th June' + * in combination with the {@link Zend_Media_Id3_Frame_Tyer TYER} frame. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trda.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Trda extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Trsn.php b/app/libs/vendor/Zend/Media/Id3/Frame/Trsn.php index f563223a..96f90aa9 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Trsn.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Trsn.php @@ -1,40 +1,40 @@ -Internet radio station name frame contains the name of the - * internet radio station from which the audio is streamed. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trsn.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Trsn extends Zend_Media_Id3_TextFrame -{} +Internet radio station name frame contains the name of the + * internet radio station from which the audio is streamed. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trsn.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Trsn extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Trso.php b/app/libs/vendor/Zend/Media/Id3/Frame/Trso.php index 46b03b7f..2a0f131c 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Trso.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Trso.php @@ -1,40 +1,40 @@ -Internet radio station owner frame contains the name of the owner - * of the internet radio station from which the audio is streamed. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trso.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Trso extends Zend_Media_Id3_TextFrame -{} +Internet radio station owner frame contains the name of the owner + * of the internet radio station from which the audio is streamed. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trso.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Trso extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsiz.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsiz.php index b3706a55..2d5d59a6 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsiz.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsiz.php @@ -1,42 +1,42 @@ -Size frame contains the size of the audiofile in bytes, excluding - * the ID3v2 tag. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsiz.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Tsiz extends Zend_Media_Id3_NumberFrame -{} +Size frame contains the size of the audiofile in bytes, excluding + * the ID3v2 tag. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsiz.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Tsiz extends Zend_Media_Id3_NumberFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tso2.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tso2.php index 33760689..013e484e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tso2.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tso2.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tso2.php 204 2010-10-14 05:58:51Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tso2 extends Zend_Media_Id3_TextFrame -{} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tso2.php 204 2010-10-14 05:58:51Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tso2 extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsoa.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsoa.php index a8fc9250..f5f0cf77 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsoa.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsoa.php @@ -1,43 +1,43 @@ -Album sort order frame defines a string which should be used - * instead of the {@link Zend_Media_Id3_Frame_Talb TALB} album name frame for - * sorting purposes. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsoa.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tsoa extends Zend_Media_Id3_TextFrame -{} +Album sort order frame defines a string which should be used + * instead of the {@link Zend_Media_Id3_Frame_Talb TALB} album name frame for + * sorting purposes. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsoa.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tsoa extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsoc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsoc.php index ff57fa07..1ec1dc60 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsoc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsoc.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsoc.php 204 2010-10-14 05:58:51Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tsoc extends Zend_Media_Id3_TextFrame -{} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsoc.php 204 2010-10-14 05:58:51Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tsoc extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsop.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsop.php index f045b179..a47b9d98 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsop.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsop.php @@ -1,43 +1,43 @@ -Performer sort order frame defines a string which should be used - * instead of the {@link Zend_Media_Id3_Frame_Tpe2 TPE2} performer frame for - * sorting purposes. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsop.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tsop extends Zend_Media_Id3_TextFrame -{} +Performer sort order frame defines a string which should be used + * instead of the {@link Zend_Media_Id3_Frame_Tpe2 TPE2} performer frame for + * sorting purposes. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsop.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tsop extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsot.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsot.php index 04db9516..7f8b00f4 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsot.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsot.php @@ -1,43 +1,43 @@ -Title sort order frame defines a string which should be used - * instead of the {@link Zend_Media_Id3_Frame_Tit2 TIT2} title frame for sorting - * purposes. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsot.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tsot extends Zend_Media_Id3_TextFrame -{} +Title sort order frame defines a string which should be used + * instead of the {@link Zend_Media_Id3_Frame_Tit2 TIT2} title frame for sorting + * purposes. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsot.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tsot extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsrc.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsrc.php index 2d59f798..47cf07db 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsrc.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsrc.php @@ -1,202 +1,202 @@ -TSRC frame should contain the International Standard Recording - * Code or ISRC (12 characters). - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsrc.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tsrc extends Zend_Media_Id3_TextFrame -{ - /** @var string */ - private $_country; - - /** @var string */ - private $_registrant; - - /** @var string */ - private $_year; - - /** @var string */ - private $_uniqueNumber; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - $this->_country = substr($this->getText(), 0, 2); - $this->_registrant = substr($this->getText(), 2, 3); - $this->_year = substr($this->getText(), 5, 2); - $this->_uniqueNumber = substr($this->getText(), 7, 5); - } - - /** - * Returns the appropriate for the registrant the two-character ISO 3166-1 - * alpha-2 country code. - * - * @return string - */ - public function getCountry() - { - return $this->_country; - } - - /** - * Sets the country. - * - * @param string $country The two-character ISO 3166-1 alpha-2 country code. - */ - public function setCountry($country) - { - $this->_country = $country; - } - - /** - * Returns the three character alphanumeric registrant code, uniquely - * identifying the organisation which registered the ISRC code. - * - * @return string - */ - public function getRegistrant() - { - return $this->_registrant; - } - - /** - * Sets the registrant. - * - * @param string $registrant The three character alphanumeric registrant - * code. - */ - public function setRegistrant($registrant) - { - $this->_registrant = $registrant; - } - - /** - * Returns the year of registration. - * - * @return integer - */ - public function getYear() - { - $year = intval($this->_year); - if ($year > 50) { - return 1900 + $year; - } else { - return 2000 + $year; - } - } - - /** - * Sets the year. - * - * @param integer $year The year of registration. - */ - public function setYear($year) - { - $this->_year = substr(strval($year), 2, 2); - } - - /** - * Returns the unique number identifying the particular sound recording. - * - * @return integer - */ - public function getUniqueNumber() - { - return intval($this->_uniqueNumber); - } - - /** - * Sets the unique number. - * - * @param integer $uniqueNumber The unique number identifying the - * particular sound recording. - */ - public function setUniqueNumber($uniqueNumber) - { - $this->_uniqueNumber = - str_pad(strval($uniqueNumber), 5, "0", STR_PAD_LEFT); - } - - /** - * Returns the whole ISRC code in the form - * "country-registrant-year-unique number". - * - * @return string - */ - public function getIsrc() - { - return $this->_country . "-" . $this->_registrant . "-" . - $this->_year . "-" . $this->_uniqueNumber; - } - - /** - * Sets the ISRC code in the form "country-registrant-year-unique number". - * - * @param string $isrc The ISRC code. - */ - public function setIsrc($isrc) - { - list($this->_country, - $this->_registrant, - $this->_year, - $this->_uniqueNumber) = preg_split('/-/', $isrc); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $this->setText - ($this->_country . $this->_registrant . $this->_year . - $this->_uniqueNumber, Zend_Media_Id3_Encoding::ISO88591); - parent::_writeData($writer); - } -} +TSRC frame should contain the International Standard Recording + * Code or ISRC (12 characters). + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsrc.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tsrc extends Zend_Media_Id3_TextFrame +{ + /** @var string */ + private $_country; + + /** @var string */ + private $_registrant; + + /** @var string */ + private $_year; + + /** @var string */ + private $_uniqueNumber; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + $this->_country = substr($this->getText(), 0, 2); + $this->_registrant = substr($this->getText(), 2, 3); + $this->_year = substr($this->getText(), 5, 2); + $this->_uniqueNumber = substr($this->getText(), 7, 5); + } + + /** + * Returns the appropriate for the registrant the two-character ISO 3166-1 + * alpha-2 country code. + * + * @return string + */ + public function getCountry() + { + return $this->_country; + } + + /** + * Sets the country. + * + * @param string $country The two-character ISO 3166-1 alpha-2 country code. + */ + public function setCountry($country) + { + $this->_country = $country; + } + + /** + * Returns the three character alphanumeric registrant code, uniquely + * identifying the organisation which registered the ISRC code. + * + * @return string + */ + public function getRegistrant() + { + return $this->_registrant; + } + + /** + * Sets the registrant. + * + * @param string $registrant The three character alphanumeric registrant + * code. + */ + public function setRegistrant($registrant) + { + $this->_registrant = $registrant; + } + + /** + * Returns the year of registration. + * + * @return integer + */ + public function getYear() + { + $year = intval($this->_year); + if ($year > 50) { + return 1900 + $year; + } else { + return 2000 + $year; + } + } + + /** + * Sets the year. + * + * @param integer $year The year of registration. + */ + public function setYear($year) + { + $this->_year = substr(strval($year), 2, 2); + } + + /** + * Returns the unique number identifying the particular sound recording. + * + * @return integer + */ + public function getUniqueNumber() + { + return intval($this->_uniqueNumber); + } + + /** + * Sets the unique number. + * + * @param integer $uniqueNumber The unique number identifying the + * particular sound recording. + */ + public function setUniqueNumber($uniqueNumber) + { + $this->_uniqueNumber = + str_pad(strval($uniqueNumber), 5, "0", STR_PAD_LEFT); + } + + /** + * Returns the whole ISRC code in the form + * "country-registrant-year-unique number". + * + * @return string + */ + public function getIsrc() + { + return $this->_country . "-" . $this->_registrant . "-" . + $this->_year . "-" . $this->_uniqueNumber; + } + + /** + * Sets the ISRC code in the form "country-registrant-year-unique number". + * + * @param string $isrc The ISRC code. + */ + public function setIsrc($isrc) + { + list($this->_country, + $this->_registrant, + $this->_year, + $this->_uniqueNumber) = preg_split('/-/', $isrc); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $this->setText + ($this->_country . $this->_registrant . $this->_year . + $this->_uniqueNumber, Zend_Media_Id3_Encoding::ISO88591); + parent::_writeData($writer); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsse.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsse.php index de4cd62c..dce4931d 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsse.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsse.php @@ -1,41 +1,41 @@ -Software/Hardware and settings used for encoding frame includes - * the used audio encoder and its settings when the file was encoded. Hardware - * refers to hardware encoders, not the computer on which a program was run. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsse.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Tsse extends Zend_Media_Id3_TextFrame -{} +Software/Hardware and settings used for encoding frame includes + * the used audio encoder and its settings when the file was encoded. Hardware + * refers to hardware encoders, not the computer on which a program was run. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsse.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Tsse extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tsst.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tsst.php index 946350f8..e6cfb35a 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tsst.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tsst.php @@ -1,42 +1,42 @@ -Set subtitle frame is intended for the subtitle of the part of a - * set this track belongs to. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tsst.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since ID3v2.4.0 - */ -final class Zend_Media_Id3_Frame_Tsst extends Zend_Media_Id3_TextFrame -{} +Set subtitle frame is intended for the subtitle of the part of a + * set this track belongs to. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tsst.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since ID3v2.4.0 + */ +final class Zend_Media_Id3_Frame_Tsst extends Zend_Media_Id3_TextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Txxx.php b/app/libs/vendor/Zend/Media/Id3/Frame/Txxx.php index 78b1819c..a2150261 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Txxx.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Txxx.php @@ -1,144 +1,144 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Txxx.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Txxx extends Zend_Media_Id3_TextFrame -{ - /** @var string */ - private $_description; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - Zend_Media_Id3_Frame::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($this->_description, $this->_text) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_description = - $this->_convertString($this->_description, $encoding); - $this->_text = - $this->_convertString(array($this->_text), $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - list($this->_description, $this->_text) = $this->_convertString - ($this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2), - $encoding); - $this->_text = array($this->_text); - break; - } - } - - /** - * Returns the description text. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the description text using given encoding. - * - * @param string $description The content description text. - * @param integer $encoding The text encoding. - */ - public function setDescription($description, $encoding = null) - { - $this->_description = $description; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, null, 1) - ->writeString16 - ($this->_text[0], - Zend_Io_Writer::LITTLE_ENDIAN_ORDER); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1) - ->writeString16($this->_text[0], null); - break; - default: - $writer->writeString8($this->_description, 1) - ->writeString8($this->_text[0]); - break; - } - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Txxx.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Txxx extends Zend_Media_Id3_TextFrame +{ + /** @var string */ + private $_description; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + Zend_Media_Id3_Frame::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($this->_description, $this->_text) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_description = + $this->_convertString($this->_description, $encoding); + $this->_text = + $this->_convertString(array($this->_text), $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + list($this->_description, $this->_text) = $this->_convertString + ($this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2), + $encoding); + $this->_text = array($this->_text); + break; + } + } + + /** + * Returns the description text. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the description text using given encoding. + * + * @param string $description The content description text. + * @param integer $encoding The text encoding. + */ + public function setDescription($description, $encoding = null) + { + $this->_description = $description; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, null, 1) + ->writeString16 + ($this->_text[0], + Zend_Io_Writer::LITTLE_ENDIAN_ORDER); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1) + ->writeString16($this->_text[0], null); + break; + default: + $writer->writeString8($this->_description, 1) + ->writeString8($this->_text[0]); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Tyer.php b/app/libs/vendor/Zend/Media/Id3/Frame/Tyer.php index 89175d1c..6af97492 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Tyer.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Tyer.php @@ -1,73 +1,73 @@ -Year frame is a numeric string with a year of the recording. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tyer.php 177 2010-03-09 13:13:34Z svollbehr $ - * @deprecated ID3v2.3.0 - */ -final class Zend_Media_Id3_Frame_Tyer extends Zend_Media_Id3_DateFrame -{ - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options, 'Y'); - } - - /** - * Returns the year. - * - * @return integer - */ - public function getYear() - { - return intval($this->getText()); - } - - /** - * Sets the year. - * - * @param integer $year The year given in four digits. - */ - public function setYear($year) - { - $this->setText(strval($year)); - } -} +Year frame is a numeric string with a year of the recording. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tyer.php 177 2010-03-09 13:13:34Z svollbehr $ + * @deprecated ID3v2.3.0 + */ +final class Zend_Media_Id3_Frame_Tyer extends Zend_Media_Id3_DateFrame +{ + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options, 'Y'); + } + + /** + * Returns the year. + * + * @return integer + */ + public function getYear() + { + return intval($this->getText()); + } + + /** + * Sets the year. + * + * @param integer $year The year given in four digits. + */ + public function setYear($year) + { + $this->setText(strval($year)); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Ufid.php b/app/libs/vendor/Zend/Media/Id3/Frame/Ufid.php index a2608658..35551ef1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Ufid.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Ufid.php @@ -1,131 +1,131 @@ -Unique File Identifier frame's purpose is to be able to identify - * the audio file in a database, that may provide more information relevant to - * the content. Since standardisation of such a database is beyond this document, - * all UFID frames begin with an 'owner identifier' field. It is a null- - * terminated string with a URL containing an email address, or a link to - * a location where an email address can be found, that belongs to the - * organisation responsible for this specific database implementation. - * Questions regarding the database should be sent to the indicated email - * address. The URL should not be used for the actual database queries. The - * string "http://www.id3.org/dummy/ufid.html" should be used for tests. The - * 'Owner identifier' must be non-empty (more than just a termination). The - * 'Owner identifier' is then followed by the actual identifier, which may be - * up to 64 bytes. There may be more than one "UFID" frame in a tag, but only - * one with the same 'Owner identifier'. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Arlo Kleijweg - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ufid.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Ufid extends Zend_Media_Id3_Frame -{ - /** @var string */ - private $_owner; - - /** @var string */ - private $_fileIdentifier; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader === null) { - return; - } - - list($this->_owner, $this->_fileIdentifier) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - } - - /** - * Returns the owner identifier string. - * - * @return string - */ - public function getOwner() - { - return $this->_owner; - } - - /** - * Sets the owner identifier string. - * - * @param string $owner The owner identifier string. - */ - public function setOwner($owner) - { - $this->_owner = $owner; - } - - /** - * Returns the identifier binary data associated with the frame. - * - * @return string - */ - public function getFileIdentifier() - { - return $this->_fileIdentifier; - } - - /** - * Sets the identifier binary data associated with the frame. - * - * @param string $fileIdentifier The file identifier binary data string. - */ - public function setFileIdentifier($fileIdentifier) - { - $this->_fileIdentifier = $fileIdentifier; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeString8($this->_owner, 1) - ->write($this->_fileIdentifier); - } -} +Unique File Identifier frame's purpose is to be able to identify + * the audio file in a database, that may provide more information relevant to + * the content. Since standardisation of such a database is beyond this document, + * all UFID frames begin with an 'owner identifier' field. It is a null- + * terminated string with a URL containing an email address, or a link to + * a location where an email address can be found, that belongs to the + * organisation responsible for this specific database implementation. + * Questions regarding the database should be sent to the indicated email + * address. The URL should not be used for the actual database queries. The + * string "http://www.id3.org/dummy/ufid.html" should be used for tests. The + * 'Owner identifier' must be non-empty (more than just a termination). The + * 'Owner identifier' is then followed by the actual identifier, which may be + * up to 64 bytes. There may be more than one "UFID" frame in a tag, but only + * one with the same 'Owner identifier'. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Arlo Kleijweg + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ufid.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Ufid extends Zend_Media_Id3_Frame +{ + /** @var string */ + private $_owner; + + /** @var string */ + private $_fileIdentifier; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader === null) { + return; + } + + list($this->_owner, $this->_fileIdentifier) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + } + + /** + * Returns the owner identifier string. + * + * @return string + */ + public function getOwner() + { + return $this->_owner; + } + + /** + * Sets the owner identifier string. + * + * @param string $owner The owner identifier string. + */ + public function setOwner($owner) + { + $this->_owner = $owner; + } + + /** + * Returns the identifier binary data associated with the frame. + * + * @return string + */ + public function getFileIdentifier() + { + return $this->_fileIdentifier; + } + + /** + * Sets the identifier binary data associated with the frame. + * + * @param string $fileIdentifier The file identifier binary data string. + */ + public function setFileIdentifier($fileIdentifier) + { + $this->_fileIdentifier = $fileIdentifier; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeString8($this->_owner, 1) + ->write($this->_fileIdentifier); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Unknown.php b/app/libs/vendor/Zend/Media/Id3/Frame/Unknown.php index d1fbea15..a79d0038 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Unknown.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Unknown.php @@ -1,48 +1,48 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Unknown.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Unknown extends Zend_Media_Id3_Frame -{ - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - {} -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Unknown.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Unknown extends Zend_Media_Id3_Frame +{ + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + {} +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/User.php b/app/libs/vendor/Zend/Media/Id3/Frame/User.php index 712cf428..2a9bfb99 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/User.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/User.php @@ -1,43 +1,43 @@ -Terms of use frame contains a brief description of the terms of - * use and ownership of the file. More detailed information concerning the legal - * terms might be available through the {@link Zend_Media_Id3_Frame_Wcop WCOP} - * frame. Newlines are allowed in the text. There may be more than one Terms of - * use frames in a tag, but only one with the same language. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: User.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_User extends Zend_Media_Id3_LanguageTextFrame -{} +Terms of use frame contains a brief description of the terms of + * use and ownership of the file. More detailed information concerning the legal + * terms might be available through the {@link Zend_Media_Id3_Frame_Wcop WCOP} + * frame. Newlines are allowed in the text. There may be more than one Terms of + * use frames in a tag, but only one with the same language. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: User.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_User extends Zend_Media_Id3_LanguageTextFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Uslt.php b/app/libs/vendor/Zend/Media/Id3/Frame/Uslt.php index 432bb320..f0d8a9a5 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Uslt.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Uslt.php @@ -1,154 +1,154 @@ -Unsynchronised lyrics/text transcription frame contains the lyrics - * of the song or a text transcription of other vocal activities. There may be - * more than one unsynchronised lyrics/text transcription frame in each tag, but - * only one with the same language and content descriptor. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Uslt.php 255 2012-01-21 19:46:18Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Uslt extends Zend_Media_Id3_LanguageTextFrame -{ - /** @var string */ - private $_description; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - Zend_Media_Id3_Frame::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_language = strtolower($this->_reader->read(3)); - if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { - $this->_language = 'und'; - } - - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($this->_description, $this->_text) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - $this->_description = - $this->_convertString($this->_description, $encoding); - $this->_text = - $this->_convertString($this->_text, $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - list($this->_description, $this->_text) = $this->_convertString - ($this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2), - $encoding); - break; - } - } - - /** - * Returns the short content description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. The description - * language and encoding must be that of the actual text. - * - * @param string $description The content description text. - * @param string $language The language code. - * @param integer $encoding The text encoding. - */ - public function setDescription - ($description, $language = null, $encoding = null) - { - $this->_description = $description; - if ($language !== null) { - $this->setLanguage($language); - } - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_language); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) - ->writeString16 - ($this->_text,Zend_Io_Writer::LITTLE_ENDIAN_ORDER); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1) - ->writeString16($this->_text); - break; - default: - $writer->writeString8($this->_description, 1) - ->writeString8($this->_text); - break; - } - } -} +Unsynchronised lyrics/text transcription frame contains the lyrics + * of the song or a text transcription of other vocal activities. There may be + * more than one unsynchronised lyrics/text transcription frame in each tag, but + * only one with the same language and content descriptor. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Uslt.php 255 2012-01-21 19:46:18Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Uslt extends Zend_Media_Id3_LanguageTextFrame +{ + /** @var string */ + private $_description; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + Zend_Media_Id3_Frame::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_language = strtolower($this->_reader->read(3)); + if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { + $this->_language = 'und'; + } + + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($this->_description, $this->_text) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + $this->_description = + $this->_convertString($this->_description, $encoding); + $this->_text = + $this->_convertString($this->_text, $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + list($this->_description, $this->_text) = $this->_convertString + ($this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2), + $encoding); + break; + } + } + + /** + * Returns the short content description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. The description + * language and encoding must be that of the actual text. + * + * @param string $description The content description text. + * @param string $language The language code. + * @param integer $encoding The text encoding. + */ + public function setDescription + ($description, $language = null, $encoding = null) + { + $this->_description = $description; + if ($language !== null) { + $this->setLanguage($language); + } + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_language); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1) + ->writeString16 + ($this->_text,Zend_Io_Writer::LITTLE_ENDIAN_ORDER); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1) + ->writeString16($this->_text); + break; + default: + $writer->writeString8($this->_description, 1) + ->writeString8($this->_text); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wcom.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wcom.php index 61676ad6..911e484e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wcom.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wcom.php @@ -1,41 +1,41 @@ -Commercial information frame is a URL pointing at a webpage with - * information such as where the album can be bought. There may be more than one - * WCOM frame in a tag, but not with the same content. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wcom.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wcom extends Zend_Media_Id3_LinkFrame -{} +Commercial information frame is a URL pointing at a webpage with + * information such as where the album can be bought. There may be more than one + * WCOM frame in a tag, but not with the same content. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wcom.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wcom extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wcop.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wcop.php index 05d32adb..3b195c59 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wcop.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wcop.php @@ -1,40 +1,40 @@ -Copyright/Legal information frame is a URL pointing at a webpage - * where the terms of use and ownership of the file is described. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wcop.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wcop extends Zend_Media_Id3_LinkFrame -{} +Copyright/Legal information frame is a URL pointing at a webpage + * where the terms of use and ownership of the file is described. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wcop.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wcop extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Woaf.php b/app/libs/vendor/Zend/Media/Id3/Frame/Woaf.php index bed2f4b4..037472e3 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Woaf.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Woaf.php @@ -1,40 +1,40 @@ -Official audio file webpage frame is a URL pointing at a file - * specific webpage. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Woaf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Woaf extends Zend_Media_Id3_LinkFrame -{} +Official audio file webpage frame is a URL pointing at a file + * specific webpage. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Woaf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Woaf extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Woar.php b/app/libs/vendor/Zend/Media/Id3/Frame/Woar.php index 8b78b51e..1dd8bb2f 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Woar.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Woar.php @@ -1,41 +1,41 @@ -Official artist/performer webpage frame is a URL pointing at the - * artists official webpage. There may be more than one WOAR frame in a tag if - * the audio contains more than one performer, but not with the same content. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Woar.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Woar extends Zend_Media_Id3_LinkFrame -{} +Official artist/performer webpage frame is a URL pointing at the + * artists official webpage. There may be more than one WOAR frame in a tag if + * the audio contains more than one performer, but not with the same content. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Woar.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Woar extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Woas.php b/app/libs/vendor/Zend/Media/Id3/Frame/Woas.php index f21fb807..56378da1 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Woas.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Woas.php @@ -1,40 +1,40 @@ -Official audio source webpage frame is a URL pointing at the - * official webpage for the source of the audio file, e.g. a movie. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Woas.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Woas extends Zend_Media_Id3_LinkFrame -{} +Official audio source webpage frame is a URL pointing at the + * official webpage for the source of the audio file, e.g. a movie. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Woas.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Woas extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wors.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wors.php index 0c9de67c..8330e0d8 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wors.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wors.php @@ -1,40 +1,40 @@ -Official Internet radio station homepage contains a URL pointing - * at the homepage of the internet radio station. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wors.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wors extends Zend_Media_Id3_LinkFrame -{} +Official Internet radio station homepage contains a URL pointing + * at the homepage of the internet radio station. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wors.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wors extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wpay.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wpay.php index 3077fa34..d2c8b5d0 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wpay.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wpay.php @@ -1,40 +1,40 @@ -Payment frame is a URL pointing at a webpage that will handle the - * process of paying for this file. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wpay.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wpay extends Zend_Media_Id3_LinkFrame -{} +Payment frame is a URL pointing at a webpage that will handle the + * process of paying for this file. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wpay.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wpay extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wpub.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wpub.php index fac3a989..9db32e84 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wpub.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wpub.php @@ -1,40 +1,40 @@ -Publishers official webpage frame is a URL pointing at the - * official webpage for the publisher. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wpub.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wpub extends Zend_Media_Id3_LinkFrame -{} +Publishers official webpage frame is a URL pointing at the + * official webpage for the publisher. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wpub.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wpub extends Zend_Media_Id3_LinkFrame +{} diff --git a/app/libs/vendor/Zend/Media/Id3/Frame/Wxxx.php b/app/libs/vendor/Zend/Media/Id3/Frame/Wxxx.php index c5c6d3aa..b112113e 100644 --- a/app/libs/vendor/Zend/Media/Id3/Frame/Wxxx.php +++ b/app/libs/vendor/Zend/Media/Id3/Frame/Wxxx.php @@ -1,180 +1,180 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Wxxx.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Id3_Frame_Wxxx extends Zend_Media_Id3_LinkFrame - implements Zend_Media_Id3_Encoding -{ - /** @var integer */ - private $_encoding; - - /** @var string */ - private $_description; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - Zend_Media_Id3_Frame::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - list($this->_description, $this->_link) = - $this->_explodeString16 - ($this->_reader->read($this->_reader->getSize()), 2); - break; - case self::UTF8: - // break intentionally omitted - default: - list($this->_description, $this->_link) = - $this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 2); - break; - } - $this->_description = - $this->_convertString($this->_description, $encoding); - $this->_link = implode($this->_explodeString8($this->_link, 1), ''); - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the link description. - * - * @return string - */ - public function getDescription() - { - return $this->_description; - } - - /** - * Sets the content description text using given encoding. - * - * @param string $description The content description text. - * @param integer $encoding The text encoding. - */ - public function setDescription($description, $encoding = null) - { - $this->_description = $description; - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_description, - Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->writeString16($this->_description, null, 1); - break; - default: - $writer->writeString8($this->_description, 1); - break; - } - $writer->write($this->_link); - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Wxxx.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Id3_Frame_Wxxx extends Zend_Media_Id3_LinkFrame + implements Zend_Media_Id3_Encoding +{ + /** @var integer */ + private $_encoding; + + /** @var string */ + private $_description; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + Zend_Media_Id3_Frame::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + list($this->_description, $this->_link) = + $this->_explodeString16 + ($this->_reader->read($this->_reader->getSize()), 2); + break; + case self::UTF8: + // break intentionally omitted + default: + list($this->_description, $this->_link) = + $this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 2); + break; + } + $this->_description = + $this->_convertString($this->_description, $encoding); + $this->_link = implode($this->_explodeString8($this->_link, 1), ''); + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the link description. + * + * @return string + */ + public function getDescription() + { + return $this->_description; + } + + /** + * Sets the content description text using given encoding. + * + * @param string $description The content description text. + * @param integer $encoding The text encoding. + */ + public function setDescription($description, $encoding = null) + { + $this->_description = $description; + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_description, + Zend_Io_Writer::LITTLE_ENDIAN_ORDER, 1); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->writeString16($this->_description, null, 1); + break; + default: + $writer->writeString8($this->_description, 1); + break; + } + $writer->write($this->_link); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Header.php b/app/libs/vendor/Zend/Media/Id3/Header.php index 706ca408..c2b18671 100644 --- a/app/libs/vendor/Zend/Media/Id3/Header.php +++ b/app/libs/vendor/Zend/Media/Id3/Header.php @@ -1,178 +1,178 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Header.php 216 2011-05-02 14:59:16Z svollbehr $ - */ -final class Zend_Media_Id3_Header extends Zend_Media_Id3_Object -{ - /** A flag to denote whether or not unsynchronisation is applied on all - frames */ - const UNSYNCHRONISATION = 128; - - /** A flag to denote whether or not the header is followed by an extended - header */ - const EXTENDED_HEADER = 64; - - /** A flag used as an experimental indicator. This flag shall always be set - when the tag is in an experimental stage. */ - const EXPERIMENTAL = 32; - - /** - * A flag to denote whether a footer is present at the very end of the tag. - * - * @since ID3v2.4.0 - */ - const FOOTER = 16; - - /** @var integer */ - private $_version = 4.0; - - /** @var integer */ - private $_flags = 0; - - /** @var integer */ - private $_size; - - /** - * Constructs the class with given parameters and reads object related data - * from the ID3v2 tag. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) - return; - - $this->_version = $options['version'] = - $this->_reader->readUInt8() + $this->_reader->readUInt8() / 10; - $this->_flags = $this->_reader->readUInt8(); - $this->_size = $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); - } - - /** - * Returns the tag version number. The version number is in the form of - * major.revision. - * - * @return integer - */ - public function getVersion() - { - return $this->_version; - } - - /** - * Sets the tag version number. Supported version numbers are 3.0 and 4.0 - * for ID3v2.3.0 and ID3v2.4.0 standards, respectively. - * - * @param integer $version The tag version number in the form of - * major.revision. - */ - public function setVersion($version) - { - $this->setOption('version', $this->_version = $version); - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the flags byte. - * - * @return integer - */ - public function getFlags() - { - return $this->_flags; - } - - /** - * Sets the flags byte. - * - * @param string $flags The flags byte. - */ - public function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Returns the tag size, excluding the header and the footer. - * - * @return integer - */ - public function getSize() - { - return $this->_size; - } - - /** - * Sets the tag size, excluding the header and the footer. Called - * automatically upon tag generation to adjust the tag size. - * - * @param integer $size The size of the tag, in bytes. - */ - public function setSize($size) - { - $this->_size = $size; - } - - /** - * Writes the header/footer data without the identifier. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - $writer->writeUInt8(floor($this->_version)) - ->writeUInt8(($this->_version - floor($this->_version)) * 10) - ->writeUInt8($this->_flags) - ->writeUInt32BE($this->_encodeSynchsafe32($this->_size)); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Header.php 216 2011-05-02 14:59:16Z svollbehr $ + */ +final class Zend_Media_Id3_Header extends Zend_Media_Id3_Object +{ + /** A flag to denote whether or not unsynchronisation is applied on all + frames */ + const UNSYNCHRONISATION = 128; + + /** A flag to denote whether or not the header is followed by an extended + header */ + const EXTENDED_HEADER = 64; + + /** A flag used as an experimental indicator. This flag shall always be set + when the tag is in an experimental stage. */ + const EXPERIMENTAL = 32; + + /** + * A flag to denote whether a footer is present at the very end of the tag. + * + * @since ID3v2.4.0 + */ + const FOOTER = 16; + + /** @var integer */ + private $_version = 4.0; + + /** @var integer */ + private $_flags = 0; + + /** @var integer */ + private $_size; + + /** + * Constructs the class with given parameters and reads object related data + * from the ID3v2 tag. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) + return; + + $this->_version = $options['version'] = + $this->_reader->readUInt8() + $this->_reader->readUInt8() / 10; + $this->_flags = $this->_reader->readUInt8(); + $this->_size = $this->_decodeSynchsafe32($this->_reader->readUInt32BE()); + } + + /** + * Returns the tag version number. The version number is in the form of + * major.revision. + * + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Sets the tag version number. Supported version numbers are 3.0 and 4.0 + * for ID3v2.3.0 and ID3v2.4.0 standards, respectively. + * + * @param integer $version The tag version number in the form of + * major.revision. + */ + public function setVersion($version) + { + $this->setOption('version', $this->_version = $version); + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the flags byte. + * + * @return integer + */ + public function getFlags() + { + return $this->_flags; + } + + /** + * Sets the flags byte. + * + * @param string $flags The flags byte. + */ + public function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Returns the tag size, excluding the header and the footer. + * + * @return integer + */ + public function getSize() + { + return $this->_size; + } + + /** + * Sets the tag size, excluding the header and the footer. Called + * automatically upon tag generation to adjust the tag size. + * + * @param integer $size The size of the tag, in bytes. + */ + public function setSize($size) + { + $this->_size = $size; + } + + /** + * Writes the header/footer data without the identifier. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + $writer->writeUInt8(floor($this->_version)) + ->writeUInt8(($this->_version - floor($this->_version)) * 10) + ->writeUInt8($this->_flags) + ->writeUInt32BE($this->_encodeSynchsafe32($this->_size)); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Language.php b/app/libs/vendor/Zend/Media/Id3/Language.php index 478cc591..dc87ec66 100644 --- a/app/libs/vendor/Zend/Media/Id3/Language.php +++ b/app/libs/vendor/Zend/Media/Id3/Language.php @@ -1,56 +1,56 @@ -Zend_Media_Id3_Language interface implies that the - * implementing ID3v2 frame supports its content to be given in multiple - * languages. - * - * The three byte language code is used to describe the language of the frame's - * content, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO-639-2}. The language should be represented in lower case. If the language - * is not known the string 'und' should be used. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Language.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -interface Zend_Media_Id3_Language -{ - /** - * Returns the text language code. - * - * @return string - */ - public function getLanguage(); - - /** - * Sets the text language code. - * - * @param string $language The text language code. - */ - public function setLanguage($language); -} +Zend_Media_Id3_Language interface implies that the + * implementing ID3v2 frame supports its content to be given in multiple + * languages. + * + * The three byte language code is used to describe the language of the frame's + * content, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO-639-2}. The language should be represented in lower case. If the language + * is not known the string 'und' should be used. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Language.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +interface Zend_Media_Id3_Language +{ + /** + * Returns the text language code. + * + * @return string + */ + public function getLanguage(); + + /** + * Sets the text language code. + * + * @param string $language The text language code. + */ + public function setLanguage($language); +} diff --git a/app/libs/vendor/Zend/Media/Id3/LanguageTextFrame.php b/app/libs/vendor/Zend/Media/Id3/LanguageTextFrame.php index eb746fe4..2ee4a943 100644 --- a/app/libs/vendor/Zend/Media/Id3/LanguageTextFrame.php +++ b/app/libs/vendor/Zend/Media/Id3/LanguageTextFrame.php @@ -1,222 +1,222 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: LanguageTextFrame.php 255 2012-01-21 19:46:18Z svollbehr $ - */ -abstract class Zend_Media_Id3_LanguageTextFrame extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding, Zend_Media_Id3_Language -{ - /** - * The text encoding. - * - * @var integer - */ - protected $_encoding; - - /** - * The ISO-639-2 language code. - * - * @var string - */ - protected $_language = 'und'; - - /** - * The text. - * - * @var string - */ - protected $_text; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - $this->_language = strtolower($this->_reader->read(3)); - if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { - $this->_language = 'und'; - } - - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $this->_text = $this->_convertString - ($this->_reader->readString16($this->_reader->getSize()), - $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - $this->_text = $this->_convertString - ($this->_reader->readString8($this->_reader->getSize()), - $encoding); - break; - } - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the language code as specified in the - * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. - * - * @return string - */ - public function getLanguage() - { - return $this->_language; - } - - /** - * Sets the text language code as specified in the - * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. - * - * @see Zend_Media_Id3_Language - * @param string $language The language code. - */ - public function setLanguage($language) - { - $language = strtolower($language); - if ($language == 'xxx') { - $language = 'und'; - } - $this->_language = substr($language, 0, 3); - } - - /** - * Returns the text. - * - * @return string - */ - public function getText() - { - return $this->_text; - } - - /** - * Sets the text using given language and encoding. - * - * @param string $text The text. - * @param string $language The language code. - * @param integer $encoding The text encoding. - */ - public function setText($text, $language = null, $encoding = null) - { - $this->_text = $text; - if ($language !== null) { - $this->setLanguage($language); - } - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding) - ->write($this->_language); - switch ($this->_encoding) { - case self::UTF16LE: - $writer->writeString16 - ($this->_text, Zend_Io_Writer::LITTLE_ENDIAN_ORDER); - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - // break intentionally omitted - default: - $writer->write($this->_text); - break; - } - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: LanguageTextFrame.php 255 2012-01-21 19:46:18Z svollbehr $ + */ +abstract class Zend_Media_Id3_LanguageTextFrame extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding, Zend_Media_Id3_Language +{ + /** + * The text encoding. + * + * @var integer + */ + protected $_encoding; + + /** + * The ISO-639-2 language code. + * + * @var string + */ + protected $_language = 'und'; + + /** + * The text. + * + * @var string + */ + protected $_text; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + $this->_language = strtolower($this->_reader->read(3)); + if ($this->_language == 'xxx' || trim($this->_language, "\0") == '') { + $this->_language = 'und'; + } + + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $this->_text = $this->_convertString + ($this->_reader->readString16($this->_reader->getSize()), + $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + $this->_text = $this->_convertString + ($this->_reader->readString8($this->_reader->getSize()), + $encoding); + break; + } + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regarless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the language code as specified in the + * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. + * + * @return string + */ + public function getLanguage() + { + return $this->_language; + } + + /** + * Sets the text language code as specified in the + * {@link http://www.loc.gov/standards/iso639-2/ ISO-639-2} standard. + * + * @see Zend_Media_Id3_Language + * @param string $language The language code. + */ + public function setLanguage($language) + { + $language = strtolower($language); + if ($language == 'xxx') { + $language = 'und'; + } + $this->_language = substr($language, 0, 3); + } + + /** + * Returns the text. + * + * @return string + */ + public function getText() + { + return $this->_text; + } + + /** + * Sets the text using given language and encoding. + * + * @param string $text The text. + * @param string $language The language code. + * @param integer $encoding The text encoding. + */ + public function setText($text, $language = null, $encoding = null) + { + $this->_text = $text; + if ($language !== null) { + $this->setLanguage($language); + } + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding) + ->write($this->_language); + switch ($this->_encoding) { + case self::UTF16LE: + $writer->writeString16 + ($this->_text, Zend_Io_Writer::LITTLE_ENDIAN_ORDER); + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + // break intentionally omitted + default: + $writer->write($this->_text); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/LinkFrame.php b/app/libs/vendor/Zend/Media/Id3/LinkFrame.php index 2af47364..1ab642db 100644 --- a/app/libs/vendor/Zend/Media/Id3/LinkFrame.php +++ b/app/libs/vendor/Zend/Media/Id3/LinkFrame.php @@ -1,92 +1,92 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: LinkFrame.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Id3_LinkFrame extends Zend_Media_Id3_Frame -{ - /** @var string */ - protected $_link; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->_reader !== null) { - $this->_link = implode - ($this->_explodeString8 - ($this->_reader->read($this->_reader->getSize()), 1), ''); - } - } - - /** - * Returns the link associated with the frame. - * - * @return string - */ - public function getLink() - { - return $this->_link; - } - - /** - * Sets the link. The link encoding is always ISO-8859-1. - * - * @param string $link The link. - */ - public function setLink($link) - { - $this->_link = $link; - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->write($this->_link); - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: LinkFrame.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Id3_LinkFrame extends Zend_Media_Id3_Frame +{ + /** @var string */ + protected $_link; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->_reader !== null) { + $this->_link = implode + ($this->_explodeString8 + ($this->_reader->read($this->_reader->getSize()), 1), ''); + } + } + + /** + * Returns the link associated with the frame. + * + * @return string + */ + public function getLink() + { + return $this->_link; + } + + /** + * Sets the link. The link encoding is always ISO-8859-1. + * + * @param string $link The link. + */ + public function setLink($link) + { + $this->_link = $link; + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->write($this->_link); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/NumberFrame.php b/app/libs/vendor/Zend/Media/Id3/NumberFrame.php index f4d4e8c6..4150ccfa 100644 --- a/app/libs/vendor/Zend/Media/Id3/NumberFrame.php +++ b/app/libs/vendor/Zend/Media/Id3/NumberFrame.php @@ -1,93 +1,93 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: NumberFrame.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Id3_NumberFrame - extends Zend_Media_Id3_TextFrame -{ - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - Zend_Media_Id3_Frame::__construct($reader, $options); - - $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); - - if ($this->_reader === null) { - return; - } - - $this->_reader->skip(1); - $this->setText($this->_reader->readString8($this->_reader->getSize())); - } - - /** - * Returns the integer value of the text. - * - * @return integer - */ - public function getValue() - { - return doubleval($this->getText()); - } - - /** - * Sets the integer value of the text. - * - * @param integer $value The integer value of the text. - */ - public function setValue($value) - { - $this->setText(strval($value), Zend_Media_Id3_Encoding::ISO88591); - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); - parent::_writeData($writer); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: NumberFrame.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Id3_NumberFrame + extends Zend_Media_Id3_TextFrame +{ + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + Zend_Media_Id3_Frame::__construct($reader, $options); + + $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); + + if ($this->_reader === null) { + return; + } + + $this->_reader->skip(1); + $this->setText($this->_reader->readString8($this->_reader->getSize())); + } + + /** + * Returns the integer value of the text. + * + * @return integer + */ + public function getValue() + { + return doubleval($this->getText()); + } + + /** + * Sets the integer value of the text. + * + * @param integer $value The integer value of the text. + */ + public function setValue($value) + { + $this->setText(strval($value), Zend_Media_Id3_Encoding::ISO88591); + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $this->setEncoding(Zend_Media_Id3_Encoding::ISO88591); + parent::_writeData($writer); + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Object.php b/app/libs/vendor/Zend/Media/Id3/Object.php index e2e698b6..4a099b2c 100644 --- a/app/libs/vendor/Zend/Media/Id3/Object.php +++ b/app/libs/vendor/Zend/Media/Id3/Object.php @@ -1,361 +1,361 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Object.php 215 2011-04-30 10:37:09Z svollbehr $ - */ -abstract class Zend_Media_Id3_Object -{ - /** - * The reader object. - * - * @var Zend_Io_Reader - */ - protected $_reader; - - /** - * The options array. - * - * @var Array - */ - private $_options; - - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - $this->_reader = $reader; - $this->_options = &$options; - } - - /** - * Returns the options array. - * - * @return Array - */ - public final function &getOptions() - { - return $this->_options; - } - - /** - * Returns the given option value, or the default value if the option is not - * defined. - * - * @param string $option The name of the option. - * @param mixed $defaultValue The default value to be returned. - */ - public final function getOption($option, $defaultValue = null) - { - if (isset($this->_options[$option])) { - return $this->_options[$option]; - } - return $defaultValue; - } - - /** - * Sets the options array. See {@link Zend_Media_Id3v2} class for available - * options. - * - * @param Array $options The options array. - */ - public final function setOptions(&$options) - { - $this->_options = &$options; - } - - /** - * Sets the given option the given value. - * - * @param string $option The name of the option. - * @param mixed $value The value to set for the option. - */ - public final function setOption($option, $value) - { - $this->_options[$option] = $value; - } - - /** - * Clears the given option value. - * - * @param string $option The name of the option. - */ - public final function clearOption($option) - { - unset($this->_options[$option]); - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } else { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } else { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); - } - } - - /** - * Encodes the given 32-bit integer to 28-bit synchsafe integer, where the - * most significant bit of each byte is zero, making seven bits out of eight - * available. - * - * @param integer $val The integer to encode. - * @return integer - */ - protected final function _encodeSynchsafe32($val) - { - return ($val & 0x7f) | ($val & 0x3f80) << 1 | - ($val & 0x1fc000) << 2 | ($val & 0xfe00000) << 3; - } - - /** - * Decodes the given 28-bit synchsafe integer to regular 32-bit integer. - * - * @param integer $val The integer to decode - * @return integer - */ - protected final function _decodeSynchsafe32($val) - { - return ($val & 0x7f) | ($val & 0x7f00) >> 1 | - ($val & 0x7f0000) >> 2 | ($val & 0x7f000000) >> 3; - } - - /** - * Applies the unsynchronisation scheme to the given data string. - * - * Whenever a false synchronisation is found within the data, one zeroed - * byte is inserted after the first false synchronisation byte. This has the - * side effect that all 0xff00 combinations have to be altered, so they will - * not be affected by the decoding process. - * - * Therefore all the 0xff00 combinations are replaced with the 0xff0000 combination and all the 0xff[0xe0-0xff] - * combinations are replaced with 0xff00[0xe0-0xff] during the unsynchronisation. - * - * @param string $data The input data. - * @return string - */ - protected final function _encodeUnsynchronisation(&$data) - { - return preg_replace('/\xff(?=[\xe0-\xff])/', "\xff\x00", preg_replace('/\xff\x00/', "\xff\x00\x00", $data)); - } - - /** - * Reverses the unsynchronisation scheme from the given data string. - * - * @see _encodeUnsynchronisation - * @param string $data The input data. - * @return string - */ - protected final function _decodeUnsynchronisation(&$data) - { - return preg_replace('/\xff\x00\x00/', "\xff\x00", preg_replace('/\xff\x00(?=[\xe0-\xff])/', "\xff", $data)); - } - - /** - * Splits UTF-16 formatted binary data up according to null terminators - * residing in the string, up to a given limit. - * - * @param string $value The input string. - * @return Array - */ - protected final function _explodeString16($value, $limit = null) - { - $i = 0; - $array = array(); - while (count($array) < $limit - 1 || $limit === null) { - $start = $i; - do { - $i = strpos($value, "\x00\x00", $i); - if ($i === false) { - $array[] = substr($value, $start); - return $array; - } - } while ($i & 0x1 != 0 && $i++); // make sure its aligned - $array[] = substr($value, $start, $i - $start); - $i += 2; - } - $array[] = substr($value, $i); - return $array; - } - - /** - * Splits UTF-8 or ISO-8859-1 formatted binary data according to null - * terminators residing in the string, up to a given limit. - * - * @param string $value The input string. - * @return Array - */ - protected final function _explodeString8($value, $limit = null) - { - return preg_split('/\x00/', $value, $limit); - } - - /** - * Converts string from the given character encoding to the target encoding - * specified by the options as the encoding to display all the texts with, - * and returns the converted string. - * - * Character encoding sets can be {@link Zend_Media_Id3_Encoding} - * constants or already in the string form accepted by iconv. - * - * @param string|Array $string - * @param string|integer $source The source encoding. - * @param string|integer $target The target encoding. Defaults to the - * encoding value set in options. - */ - protected final function _convertString($string, $source, $target = null) - { - if ($target === null) { - $target = $this->getOption('encoding', 'utf-8'); - } - - $source = $this->_translateIntToEncoding($source); - $target = $this->_translateIntToEncoding($target); - - if ($source == $target) { - return $string; - } - - if (is_array($string)) { - foreach ($string as $key => $value) { - $string[$key] = iconv($source, $target, $value); - } - } else { - $string = iconv($source, $target, $string); - } - return $string; - } - - /** - * Returns given encoding in the form accepted by iconv. - * - * Character encoding set can be a {@link Zend_Media_Id3_Encoding} - * constant or already in the string form accepted by iconv. - * - * @param string|integer $encoding The encoding. - * @return string - */ - protected final function _translateIntToEncoding($encoding) - { - if (is_string($encoding)) { - return strtolower($encoding); - } - if (is_integer($encoding)) { - switch ($encoding) { - case Zend_Media_Id3_Encoding::UTF16: - return 'utf-16'; - case Zend_Media_Id3_Encoding::UTF16LE: - return 'utf-16le'; - case Zend_Media_Id3_Encoding::UTF16BE: - return 'utf-16be'; - case Zend_Media_Id3_Encoding::ISO88591: - return 'iso-8859-1'; - default: - return 'utf-8'; - } - } - return 'utf-8'; - } - - /** - * Returns given encoding in the form possible to write to the tag frame. - * - * Character encoding set can be in the string form accepted by iconv or - * already a {@link Zend_Media_Id3_Encoding} constant. - * - * @param string|integer $encoding The encoding. - * @return integer - */ - protected final function _translateEncodingToInt($encoding) - { - if (is_integer($encoding)) { - if ($encoding >= 0 && $encoding <= 4) { - return $encoding; - } - } - if (is_string($encoding)) { - switch ($encoding) { - case 'utf-16': - return Zend_Media_Id3_Encoding::UTF16; - case 'utf-16le': - return Zend_Media_Id3_Encoding::UTF16; - case 'utf-16be': - return Zend_Media_Id3_Encoding::UTF16BE; - case 'iso-8859-1': - return Zend_Media_Id3_Encoding::ISO88591; - default: - return Zend_Media_Id3_Encoding::UTF8; - } - } - return Zend_Media_Id3_Encoding::UTF8; - } - - /** - * Writes the object data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - abstract public function write($writer); -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Object.php 215 2011-04-30 10:37:09Z svollbehr $ + */ +abstract class Zend_Media_Id3_Object +{ + /** + * The reader object. + * + * @var Zend_Io_Reader + */ + protected $_reader; + + /** + * The options array. + * + * @var Array + */ + private $_options; + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + $this->_reader = $reader; + $this->_options = &$options; + } + + /** + * Returns the options array. + * + * @return Array + */ + public final function &getOptions() + { + return $this->_options; + } + + /** + * Returns the given option value, or the default value if the option is not + * defined. + * + * @param string $option The name of the option. + * @param mixed $defaultValue The default value to be returned. + */ + public final function getOption($option, $defaultValue = null) + { + if (isset($this->_options[$option])) { + return $this->_options[$option]; + } + return $defaultValue; + } + + /** + * Sets the options array. See {@link Zend_Media_Id3v2} class for available + * options. + * + * @param Array $options The options array. + */ + public final function setOptions(&$options) + { + $this->_options = &$options; + } + + /** + * Sets the given option the given value. + * + * @param string $option The name of the option. + * @param mixed $value The value to set for the option. + */ + public final function setOption($option, $value) + { + $this->_options[$option] = $value; + } + + /** + * Clears the given option value. + * + * @param string $option The name of the option. + */ + public final function clearOption($option) + { + unset($this->_options[$option]); + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } else { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } else { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); + } + } + + /** + * Encodes the given 32-bit integer to 28-bit synchsafe integer, where the + * most significant bit of each byte is zero, making seven bits out of eight + * available. + * + * @param integer $val The integer to encode. + * @return integer + */ + protected final function _encodeSynchsafe32($val) + { + return ($val & 0x7f) | ($val & 0x3f80) << 1 | + ($val & 0x1fc000) << 2 | ($val & 0xfe00000) << 3; + } + + /** + * Decodes the given 28-bit synchsafe integer to regular 32-bit integer. + * + * @param integer $val The integer to decode + * @return integer + */ + protected final function _decodeSynchsafe32($val) + { + return ($val & 0x7f) | ($val & 0x7f00) >> 1 | + ($val & 0x7f0000) >> 2 | ($val & 0x7f000000) >> 3; + } + + /** + * Applies the unsynchronisation scheme to the given data string. + * + * Whenever a false synchronisation is found within the data, one zeroed + * byte is inserted after the first false synchronisation byte. This has the + * side effect that all 0xff00 combinations have to be altered, so they will + * not be affected by the decoding process. + * + * Therefore all the 0xff00 combinations are replaced with the 0xff0000 combination and all the 0xff[0xe0-0xff] + * combinations are replaced with 0xff00[0xe0-0xff] during the unsynchronisation. + * + * @param string $data The input data. + * @return string + */ + protected final function _encodeUnsynchronisation(&$data) + { + return preg_replace('/\xff(?=[\xe0-\xff])/', "\xff\x00", preg_replace('/\xff\x00/', "\xff\x00\x00", $data)); + } + + /** + * Reverses the unsynchronisation scheme from the given data string. + * + * @see _encodeUnsynchronisation + * @param string $data The input data. + * @return string + */ + protected final function _decodeUnsynchronisation(&$data) + { + return preg_replace('/\xff\x00\x00/', "\xff\x00", preg_replace('/\xff\x00(?=[\xe0-\xff])/', "\xff", $data)); + } + + /** + * Splits UTF-16 formatted binary data up according to null terminators + * residing in the string, up to a given limit. + * + * @param string $value The input string. + * @return Array + */ + protected final function _explodeString16($value, $limit = null) + { + $i = 0; + $array = array(); + while (count($array) < $limit - 1 || $limit === null) { + $start = $i; + do { + $i = strpos($value, "\x00\x00", $i); + if ($i === false) { + $array[] = substr($value, $start); + return $array; + } + } while ($i & 0x1 != 0 && $i++); // make sure its aligned + $array[] = substr($value, $start, $i - $start); + $i += 2; + } + $array[] = substr($value, $i); + return $array; + } + + /** + * Splits UTF-8 or ISO-8859-1 formatted binary data according to null + * terminators residing in the string, up to a given limit. + * + * @param string $value The input string. + * @return Array + */ + protected final function _explodeString8($value, $limit = null) + { + return preg_split('/\x00/', $value, $limit); + } + + /** + * Converts string from the given character encoding to the target encoding + * specified by the options as the encoding to display all the texts with, + * and returns the converted string. + * + * Character encoding sets can be {@link Zend_Media_Id3_Encoding} + * constants or already in the string form accepted by iconv. + * + * @param string|Array $string + * @param string|integer $source The source encoding. + * @param string|integer $target The target encoding. Defaults to the + * encoding value set in options. + */ + protected final function _convertString($string, $source, $target = null) + { + if ($target === null) { + $target = $this->getOption('encoding', 'utf-8'); + } + + $source = $this->_translateIntToEncoding($source); + $target = $this->_translateIntToEncoding($target); + + if ($source == $target) { + return $string; + } + + if (is_array($string)) { + foreach ($string as $key => $value) { + $string[$key] = iconv($source, $target, $value); + } + } else { + $string = iconv($source, $target, $string); + } + return $string; + } + + /** + * Returns given encoding in the form accepted by iconv. + * + * Character encoding set can be a {@link Zend_Media_Id3_Encoding} + * constant or already in the string form accepted by iconv. + * + * @param string|integer $encoding The encoding. + * @return string + */ + protected final function _translateIntToEncoding($encoding) + { + if (is_string($encoding)) { + return strtolower($encoding); + } + if (is_integer($encoding)) { + switch ($encoding) { + case Zend_Media_Id3_Encoding::UTF16: + return 'utf-16'; + case Zend_Media_Id3_Encoding::UTF16LE: + return 'utf-16le'; + case Zend_Media_Id3_Encoding::UTF16BE: + return 'utf-16be'; + case Zend_Media_Id3_Encoding::ISO88591: + return 'iso-8859-1'; + default: + return 'utf-8'; + } + } + return 'utf-8'; + } + + /** + * Returns given encoding in the form possible to write to the tag frame. + * + * Character encoding set can be in the string form accepted by iconv or + * already a {@link Zend_Media_Id3_Encoding} constant. + * + * @param string|integer $encoding The encoding. + * @return integer + */ + protected final function _translateEncodingToInt($encoding) + { + if (is_integer($encoding)) { + if ($encoding >= 0 && $encoding <= 4) { + return $encoding; + } + } + if (is_string($encoding)) { + switch ($encoding) { + case 'utf-16': + return Zend_Media_Id3_Encoding::UTF16; + case 'utf-16le': + return Zend_Media_Id3_Encoding::UTF16; + case 'utf-16be': + return Zend_Media_Id3_Encoding::UTF16BE; + case 'iso-8859-1': + return Zend_Media_Id3_Encoding::ISO88591; + default: + return Zend_Media_Id3_Encoding::UTF8; + } + } + return Zend_Media_Id3_Encoding::UTF8; + } + + /** + * Writes the object data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + abstract public function write($writer); +} diff --git a/app/libs/vendor/Zend/Media/Id3/TextFrame.php b/app/libs/vendor/Zend/Media/Id3/TextFrame.php index ce0fd2b9..2fac2b67 100644 --- a/app/libs/vendor/Zend/Media/Id3/TextFrame.php +++ b/app/libs/vendor/Zend/Media/Id3/TextFrame.php @@ -1,195 +1,195 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: TextFrame.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -abstract class Zend_Media_Id3_TextFrame extends Zend_Media_Id3_Frame - implements Zend_Media_Id3_Encoding -{ - /** - * The text encoding. - * - * @var integer - */ - protected $_encoding; - - /** - * The text array. - * - * @var string - */ - protected $_text; - - /** - * Constructs the class with given parameters and parses object related - * data. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - $this->setEncoding - ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); - - if ($this->_reader === null) { - return; - } - - $encoding = $this->_reader->readUInt8(); - switch ($encoding) { - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $this->_text = $this->_convertString - ($this->_explodeString16 - ($this->_reader->readString16($this->_reader->getSize())), - $encoding); - break; - case self::UTF8: - // break intentionally omitted - default: - $this->_text = $this->_convertString - ($this->_explodeString8 - ($this->_reader->readString8($this->_reader->getSize())), - $encoding); - break; - } - } - - /** - * Returns the text encoding. - * - * All the strings read from a file are automatically converted to the - * character encoding specified with the encoding option. See - * {@link Zend_Media_Id3v2} for details. This method returns that character - * encoding, or any value set after read, translated into a string form - * regardless if it was set using a {@link Zend_Media_Id3_Encoding} constant - * or a string. - * - * @return integer - */ - public function getEncoding() - { - return $this->_translateIntToEncoding($this->_encoding); - } - - /** - * Sets the text encoding. - * - * All the string written to the frame are done so using given character - * encoding. No conversions of existing data take place upon the call to - * this method thus all texts must be given in given character encoding. - * - * The character encoding parameter takes either a - * {@link Zend_Media_Id3_Encoding} constant or a character set name string - * in the form accepted by iconv. The default character encoding used to - * write the frame is 'utf-8'. - * - * @see Zend_Media_Id3_Encoding - * @param integer $encoding The text encoding. - */ - public function setEncoding($encoding) - { - $this->_encoding = $this->_translateEncodingToInt($encoding); - } - - /** - * Returns the first text chunk the frame contains. - * - * @return string - */ - public function getText() - { - return $this->_text[0]; - } - - /** - * Returns an array of texts the frame contains. - * - * @return Array - */ - public function getTexts() - { - return $this->_text; - } - - /** - * Sets the text using given encoding. - * - * @param mixed $text The text string or an array of strings. - * @param integer $encoding The text encoding. - */ - public function setText($text, $encoding = null) - { - $this->_text = is_array($text) ? $text : array($text); - if ($encoding !== null) { - $this->setEncoding($encoding); - } - } - - /** - * Writes the frame raw data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt8($this->_encoding); - switch ($this->_encoding) { - case self::UTF16LE: - $count = count($this->_text); - for ($i = 0; $i < $count; $i++) { - $writer->writeString16 - ($this->_text, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, - $i == $count ? null : 1); - } - break; - case self::UTF16: - // break intentionally omitted - case self::UTF16BE: - $writer->write(implode("\0\0", $this->_text)); - break; - default: - $writer->write(implode("\0", $this->_text)); - break; - } - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: TextFrame.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +abstract class Zend_Media_Id3_TextFrame extends Zend_Media_Id3_Frame + implements Zend_Media_Id3_Encoding +{ + /** + * The text encoding. + * + * @var integer + */ + protected $_encoding; + + /** + * The text array. + * + * @var string + */ + protected $_text; + + /** + * Constructs the class with given parameters and parses object related + * data. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + $this->setEncoding + ($this->getOption('encoding', Zend_Media_Id3_Encoding::UTF8)); + + if ($this->_reader === null) { + return; + } + + $encoding = $this->_reader->readUInt8(); + switch ($encoding) { + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $this->_text = $this->_convertString + ($this->_explodeString16 + ($this->_reader->readString16($this->_reader->getSize())), + $encoding); + break; + case self::UTF8: + // break intentionally omitted + default: + $this->_text = $this->_convertString + ($this->_explodeString8 + ($this->_reader->readString8($this->_reader->getSize())), + $encoding); + break; + } + } + + /** + * Returns the text encoding. + * + * All the strings read from a file are automatically converted to the + * character encoding specified with the encoding option. See + * {@link Zend_Media_Id3v2} for details. This method returns that character + * encoding, or any value set after read, translated into a string form + * regardless if it was set using a {@link Zend_Media_Id3_Encoding} constant + * or a string. + * + * @return integer + */ + public function getEncoding() + { + return $this->_translateIntToEncoding($this->_encoding); + } + + /** + * Sets the text encoding. + * + * All the string written to the frame are done so using given character + * encoding. No conversions of existing data take place upon the call to + * this method thus all texts must be given in given character encoding. + * + * The character encoding parameter takes either a + * {@link Zend_Media_Id3_Encoding} constant or a character set name string + * in the form accepted by iconv. The default character encoding used to + * write the frame is 'utf-8'. + * + * @see Zend_Media_Id3_Encoding + * @param integer $encoding The text encoding. + */ + public function setEncoding($encoding) + { + $this->_encoding = $this->_translateEncodingToInt($encoding); + } + + /** + * Returns the first text chunk the frame contains. + * + * @return string + */ + public function getText() + { + return $this->_text[0]; + } + + /** + * Returns an array of texts the frame contains. + * + * @return Array + */ + public function getTexts() + { + return $this->_text; + } + + /** + * Sets the text using given encoding. + * + * @param mixed $text The text string or an array of strings. + * @param integer $encoding The text encoding. + */ + public function setText($text, $encoding = null) + { + $this->_text = is_array($text) ? $text : array($text); + if ($encoding !== null) { + $this->setEncoding($encoding); + } + } + + /** + * Writes the frame raw data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt8($this->_encoding); + switch ($this->_encoding) { + case self::UTF16LE: + $count = count($this->_text); + for ($i = 0; $i < $count; $i++) { + $writer->writeString16 + ($this->_text, Zend_Io_Writer::LITTLE_ENDIAN_ORDER, + $i == $count ? null : 1); + } + break; + case self::UTF16: + // break intentionally omitted + case self::UTF16BE: + $writer->write(implode("\0\0", $this->_text)); + break; + default: + $writer->write(implode("\0", $this->_text)); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3/Timing.php b/app/libs/vendor/Zend/Media/Id3/Timing.php index d32e9c43..0da16f6b 100644 --- a/app/libs/vendor/Zend/Media/Id3/Timing.php +++ b/app/libs/vendor/Zend/Media/Id3/Timing.php @@ -1,60 +1,60 @@ -Zend_Media_Id3_Timing interface implies that the implementing - * ID3v2 frame contains one or more 32-bit timestamps. - * - * The timestamps are absolute times, meaning that every stamp contains the time - * from the beginning of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage ID3 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Timing.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -interface Zend_Media_Id3_Timing -{ - /** The timestamp is an absolute time, using MPEG frames as unit. */ - const MPEG_FRAMES = 1; - - /** The timestamp is an absolute time, using milliseconds as unit. */ - const MILLISECONDS = 2; - - /** - * Returns the timing format. - * - * @return integer - */ - public function getFormat(); - - /** - * Sets the timing format. - * - - * @param integer $format The timing format. - */ - public function setFormat($format); -} +Zend_Media_Id3_Timing interface implies that the implementing + * ID3v2 frame contains one or more 32-bit timestamps. + * + * The timestamps are absolute times, meaning that every stamp contains the time + * from the beginning of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage ID3 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Timing.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +interface Zend_Media_Id3_Timing +{ + /** The timestamp is an absolute time, using MPEG frames as unit. */ + const MPEG_FRAMES = 1; + + /** The timestamp is an absolute time, using milliseconds as unit. */ + const MILLISECONDS = 2; + + /** + * Returns the timing format. + * + * @return integer + */ + public function getFormat(); + + /** + * Sets the timing format. + * + + * @param integer $format The timing format. + */ + public function setFormat($format); +} diff --git a/app/libs/vendor/Zend/Media/Id3v1.php b/app/libs/vendor/Zend/Media/Id3v1.php index 777e41ec..72a3ed6b 100644 --- a/app/libs/vendor/Zend/Media/Id3v1.php +++ b/app/libs/vendor/Zend/Media/Id3v1.php @@ -1,419 +1,419 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Id3v1.php 217 2011-05-02 19:09:58Z svollbehr $ - */ -final class Zend_Media_Id3v1 -{ - /** @var string */ - private $_title; - - /** @var string */ - private $_artist; - - /** @var string */ - private $_album; - - /** @var string */ - private $_year; - - /** @var string */ - private $_comment; - - /** @var integer */ - private $_track; - - /** @var integer */ - private $_genre = 255; - - /** - * The genre list. - * - * @var Array - */ - public static $genres = array - ('Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge', - 'Hip-Hop', 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B', - 'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', 'Alternative', 'Ska', - 'Death Metal', 'Pranks', 'Soundtrack', 'Euro-Techno', 'Ambient', - 'Trip-Hop', 'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', 'Classical', - 'Instrumental', 'Acid', 'House', 'Game', 'Sound Clip', 'Gospel', - 'Noise', 'AlternRock', 'Bass', 'Soul', 'Punk', 'Space', 'Meditative', - 'Instrumental Pop', 'Instrumental Rock', 'Ethnic', 'Gothic', - 'Darkwave', 'Techno-Industrial', 'Electronic', 'Pop-Folk', 'Eurodance', - 'Dream', 'Southern Rock', 'Comedy', 'Cult', 'Gangsta', 'Top 40', - 'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American', 'Cabaret', - 'New Wave', 'Psychadelic', 'Rave', 'Showtunes', 'Trailer', 'Lo-Fi', - 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro', 'Musical', - 'Rock & Roll', 'Hard Rock', 'Folk', 'Folk-Rock', 'National Folk', - 'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival', 'Celtic', - 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock', - 'Psychedelic Rock', 'Symphonic Rock', 'Slow Rock', 'Big Band', - 'Chorus', 'Easy Listening', 'Acoustic', 'Humour', 'Speech', 'Chanson', - 'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus', - 'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba', - 'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle', - 'Duet', 'Punk Rock', 'Drum Solo', 'A capella', 'Euro-House', - 'Dance Hall', 255 => 'Unknown'); - - /** @var Zend_Io_Reader */ - private $_reader; - - /** @var string */ - private $_filename = null; - - /** - * Constructs the Id3v1 class with given file. The file is not mandatory - * argument and may be omitted as a new tag can be written to a file also by - * giving the filename to the {@link #write} method of this class. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @throws Zend_Media_Id3_Exception if given file descriptor is not valid - */ - public function __construct($filename = null) - { - if ($filename === null) { - return; - } - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - $this->_filename = $filename; - require_once('Zend/Io/FileReader.php'); - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception($e->getMessage()); - } - } - - if ($this->_reader->getSize() < 128) { - $this->_reader = null; - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('File does not contain ID3v1 tag'); - } - $this->_reader->setOffset(-128); - if ($this->_reader->read(3) != 'TAG') { - $this->_reader = null; - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('File does not contain ID3v1 tag'); - } - - $this->_title = $this->_reader->readString8(30, " \0"); - $this->_artist = $this->_reader->readString8(30, " \0"); - $this->_album = $this->_reader->readString8(30, " \0"); - $this->_year = $this->_reader->readString8(4); - $this->_comment = $this->_reader->readString8(28); - - /* ID3v1.1 support for tracks */ - $v11_null = $this->_reader->read(1); - $v11_track = $this->_reader->read(1); - if (ord($v11_null) == 0 && ord($v11_track) != 0) { - $this->_track = ord($v11_track); - } else { - $this->_comment = rtrim - ($this->_comment . $v11_null . $v11_track, " \0"); - } - - $this->_genre = $this->_reader->readInt8(); - } - - /** - * Returns the title field. - * - * @return string - */ - public function getTitle() - { - return $this->_title; - } - - /** - * Sets a new value for the title field. The field cannot exceed 30 - * characters in length. - * - * @param string $title The title. - */ - public function setTitle($title) - { - $this->_title = $title; - } - - /** - * Returns the artist field. - * - * @return string - */ - public function getArtist() - { - return $this->_artist; - } - - /** - * Sets a new value for the artist field. The field cannot exceed 30 - * characters in length. - * - * @param string $artist The artist. - */ - public function setArtist($artist) - { - $this->_artist = $artist; - } - - /** - * Returns the album field. - * - * @return string - */ - public function getAlbum() - { - return $this->_album; - } - - /** - * Sets a new value for the album field. The field cannot exceed 30 - * characters in length. - * - * @param string $album The album. - */ - public function setAlbum($album) - { - $this->_album = $album; - } - - /** - * Returns the year field. - * - * @return string - */ - public function getYear() - { - return $this->_year; - } - - /** - * Sets a new value for the year field. The field cannot exceed 4 - * characters in length. - * - * @param string $year The year. - */ - public function setYear($year) - { - $this->_year = $year; - } - - /** - * Returns the comment field. - * - * @return string - */ - public function getComment() - { - return $this->_comment; - } - - /** - * Sets a new value for the comment field. The field cannot exceed 30 - * characters in length. - * - * @param string $comment The comment. - */ - public function setComment($comment) - { - $this->_comment = $comment; - } - - /** - * Returns the track field. - * - * @since ID3v1.1 - * @return integer - */ - public function getTrack() - { - return $this->_track; - } - - /** - * Sets a new value for the track field. By setting this field you enforce - * the 1.1 version to be used. - * - * @since ID3v1.1 - * @param integer $track The track number. - */ - public function setTrack($track) - { - $this->_track = $track; - } - - /** - * Returns the genre. - * - * @return string - */ - public function getGenre() - { - if (isset(self::$genres[$this->_genre])) - return self::$genres[$this->_genre]; - else - return self::$genres[255]; // unknown - } - - /** - * Sets a new value for the genre field. The value may either be a numerical - * code representing one of the genres, or its string variant. - * - * The genre is set to unknown (code 255) in case the string is not found - * from the static {@link $genres} array of this class. - * - * @param integer $genre The genre. - */ - public function setGenre($genre) - { - if ((is_numeric($genre) && $genre >= 0 && $genre <= 255) || - ($genre = array_search($genre, self::$genres)) !== false) - $this->_genre = $genre; - else - $this->_genre = 255; // unknown - } - - /** - * Writes the possibly altered ID3v1 tag back to the file where it was read. - * If the class was constructed without a file name, one can be provided - * here as an argument. Regardless, the write operation will override - * previous tag information, if found. - * - * @param string $filename The optional path to the file. - * @throws Zend_Media_Id3_Exception if there is no file to write the tag to - */ - public function write($filename = null) - { - if ($filename === null && ($filename = $this->_filename) === null) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('No file given to write the tag to'); - } - - require_once('Zend/Io/FileWriter.php'); - try { - $writer = new Zend_Io_FileWriter($filename); - $offset = $writer->getSize(); - if ($this->_reader !== null) { - $offset = -128; - } else { - $reader = new Zend_Io_Reader($writer->getFileDescriptor()); - $reader->setOffset(-128); - if ($reader->read(3) == 'TAG') - $offset = -128; - } - $writer->setOffset($offset); - $writer->writeString8('TAG') - ->writeString8(substr($this->_title, 0, 30), 30) - ->writeString8(substr($this->_artist, 0, 30), 30) - ->writeString8(substr($this->_album, 0, 30), 30) - ->writeString8(substr($this->_year, 0, 4), 4); - if ($this->_track) { - $writer->writeString8(substr($this->_comment, 0, 28), 28) - ->writeInt8(0) - ->writeInt8($this->_track); - } else { - $writer->writeString8(substr($this->_comment, 0, 30), 30); - } - $writer->writeInt8($this->_genre); - $writer->flush(); - } catch (Zend_Io_Exception $e) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception($e->getMessage()); - } - - $this->_filename = $filename; - } - - /** - * Removes the ID3v1 tag altogether. - * - * @param string $filename The path to the file. - */ - public static function remove($filename) - { - $reader = new Zend_Io_FileReader($filename, 'r+b'); - $reader->setOffset(-128); - if ($reader->read(3) == 'TAG') { - ftruncate($reader->getFileDescriptor(), $reader->getSize() - 128); - } - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { - return call_user_func - (array($this, 'get' . ucfirst(strtolower($name)))); - } else { - require_once('Zend/Media/Id3/Exception.php'); - throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { - call_user_func - (array($this, 'set' . ucfirst(strtolower($name))), $value); - } else { - require_once('Zend/Media/Id3/Exception.php'); - throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); - } - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Id3v1.php 217 2011-05-02 19:09:58Z svollbehr $ + */ +final class Zend_Media_Id3v1 +{ + /** @var string */ + private $_title; + + /** @var string */ + private $_artist; + + /** @var string */ + private $_album; + + /** @var string */ + private $_year; + + /** @var string */ + private $_comment; + + /** @var integer */ + private $_track; + + /** @var integer */ + private $_genre = 255; + + /** + * The genre list. + * + * @var Array + */ + public static $genres = array + ('Blues', 'Classic Rock', 'Country', 'Dance', 'Disco', 'Funk', 'Grunge', + 'Hip-Hop', 'Jazz', 'Metal', 'New Age', 'Oldies', 'Other', 'Pop', 'R&B', + 'Rap', 'Reggae', 'Rock', 'Techno', 'Industrial', 'Alternative', 'Ska', + 'Death Metal', 'Pranks', 'Soundtrack', 'Euro-Techno', 'Ambient', + 'Trip-Hop', 'Vocal', 'Jazz+Funk', 'Fusion', 'Trance', 'Classical', + 'Instrumental', 'Acid', 'House', 'Game', 'Sound Clip', 'Gospel', + 'Noise', 'AlternRock', 'Bass', 'Soul', 'Punk', 'Space', 'Meditative', + 'Instrumental Pop', 'Instrumental Rock', 'Ethnic', 'Gothic', + 'Darkwave', 'Techno-Industrial', 'Electronic', 'Pop-Folk', 'Eurodance', + 'Dream', 'Southern Rock', 'Comedy', 'Cult', 'Gangsta', 'Top 40', + 'Christian Rap', 'Pop/Funk', 'Jungle', 'Native American', 'Cabaret', + 'New Wave', 'Psychadelic', 'Rave', 'Showtunes', 'Trailer', 'Lo-Fi', + 'Tribal', 'Acid Punk', 'Acid Jazz', 'Polka', 'Retro', 'Musical', + 'Rock & Roll', 'Hard Rock', 'Folk', 'Folk-Rock', 'National Folk', + 'Swing', 'Fast Fusion', 'Bebob', 'Latin', 'Revival', 'Celtic', + 'Bluegrass', 'Avantgarde', 'Gothic Rock', 'Progressive Rock', + 'Psychedelic Rock', 'Symphonic Rock', 'Slow Rock', 'Big Band', + 'Chorus', 'Easy Listening', 'Acoustic', 'Humour', 'Speech', 'Chanson', + 'Opera', 'Chamber Music', 'Sonata', 'Symphony', 'Booty Bass', 'Primus', + 'Porn Groove', 'Satire', 'Slow Jam', 'Club', 'Tango', 'Samba', + 'Folklore', 'Ballad', 'Power Ballad', 'Rhythmic Soul', 'Freestyle', + 'Duet', 'Punk Rock', 'Drum Solo', 'A capella', 'Euro-House', + 'Dance Hall', 255 => 'Unknown'); + + /** @var Zend_Io_Reader */ + private $_reader; + + /** @var string */ + private $_filename = null; + + /** + * Constructs the Id3v1 class with given file. The file is not mandatory + * argument and may be omitted as a new tag can be written to a file also by + * giving the filename to the {@link #write} method of this class. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @throws Zend_Media_Id3_Exception if given file descriptor is not valid + */ + public function __construct($filename = null) + { + if ($filename === null) { + return; + } + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + $this->_filename = $filename; + require_once('Zend/Io/FileReader.php'); + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception($e->getMessage()); + } + } + + if ($this->_reader->getSize() < 128) { + $this->_reader = null; + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('File does not contain ID3v1 tag'); + } + $this->_reader->setOffset(-128); + if ($this->_reader->read(3) != 'TAG') { + $this->_reader = null; + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('File does not contain ID3v1 tag'); + } + + $this->_title = $this->_reader->readString8(30, " \0"); + $this->_artist = $this->_reader->readString8(30, " \0"); + $this->_album = $this->_reader->readString8(30, " \0"); + $this->_year = $this->_reader->readString8(4); + $this->_comment = $this->_reader->readString8(28); + + /* ID3v1.1 support for tracks */ + $v11_null = $this->_reader->read(1); + $v11_track = $this->_reader->read(1); + if (ord($v11_null) == 0 && ord($v11_track) != 0) { + $this->_track = ord($v11_track); + } else { + $this->_comment = rtrim + ($this->_comment . $v11_null . $v11_track, " \0"); + } + + $this->_genre = $this->_reader->readInt8(); + } + + /** + * Returns the title field. + * + * @return string + */ + public function getTitle() + { + return $this->_title; + } + + /** + * Sets a new value for the title field. The field cannot exceed 30 + * characters in length. + * + * @param string $title The title. + */ + public function setTitle($title) + { + $this->_title = $title; + } + + /** + * Returns the artist field. + * + * @return string + */ + public function getArtist() + { + return $this->_artist; + } + + /** + * Sets a new value for the artist field. The field cannot exceed 30 + * characters in length. + * + * @param string $artist The artist. + */ + public function setArtist($artist) + { + $this->_artist = $artist; + } + + /** + * Returns the album field. + * + * @return string + */ + public function getAlbum() + { + return $this->_album; + } + + /** + * Sets a new value for the album field. The field cannot exceed 30 + * characters in length. + * + * @param string $album The album. + */ + public function setAlbum($album) + { + $this->_album = $album; + } + + /** + * Returns the year field. + * + * @return string + */ + public function getYear() + { + return $this->_year; + } + + /** + * Sets a new value for the year field. The field cannot exceed 4 + * characters in length. + * + * @param string $year The year. + */ + public function setYear($year) + { + $this->_year = $year; + } + + /** + * Returns the comment field. + * + * @return string + */ + public function getComment() + { + return $this->_comment; + } + + /** + * Sets a new value for the comment field. The field cannot exceed 30 + * characters in length. + * + * @param string $comment The comment. + */ + public function setComment($comment) + { + $this->_comment = $comment; + } + + /** + * Returns the track field. + * + * @since ID3v1.1 + * @return integer + */ + public function getTrack() + { + return $this->_track; + } + + /** + * Sets a new value for the track field. By setting this field you enforce + * the 1.1 version to be used. + * + * @since ID3v1.1 + * @param integer $track The track number. + */ + public function setTrack($track) + { + $this->_track = $track; + } + + /** + * Returns the genre. + * + * @return string + */ + public function getGenre() + { + if (isset(self::$genres[$this->_genre])) + return self::$genres[$this->_genre]; + else + return self::$genres[255]; // unknown + } + + /** + * Sets a new value for the genre field. The value may either be a numerical + * code representing one of the genres, or its string variant. + * + * The genre is set to unknown (code 255) in case the string is not found + * from the static {@link $genres} array of this class. + * + * @param integer $genre The genre. + */ + public function setGenre($genre) + { + if ((is_numeric($genre) && $genre >= 0 && $genre <= 255) || + ($genre = array_search($genre, self::$genres)) !== false) + $this->_genre = $genre; + else + $this->_genre = 255; // unknown + } + + /** + * Writes the possibly altered ID3v1 tag back to the file where it was read. + * If the class was constructed without a file name, one can be provided + * here as an argument. Regardless, the write operation will override + * previous tag information, if found. + * + * @param string $filename The optional path to the file. + * @throws Zend_Media_Id3_Exception if there is no file to write the tag to + */ + public function write($filename = null) + { + if ($filename === null && ($filename = $this->_filename) === null) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('No file given to write the tag to'); + } + + require_once('Zend/Io/FileWriter.php'); + try { + $writer = new Zend_Io_FileWriter($filename); + $offset = $writer->getSize(); + if ($this->_reader !== null) { + $offset = -128; + } else { + $reader = new Zend_Io_Reader($writer->getFileDescriptor()); + $reader->setOffset(-128); + if ($reader->read(3) == 'TAG') + $offset = -128; + } + $writer->setOffset($offset); + $writer->writeString8('TAG') + ->writeString8(substr($this->_title, 0, 30), 30) + ->writeString8(substr($this->_artist, 0, 30), 30) + ->writeString8(substr($this->_album, 0, 30), 30) + ->writeString8(substr($this->_year, 0, 4), 4); + if ($this->_track) { + $writer->writeString8(substr($this->_comment, 0, 28), 28) + ->writeInt8(0) + ->writeInt8($this->_track); + } else { + $writer->writeString8(substr($this->_comment, 0, 30), 30); + } + $writer->writeInt8($this->_genre); + $writer->flush(); + } catch (Zend_Io_Exception $e) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception($e->getMessage()); + } + + $this->_filename = $filename; + } + + /** + * Removes the ID3v1 tag altogether. + * + * @param string $filename The path to the file. + */ + public static function remove($filename) + { + $reader = new Zend_Io_FileReader($filename, 'r+b'); + $reader->setOffset(-128); + if ($reader->read(3) == 'TAG') { + ftruncate($reader->getFileDescriptor(), $reader->getSize() - 128); + } + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func + (array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Media/Id3/Exception.php'); + throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func + (array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Media/Id3/Exception.php'); + throw new Zend_Media_Id3_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Id3v2.php b/app/libs/vendor/Zend/Media/Id3v2.php index 2a020336..7eadfbec 100644 --- a/app/libs/vendor/Zend/Media/Id3v2.php +++ b/app/libs/vendor/Zend/Media/Id3v2.php @@ -1,716 +1,716 @@ - - * @author Ryan Butterfield - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Id3v2.php 273 2012-08-21 17:22:52Z svollbehr $ - */ -final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object -{ - /** @var Zend_Media_Id3_Header */ - private $_header; - - /** @var Zend_Media_Id3_ExtendedHeader */ - private $_extendedHeader; - - /** @var Zend_Media_Id3_Header */ - private $_footer; - - /** @var Array */ - private $_frames = array(); - - /** @var string */ - private $_filename = null; - - /** - * Constructs the Zend_Media_Id3v2 class with given file and options. The - * options array may also be given as the only parameter. - * - * The following options are currently recognized: - * o encoding -- Indicates the encoding that all the texts are presented - * with. See the documentation of iconv for supported values. Please - * note that write operations do not convert string and thus encodings - * are limited to those supported by the {@link Zend_Media_Id3_Encoding} - * interface. - * o version -- The ID3v2 tag version to use in write operation. This - * option is automatically set when a tag is read from a file and - * defaults to version 4.0 for tag write. - * o compat -- Normally unsynchronization is handled automatically behind - * the scenes. However, current versions of Windows operating system and - * Windows Media Player, just to name a few, do not support ID3v2.4 tags - * nor ID3v2.3 tags with unsynchronization. Hence, for compatibility - * reasons, this option is made available to disable automatic tag level - * unsynchronization scheme that version 3.0 supports. - * o readonly -- Indicates that the tag is read from a temporary file or - * another source it cannot be written back to. The tag can, however, - * still be written to another file. - * - * @todo Only limited subset of flags are processed. - * @todo Utilize the SEEK frame and search for a footer to find the tag - * @todo Utilize the LINK frame to fetch frames from other sources - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @param Array $options The options array. - * @throws Zend_Media_Id3_Exception if given file descriptor is not valid - */ - public function __construct($filename = null, $options = array()) - { - parent::__construct(null, $options); - - if (is_array($filename)) { - $options = $filename; - $filename = null; - } - - if ($filename === null) { - $this->_header = new Zend_Media_Id3_Header(null, $options); - return; - } - - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception($e->getMessage()); - } - if (is_string($filename) && !isset($options['readonly'])) { - $this->_filename = $filename; - } - } - - $startOffset = $this->_reader->getOffset(); - - if ($this->_reader->read(3) != 'ID3') { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('File does not contain ID3v2 tag'); - } - - $this->_header = new Zend_Media_Id3_Header($this->_reader, $options); - - $tagSize = $this->_header->getSize(); - - if ($this->_header->getVersion() < 3 || - $this->_header->getVersion() > 4) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('File does not contain ID3v2 tag of supported version: v2.' . - $this->_header->getVersion()); - } - if ($this->_header->getVersion() < 4 && - $this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) { - $data = $this->_reader->read($this->_header->getSize()); - require_once 'Zend/Io/StringReader.php'; - $this->_reader = new Zend_Io_StringReader - ($this->_decodeUnsynchronisation($data)); - $tagSize = $this->_reader->getSize(); - } - $this->clearOption('unsynchronisation'); - if ($this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) { - $this->setOption('unsynchronisation', true); - } - if ($this->_header->hasFlag(Zend_Media_Id3_Header::EXTENDED_HEADER)) { - require_once 'Zend/Media/Id3/ExtendedHeader.php'; - $this->_extendedHeader = - new Zend_Media_Id3_ExtendedHeader($this->_reader, $options); - } - if ($this->_header->hasFlag(Zend_Media_Id3_Header::FOOTER)) { - // skip footer, and rather copy header - $this->_footer = &$this->_header; - } - - while (true) { - $offset = $this->_reader->getOffset(); - - // Jump off the loop if we reached the end of the tag - if ($offset - $startOffset - 10 >= $tagSize - - ($this->hasFooter() ? 10 : 0) - 10 /* header */) { - break; - } - - // Jump off the loop if we reached padding - if (ord($identifier = $this->_reader->read(1)) === 0) { - break; - } - - $identifier .= $this->_reader->read(3); - - // Jump off the loop if we reached invalid entities. This fix is - // just to make things work. Utility called MP3ext does not seem - // to know what it is doing as it uses padding to write its - // version information there. - if ($identifier == 'MP3e') { - break; - } - - $this->_reader->setOffset($offset); - if (@fopen($file = 'Zend/Media/Id3/Frame/' . - ucfirst(strtolower($identifier)) . '.php', 'r', - true) !== false) { - require_once($file); - } - if (class_exists - ($classname = 'Zend_Media_Id3_Frame_' . - ucfirst(strtolower($identifier)))) { - $frame = new $classname($this->_reader, $options); - } else { - require_once 'Zend/Media/Id3/Frame/Unknown.php'; - $frame = - new Zend_Media_Id3_Frame_Unknown($this->_reader, $options); - } - - if (!isset($this->_frames[$frame->getIdentifier()])) { - $this->_frames[$frame->getIdentifier()] = array(); - } - $this->_frames[$frame->getIdentifier()][] = $frame; - } - } - - /** - * Returns the header object. - * - * @return Zend_Media_Id3_Header - */ - public function getHeader() - { - return $this->_header; - } - - /** - * Checks whether there is an extended header present in the tag. Returns - * true if the header is present, false otherwise. - * - * @return boolean - */ - public function hasExtendedHeader() - { - if ($this->_header) { - return $this->_header->hasFlag - (Zend_Media_Id3_Header::EXTENDED_HEADER); - } - return false; - } - - /** - * Returns the extended header object if present, or false - * otherwise. - * - * @return Zend_Media_Id3_ExtendedHeader|false - */ - public function getExtendedHeader() - { - if ($this->hasExtendedHeader()) { - return $this->_extendedHeader; - } - return false; - } - - /** - * Sets the extended header object. - * - * @param Zend_Media_Id3_ExtendedHeader $extendedHeader The header object - */ - public function setExtendedHeader($extendedHeader) - { - if (is_subclass_of($extendedHeader, 'Zend_Media_Id3_ExtendedHeader')) { - $this->_header->flags = - $this->_header->flags | Zend_Media_Id3_Header::EXTENDED_HEADER; - $this->_extendedHeader->setOptions($this->getOptions()); - $this->_extendedHeader = $extendedHeader; - } else { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Invalid argument'); - } - } - - /** - * Checks whether there is a frame given as an argument defined in the tag. - * Returns true if one ore more frames are present, - * false otherwise. - * - * @param string $identifier The frame name. - * @return boolean - */ - public function hasFrame($identifier) - { - return isset($this->_frames[$identifier]); - } - - /** - * Returns all the frames the tag contains as an associate array. The frame - * identifiers work as keys having an array of frames as associated value. - * - * @return Array - */ - public function getFrames() - { - return $this->_frames; - } - - /** - * Returns an array of frames matching the given identifier or an empty - * array if no frames matched the identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches - * any single character. - * - * Please note that one may also use the shorthand $obj->identifier to - * access the first frame with the identifier given. Wildcards cannot be - * used with the shorthand method. - * - * @param string $identifier The frame name. - * @return Array - */ - public function getFramesByIdentifier($identifier) - { - $matches = array(); - $searchPattern = '/^' . - str_replace(array('*', '?'), array('.*', '.'), $identifier) . '$/i'; - foreach ($this->_frames as $identifier => $frames) { - if (preg_match($searchPattern, $identifier)) { - foreach ($frames as $frame) { - $matches[] = $frame; - } - } - } - return $matches; - } - - /** - * Removes any frames matching the given object identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches - * any single character. - * - * One may also use the shorthand unset($obj->identifier) to achieve the - * same result. Wildcards cannot be used with the shorthand method. - * - * @param string $identifier The frame name. - */ - public final function removeFramesByIdentifier($identifier) - { - $searchPattern = '/^' . - str_replace(array('*', '?'), array('.*', '.'), $identifier) . '$/i'; - foreach ($this->_frames as $identifier => $frames) { - if (preg_match($searchPattern, $identifier)) { - foreach ($frames as $key => $value) { - unset($this->_frames[$identifier][$key]); - } - } - } - } - - /** - * Adds a new frame to the tag and returns it. - * - * @param Zend_Media_Id3_Frame $frame The frame to add. - * @return Zend_Media_Id3_Frame - */ - public function addFrame($frame) - { - $frame->setOptions($this->getOptions()); - $frame->setEncoding - ($this->getOption('encoding', $this->getOption('version', 4) < 4 ? - Zend_Media_Id3_Encoding::ISO88591 : Zend_Media_Id3_Encoding::UTF)); - if (!$this->hasFrame($frame->getIdentifier())) { - $this->_frames[$frame->getIdentifier()] = array(); - } - return $this->_frames[$frame->getIdentifier()][] = $frame; - } - - /** - * Remove the given frame from the tag. - * - * @param Zend_Media_Id3_Frame $frame The frame to remove. - */ - public function removeFrame($frame) - { - if (!$this->hasFrame($frame->getIdentifier())) { - return; - } - foreach ($this->_frames[$frame->getIdentifier()] as $key => $value) { - if ($frame === $value) { - unset($this->_frames[$frame->getIdentifier()][$key]); - } - } - } - - /** - * Checks whether there is a footer present in the tag. Returns - * true if the footer is present, false otherwise. - * - * @return boolean - */ - public function hasFooter() - { - return $this->_header->hasFlag(Zend_Media_Id3_Header::FOOTER); - } - - /** - * Returns the footer object if present, or false otherwise. - * - * @return Zend_Media_Id3_Header|false - */ - public function getFooter() - { - if ($this->hasFooter()) { - return $this->_footer; - } - return false; - } - - /** - * Sets whether the tag should have a footer defined. - * - * @param boolean $useFooter Whether the tag should have a footer - */ - public function setFooter($useFooter) - { - if ($useFooter) { - $this->_header->setFlags - ($this->_header->getFlags() | Zend_Media_Id3_Header::FOOTER); - $this->_footer = &$this->_header; - } else { - /* Count footer bytes towards the tag size, so it gets removed or - overridden upon re-write */ - if ($this->hasFooter()) { - $this->_header->setSize($this->_header->getSize() + 10); - } - - $this->_header->setFlags - ($this->_header->getFlags() & ~Zend_Media_Id3_Header::FOOTER); - $this->_footer = null; - } - } - - /** - * Writes the possibly altered ID3v2 tag back to the file where it was read. - * If the class was constructed without a file name, one can be provided - * here as an argument. Regardless, the write operation will override - * previous tag information, if found. - * - * If write is called on a tag without any frames to it, current tag is - * removed from the file altogether. - * - * @param string|Zend_Io_Writer $filename The optional path to the file, use - * null to save to the same file. - */ - public function write($filename) - { - if ($filename === null && ($filename = $this->_filename) === null) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('No file given to write to'); - } else if ($filename !== null && $filename instanceof Zend_Io_Writer) { - require_once 'Zend/Io/Writer.php'; - $this->_writeData($filename); - return; - } else if ($filename !== null && $this->_filename !== null && - realpath($filename) != realpath($this->_filename) && - !copy($this->_filename, $filename)) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('Unable to copy source to destination: ' . - realpath($this->_filename) . '->' . realpath($filename)); - } - - if (($fd = fopen - ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception - ('Unable to open file for writing: ' . $filename); - } - - $hasNoFrames = true; - foreach ($this->_frames as $identifier => $instances) { - if (count($instances) > 0) { - $hasNoFrames = false; - break; - } - } - if ($hasNoFrames === true) { - $this->remove(new Zend_Io_Reader($fd)); - return; - } - - if ($this->_reader !== null) { - $oldTagSize = 10 /* header */ + $this->_header->getSize(); - } else { - $reader = new Zend_Io_Reader($fd); - if ($reader->read(3) == 'ID3') { - $header = new Zend_Media_Id3_Header($reader); - $oldTagSize = 10 /* header */ + $header->getSize(); - } else { - $oldTagSize = 0; - } - } - require_once 'Zend/Io/StringWriter.php'; - $tag = new Zend_Io_StringWriter(); - $this->_writeData($tag); - $tagSize = $tag->getSize(); - - if ($tagSize > $oldTagSize) { - fseek($fd, 0, SEEK_END); - $oldFileSize = ftell($fd); - ftruncate - ($fd, $newFileSize = $tagSize - $oldTagSize + $oldFileSize); - for ($i = 1, $cur = $oldFileSize; $cur > 0; $cur -= 1024, $i++) { - if ($cur >= 1024) { - fseek($fd, -(($i * 1024) + - ($newFileSize - $oldFileSize)), SEEK_END); - $buffer = fread($fd, 1024); - fseek($fd, -($i * 1024), SEEK_END); - $bytes = fwrite($fd, $buffer, 1024); - } else { - fseek($fd, 0); - $buffer = fread($fd, $cur); - fseek($fd, $newFileSize - $oldFileSize); - $bytes = fwrite($fd, $buffer, $cur); - } - } - if (($remaining = $oldFileSize % 1024) != 0) { - // huh? - } - fseek($fd, 0, SEEK_END); - } - fseek($fd, 0); - for ($i = 0; $i < $tagSize; $i += 1024) { - fseek($tag->getFileDescriptor(), $i); - $bytes = fwrite($fd, fread($tag->getFileDescriptor(), 1024)); - } - fclose($fd); - - $this->_filename = $filename; - } - - /** - * Writes the tag data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - private function _writeData($writer) - { - $this->clearOption('unsynchronisation'); - - $buffer = new Zend_Io_StringWriter(); - foreach ($this->_frames as $frames) { - foreach ($frames as $frame) { - $frame->write($buffer); - } - } - $frameData = $buffer->toString(); - $frameDataLength = strlen($frameData); - $paddingLength = 0; - - // ID3v2.4.0 supports frame level unsynchronisation while - // ID3v2.3.0 supports only tag level unsynchronisation. - if ($this->getOption('version', 4) < 4 && - $this->getOption('compat', false) !== true) { - $frameData = $this->_encodeUnsynchronisation($frameData); - if (($len = strlen($frameData)) != $frameDataLength) { - $frameDataLength = $len; - $this->_header->setFlags - ($this->_header->getFlags() | - Zend_Media_Id3_Header::UNSYNCHRONISATION); - } else { - $this->_header->setFlags - ($this->_header->getFlags() & - ~Zend_Media_Id3_Header::UNSYNCHRONISATION); - } - } - - // The tag padding is calculated as follows. If the tag can be written - // in the space of the previous tag, the remaining space is used for - // padding. If there is no previous tag or the new tag is bigger than - // the space taken by the previous tag, the padding is a constant - // 4096 bytes. - if ($this->hasFooter() === false) { - if ($this->_reader !== null && - $frameDataLength < $this->_header->getSize()) { - $paddingLength = $this->_header->getSize() - $frameDataLength; - } else { - $paddingLength = 4096; - } - } - - /* ID3v2.4.0 CRC calculated w/ padding */ - if ($this->getOption('version', 4) >= 4) { - $frameData = - str_pad($frameData, $frameDataLength += $paddingLength, "\0"); - } - - $extendedHeaderData = ''; - $extendedHeaderDataLength = 0; - if ($this->hasExtendedHeader()) { - $this->_extendedHeader->setPadding($paddingLength); - if ($this->_extendedHeader->hasFlag - (Zend_Media_Id3_ExtendedHeader::CRC32)) { - $crc = crc32($frameData); - if ($crc & 0x80000000) { - $crc = -(($crc ^ 0xffffffff) + 1); - } - $this->_extendedHeader->setCrc($crc); - } - $buffer = new Zend_Io_StringWriter(); - $this->_extendedHeader->write($buffer); - $extendedHeaderData = $buffer->toString(); - $extendedHeaderDataLength = strlen($extendedHeaderData); - } - - /* ID3v2.3.0 CRC calculated w/o padding */ - if ($this->getOption('version', 4) < 4) { - $frameData = - str_pad($frameData, $frameDataLength += $paddingLength, "\0"); - } - - $this->_header->setSize($extendedHeaderDataLength + $frameDataLength); - - $writer->write('ID3'); - $this->_header->write($writer); - $writer->write($extendedHeaderData); - $writer->write($frameData); - if ($this->hasFooter()) { - $writer->write('3DI'); - $this->_footer->write($writer); - } - } - - /** - * Removes the ID3v2 tag altogether. - * - * @param string $filename The path to the file. - */ - public static function remove($filename) - { - if ($filename instanceof Zend_Io_Reader) { - $reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - $reader = new Zend_Io_FileReader($filename, 'r+b'); - } - - $fileSize = $reader->getSize(); - if ($reader->read(3) == 'ID3') { - $header = new Zend_Media_Id3_Header($reader); - $tagSize = 10 /* header */ + $header->getSize(); - } else return; - - $fd = $reader->getFileDescriptor(); - for ($i = 0; $tagSize + ($i * 1024) < $fileSize; $i++) { - fseek($fd, $tagSize + ($i * 1024)); - $buffer = fread($fd, 1024); - fseek($fd, ($i * 1024)); - $bytes = fwrite($fd, $buffer, 1024); - } - ftruncate($fd, $fileSize - $tagSize); - } - - /** - * Magic function so that $obj->value will work. The method will attempt to - * return the first frame that matches the identifier. - * - * If there is no frame or field with given name, the method will attempt to - * create a frame with given identifier. - * - * If none of these work, an exception is thrown. - * - * @param string $name The frame or field name. - * @return mixed - */ - public function __get($name) - { - if (!empty($this->_frames[strtoupper($name)])) { - return $this->_frames[strtoupper($name)][0]; - } - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func - (array($this, 'get' . ucfirst($name))); - } - if (@fopen($filename = 'Zend/Media/Id3/Frame/' . ucfirst($name) . - '.php', 'r', true) !== false) { - require_once $filename; - } - if (class_exists - ($classname = 'Zend_Media_Id3_Frame_' . ucfirst($name))) { - return $this->addFrame(new $classname()); - } - require_once 'Zend/Media/Id3/Exception.php'; - throw new Zend_Media_Id3_Exception('Unknown frame/field: ' . $name); - } - - /** - * Magic function so that isset($obj->value) will work. This method checks - * whether the frame matching the identifier exists. - * - * @param string $name The frame identifier. - * @return boolean - */ - public function __isset($name) - { - return isset($this->_frames[strtoupper($name)]); - } - - /** - * Magic function so that unset($obj->value) will work. This method removes - * all the frames matching the identifier. - * - * @param string $name The frame identifier. - */ - public function __unset($name) - { - unset($this->_frames[strtoupper($name)]); - } -} + + * @author Ryan Butterfield + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Id3v2.php 273 2012-08-21 17:22:52Z svollbehr $ + */ +final class Zend_Media_Id3v2 extends Zend_Media_Id3_Object +{ + /** @var Zend_Media_Id3_Header */ + private $_header; + + /** @var Zend_Media_Id3_ExtendedHeader */ + private $_extendedHeader; + + /** @var Zend_Media_Id3_Header */ + private $_footer; + + /** @var Array */ + private $_frames = array(); + + /** @var string */ + private $_filename = null; + + /** + * Constructs the Zend_Media_Id3v2 class with given file and options. The + * options array may also be given as the only parameter. + * + * The following options are currently recognized: + * o encoding -- Indicates the encoding that all the texts are presented + * with. See the documentation of iconv for supported values. Please + * note that write operations do not convert string and thus encodings + * are limited to those supported by the {@link Zend_Media_Id3_Encoding} + * interface. + * o version -- The ID3v2 tag version to use in write operation. This + * option is automatically set when a tag is read from a file and + * defaults to version 4.0 for tag write. + * o compat -- Normally unsynchronization is handled automatically behind + * the scenes. However, current versions of Windows operating system and + * Windows Media Player, just to name a few, do not support ID3v2.4 tags + * nor ID3v2.3 tags with unsynchronization. Hence, for compatibility + * reasons, this option is made available to disable automatic tag level + * unsynchronization scheme that version 3.0 supports. + * o readonly -- Indicates that the tag is read from a temporary file or + * another source it cannot be written back to. The tag can, however, + * still be written to another file. + * + * @todo Only limited subset of flags are processed. + * @todo Utilize the SEEK frame and search for a footer to find the tag + * @todo Utilize the LINK frame to fetch frames from other sources + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @param Array $options The options array. + * @throws Zend_Media_Id3_Exception if given file descriptor is not valid + */ + public function __construct($filename = null, $options = array()) + { + parent::__construct(null, $options); + + if (is_array($filename)) { + $options = $filename; + $filename = null; + } + + if ($filename === null) { + $this->_header = new Zend_Media_Id3_Header(null, $options); + return; + } + + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception($e->getMessage()); + } + if (is_string($filename) && !isset($options['readonly'])) { + $this->_filename = $filename; + } + } + + $startOffset = $this->_reader->getOffset(); + + if ($this->_reader->read(3) != 'ID3') { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('File does not contain ID3v2 tag'); + } + + $this->_header = new Zend_Media_Id3_Header($this->_reader, $options); + + $tagSize = $this->_header->getSize(); + + if ($this->_header->getVersion() < 3 || + $this->_header->getVersion() > 4) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('File does not contain ID3v2 tag of supported version: v2.' . + $this->_header->getVersion()); + } + if ($this->_header->getVersion() < 4 && + $this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) { + $data = $this->_reader->read($this->_header->getSize()); + require_once 'Zend/Io/StringReader.php'; + $this->_reader = new Zend_Io_StringReader + ($this->_decodeUnsynchronisation($data)); + $tagSize = $this->_reader->getSize(); + } + $this->clearOption('unsynchronisation'); + if ($this->_header->hasFlag(Zend_Media_Id3_Header::UNSYNCHRONISATION)) { + $this->setOption('unsynchronisation', true); + } + if ($this->_header->hasFlag(Zend_Media_Id3_Header::EXTENDED_HEADER)) { + require_once 'Zend/Media/Id3/ExtendedHeader.php'; + $this->_extendedHeader = + new Zend_Media_Id3_ExtendedHeader($this->_reader, $options); + } + if ($this->_header->hasFlag(Zend_Media_Id3_Header::FOOTER)) { + // skip footer, and rather copy header + $this->_footer = &$this->_header; + } + + while (true) { + $offset = $this->_reader->getOffset(); + + // Jump off the loop if we reached the end of the tag + if ($offset - $startOffset - 10 >= $tagSize - + ($this->hasFooter() ? 10 : 0) - 10 /* header */) { + break; + } + + // Jump off the loop if we reached padding + if (ord($identifier = $this->_reader->read(1)) === 0) { + break; + } + + $identifier .= $this->_reader->read(3); + + // Jump off the loop if we reached invalid entities. This fix is + // just to make things work. Utility called MP3ext does not seem + // to know what it is doing as it uses padding to write its + // version information there. + if ($identifier == 'MP3e') { + break; + } + + $this->_reader->setOffset($offset); + if (@fopen($file = 'Zend/Media/Id3/Frame/' . + ucfirst(strtolower($identifier)) . '.php', 'r', + true) !== false) { + require_once($file); + } + if (class_exists + ($classname = 'Zend_Media_Id3_Frame_' . + ucfirst(strtolower($identifier)))) { + $frame = new $classname($this->_reader, $options); + } else { + require_once 'Zend/Media/Id3/Frame/Unknown.php'; + $frame = + new Zend_Media_Id3_Frame_Unknown($this->_reader, $options); + } + + if (!isset($this->_frames[$frame->getIdentifier()])) { + $this->_frames[$frame->getIdentifier()] = array(); + } + $this->_frames[$frame->getIdentifier()][] = $frame; + } + } + + /** + * Returns the header object. + * + * @return Zend_Media_Id3_Header + */ + public function getHeader() + { + return $this->_header; + } + + /** + * Checks whether there is an extended header present in the tag. Returns + * true if the header is present, false otherwise. + * + * @return boolean + */ + public function hasExtendedHeader() + { + if ($this->_header) { + return $this->_header->hasFlag + (Zend_Media_Id3_Header::EXTENDED_HEADER); + } + return false; + } + + /** + * Returns the extended header object if present, or false + * otherwise. + * + * @return Zend_Media_Id3_ExtendedHeader|false + */ + public function getExtendedHeader() + { + if ($this->hasExtendedHeader()) { + return $this->_extendedHeader; + } + return false; + } + + /** + * Sets the extended header object. + * + * @param Zend_Media_Id3_ExtendedHeader $extendedHeader The header object + */ + public function setExtendedHeader($extendedHeader) + { + if (is_subclass_of($extendedHeader, 'Zend_Media_Id3_ExtendedHeader')) { + $this->_header->flags = + $this->_header->flags | Zend_Media_Id3_Header::EXTENDED_HEADER; + $this->_extendedHeader->setOptions($this->getOptions()); + $this->_extendedHeader = $extendedHeader; + } else { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Invalid argument'); + } + } + + /** + * Checks whether there is a frame given as an argument defined in the tag. + * Returns true if one ore more frames are present, + * false otherwise. + * + * @param string $identifier The frame name. + * @return boolean + */ + public function hasFrame($identifier) + { + return isset($this->_frames[$identifier]); + } + + /** + * Returns all the frames the tag contains as an associate array. The frame + * identifiers work as keys having an array of frames as associated value. + * + * @return Array + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Returns an array of frames matching the given identifier or an empty + * array if no frames matched the identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches + * any single character. + * + * Please note that one may also use the shorthand $obj->identifier to + * access the first frame with the identifier given. Wildcards cannot be + * used with the shorthand method. + * + * @param string $identifier The frame name. + * @return Array + */ + public function getFramesByIdentifier($identifier) + { + $matches = array(); + $searchPattern = '/^' . + str_replace(array('*', '?'), array('.*', '.'), $identifier) . '$/i'; + foreach ($this->_frames as $identifier => $frames) { + if (preg_match($searchPattern, $identifier)) { + foreach ($frames as $frame) { + $matches[] = $frame; + } + } + } + return $matches; + } + + /** + * Removes any frames matching the given object identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches + * any single character. + * + * One may also use the shorthand unset($obj->identifier) to achieve the + * same result. Wildcards cannot be used with the shorthand method. + * + * @param string $identifier The frame name. + */ + public final function removeFramesByIdentifier($identifier) + { + $searchPattern = '/^' . + str_replace(array('*', '?'), array('.*', '.'), $identifier) . '$/i'; + foreach ($this->_frames as $identifier => $frames) { + if (preg_match($searchPattern, $identifier)) { + foreach ($frames as $key => $value) { + unset($this->_frames[$identifier][$key]); + } + } + } + } + + /** + * Adds a new frame to the tag and returns it. + * + * @param Zend_Media_Id3_Frame $frame The frame to add. + * @return Zend_Media_Id3_Frame + */ + public function addFrame($frame) + { + $frame->setOptions($this->getOptions()); + $frame->setEncoding + ($this->getOption('encoding', $this->getOption('version', 4) < 4 ? + Zend_Media_Id3_Encoding::ISO88591 : Zend_Media_Id3_Encoding::UTF)); + if (!$this->hasFrame($frame->getIdentifier())) { + $this->_frames[$frame->getIdentifier()] = array(); + } + return $this->_frames[$frame->getIdentifier()][] = $frame; + } + + /** + * Remove the given frame from the tag. + * + * @param Zend_Media_Id3_Frame $frame The frame to remove. + */ + public function removeFrame($frame) + { + if (!$this->hasFrame($frame->getIdentifier())) { + return; + } + foreach ($this->_frames[$frame->getIdentifier()] as $key => $value) { + if ($frame === $value) { + unset($this->_frames[$frame->getIdentifier()][$key]); + } + } + } + + /** + * Checks whether there is a footer present in the tag. Returns + * true if the footer is present, false otherwise. + * + * @return boolean + */ + public function hasFooter() + { + return $this->_header->hasFlag(Zend_Media_Id3_Header::FOOTER); + } + + /** + * Returns the footer object if present, or false otherwise. + * + * @return Zend_Media_Id3_Header|false + */ + public function getFooter() + { + if ($this->hasFooter()) { + return $this->_footer; + } + return false; + } + + /** + * Sets whether the tag should have a footer defined. + * + * @param boolean $useFooter Whether the tag should have a footer + */ + public function setFooter($useFooter) + { + if ($useFooter) { + $this->_header->setFlags + ($this->_header->getFlags() | Zend_Media_Id3_Header::FOOTER); + $this->_footer = &$this->_header; + } else { + /* Count footer bytes towards the tag size, so it gets removed or + overridden upon re-write */ + if ($this->hasFooter()) { + $this->_header->setSize($this->_header->getSize() + 10); + } + + $this->_header->setFlags + ($this->_header->getFlags() & ~Zend_Media_Id3_Header::FOOTER); + $this->_footer = null; + } + } + + /** + * Writes the possibly altered ID3v2 tag back to the file where it was read. + * If the class was constructed without a file name, one can be provided + * here as an argument. Regardless, the write operation will override + * previous tag information, if found. + * + * If write is called on a tag without any frames to it, current tag is + * removed from the file altogether. + * + * @param string|Zend_Io_Writer $filename The optional path to the file, use + * null to save to the same file. + */ + public function write($filename) + { + if ($filename === null && ($filename = $this->_filename) === null) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('No file given to write to'); + } else if ($filename !== null && $filename instanceof Zend_Io_Writer) { + require_once 'Zend/Io/Writer.php'; + $this->_writeData($filename); + return; + } else if ($filename !== null && $this->_filename !== null && + realpath($filename) != realpath($this->_filename) && + !copy($this->_filename, $filename)) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('Unable to copy source to destination: ' . + realpath($this->_filename) . '->' . realpath($filename)); + } + + if (($fd = fopen + ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception + ('Unable to open file for writing: ' . $filename); + } + + $hasNoFrames = true; + foreach ($this->_frames as $identifier => $instances) { + if (count($instances) > 0) { + $hasNoFrames = false; + break; + } + } + if ($hasNoFrames === true) { + $this->remove(new Zend_Io_Reader($fd)); + return; + } + + if ($this->_reader !== null) { + $oldTagSize = 10 /* header */ + $this->_header->getSize(); + } else { + $reader = new Zend_Io_Reader($fd); + if ($reader->read(3) == 'ID3') { + $header = new Zend_Media_Id3_Header($reader); + $oldTagSize = 10 /* header */ + $header->getSize(); + } else { + $oldTagSize = 0; + } + } + require_once 'Zend/Io/StringWriter.php'; + $tag = new Zend_Io_StringWriter(); + $this->_writeData($tag); + $tagSize = $tag->getSize(); + + if ($tagSize > $oldTagSize) { + fseek($fd, 0, SEEK_END); + $oldFileSize = ftell($fd); + ftruncate + ($fd, $newFileSize = $tagSize - $oldTagSize + $oldFileSize); + for ($i = 1, $cur = $oldFileSize; $cur > 0; $cur -= 1024, $i++) { + if ($cur >= 1024) { + fseek($fd, -(($i * 1024) + + ($newFileSize - $oldFileSize)), SEEK_END); + $buffer = fread($fd, 1024); + fseek($fd, -($i * 1024), SEEK_END); + $bytes = fwrite($fd, $buffer, 1024); + } else { + fseek($fd, 0); + $buffer = fread($fd, $cur); + fseek($fd, $newFileSize - $oldFileSize); + $bytes = fwrite($fd, $buffer, $cur); + } + } + if (($remaining = $oldFileSize % 1024) != 0) { + // huh? + } + fseek($fd, 0, SEEK_END); + } + fseek($fd, 0); + for ($i = 0; $i < $tagSize; $i += 1024) { + fseek($tag->getFileDescriptor(), $i); + $bytes = fwrite($fd, fread($tag->getFileDescriptor(), 1024)); + } + fclose($fd); + + $this->_filename = $filename; + } + + /** + * Writes the tag data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + private function _writeData($writer) + { + $this->clearOption('unsynchronisation'); + + $buffer = new Zend_Io_StringWriter(); + foreach ($this->_frames as $frames) { + foreach ($frames as $frame) { + $frame->write($buffer); + } + } + $frameData = $buffer->toString(); + $frameDataLength = strlen($frameData); + $paddingLength = 0; + + // ID3v2.4.0 supports frame level unsynchronisation while + // ID3v2.3.0 supports only tag level unsynchronisation. + if ($this->getOption('version', 4) < 4 && + $this->getOption('compat', false) !== true) { + $frameData = $this->_encodeUnsynchronisation($frameData); + if (($len = strlen($frameData)) != $frameDataLength) { + $frameDataLength = $len; + $this->_header->setFlags + ($this->_header->getFlags() | + Zend_Media_Id3_Header::UNSYNCHRONISATION); + } else { + $this->_header->setFlags + ($this->_header->getFlags() & + ~Zend_Media_Id3_Header::UNSYNCHRONISATION); + } + } + + // The tag padding is calculated as follows. If the tag can be written + // in the space of the previous tag, the remaining space is used for + // padding. If there is no previous tag or the new tag is bigger than + // the space taken by the previous tag, the padding is a constant + // 4096 bytes. + if ($this->hasFooter() === false) { + if ($this->_reader !== null && + $frameDataLength < $this->_header->getSize()) { + $paddingLength = $this->_header->getSize() - $frameDataLength; + } else { + $paddingLength = 4096; + } + } + + /* ID3v2.4.0 CRC calculated w/ padding */ + if ($this->getOption('version', 4) >= 4) { + $frameData = + str_pad($frameData, $frameDataLength += $paddingLength, "\0"); + } + + $extendedHeaderData = ''; + $extendedHeaderDataLength = 0; + if ($this->hasExtendedHeader()) { + $this->_extendedHeader->setPadding($paddingLength); + if ($this->_extendedHeader->hasFlag + (Zend_Media_Id3_ExtendedHeader::CRC32)) { + $crc = crc32($frameData); + if ($crc & 0x80000000) { + $crc = -(($crc ^ 0xffffffff) + 1); + } + $this->_extendedHeader->setCrc($crc); + } + $buffer = new Zend_Io_StringWriter(); + $this->_extendedHeader->write($buffer); + $extendedHeaderData = $buffer->toString(); + $extendedHeaderDataLength = strlen($extendedHeaderData); + } + + /* ID3v2.3.0 CRC calculated w/o padding */ + if ($this->getOption('version', 4) < 4) { + $frameData = + str_pad($frameData, $frameDataLength += $paddingLength, "\0"); + } + + $this->_header->setSize($extendedHeaderDataLength + $frameDataLength); + + $writer->write('ID3'); + $this->_header->write($writer); + $writer->write($extendedHeaderData); + $writer->write($frameData); + if ($this->hasFooter()) { + $writer->write('3DI'); + $this->_footer->write($writer); + } + } + + /** + * Removes the ID3v2 tag altogether. + * + * @param string $filename The path to the file. + */ + public static function remove($filename) + { + if ($filename instanceof Zend_Io_Reader) { + $reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + $reader = new Zend_Io_FileReader($filename, 'r+b'); + } + + $fileSize = $reader->getSize(); + if ($reader->read(3) == 'ID3') { + $header = new Zend_Media_Id3_Header($reader); + $tagSize = 10 /* header */ + $header->getSize(); + } else return; + + $fd = $reader->getFileDescriptor(); + for ($i = 0; $tagSize + ($i * 1024) < $fileSize; $i++) { + fseek($fd, $tagSize + ($i * 1024)); + $buffer = fread($fd, 1024); + fseek($fd, ($i * 1024)); + $bytes = fwrite($fd, $buffer, 1024); + } + ftruncate($fd, $fileSize - $tagSize); + } + + /** + * Magic function so that $obj->value will work. The method will attempt to + * return the first frame that matches the identifier. + * + * If there is no frame or field with given name, the method will attempt to + * create a frame with given identifier. + * + * If none of these work, an exception is thrown. + * + * @param string $name The frame or field name. + * @return mixed + */ + public function __get($name) + { + if (!empty($this->_frames[strtoupper($name)])) { + return $this->_frames[strtoupper($name)][0]; + } + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func + (array($this, 'get' . ucfirst($name))); + } + if (@fopen($filename = 'Zend/Media/Id3/Frame/' . ucfirst($name) . + '.php', 'r', true) !== false) { + require_once $filename; + } + if (class_exists + ($classname = 'Zend_Media_Id3_Frame_' . ucfirst($name))) { + return $this->addFrame(new $classname()); + } + require_once 'Zend/Media/Id3/Exception.php'; + throw new Zend_Media_Id3_Exception('Unknown frame/field: ' . $name); + } + + /** + * Magic function so that isset($obj->value) will work. This method checks + * whether the frame matching the identifier exists. + * + * @param string $name The frame identifier. + * @return boolean + */ + public function __isset($name) + { + return isset($this->_frames[strtoupper($name)]); + } + + /** + * Magic function so that unset($obj->value) will work. This method removes + * all the frames matching the identifier. + * + * @param string $name The frame identifier. + */ + public function __unset($name) + { + unset($this->_frames[strtoupper($name)]); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496.php b/app/libs/vendor/Zend/Media/Iso14496.php index 40b8c125..0521db32 100644 --- a/app/libs/vendor/Zend/Media/Iso14496.php +++ b/app/libs/vendor/Zend/Media/Iso14496.php @@ -1,419 +1,419 @@ - - *
  • ftyp -- {@link Zend_Media_Iso14496_Box_Ftyp File Type Box}; - * file type and compatibility - *
  • pdin -- {@link Zend_Media_Iso14496_Box_Pdin Progressive Download - * Information Box} - *
  • moov -- {@link Zend_Media_Iso14496_Box_Moov Movie Box}; - * container for all the metadata - *
      - *
    • mvhd -- {@link Zend_Media_Iso14496_Box_Mvhd Movie Header - * Box}; overall declarations - *
    • trak -- {@link Zend_Media_Iso14496_Box_Trak Track Box}; - * container for an individual track or stream - *
        - *
      • tkhd -- {@link Zend_Media_Iso14496_Box_Tkhd Track Header - * Box}; overall information about the track - *
      • tref -- {@link Zend_Media_Iso14496_Box_Tref Track Reference - * Box} - *
      • edts -- {@link Zend_Media_Iso14496_Box_Edts Edit Box} - *
          - *
        • elst -- {@link Zend_Media_Iso14496_Box_Elst Edit List Box} - *
        - *
      • mdia -- {@link Zend_Media_Iso14496_Box_Mdia Media Box} - *
          - *
        • mdhd -- {@link Zend_Media_Iso14496_Box_Mdhd Media Header - * Box}; overall information about the media - *
        • hdlr -- {@link Zend_Media_Iso14496_Box_Hdlr Handler - * Reference Box}; declares the media type - *
        • minf -- {@link Zend_Media_Iso14496_Box_Minf Media - * Information Box} - *
            - *
          • vmhd -- {@link Zend_Media_Iso14496_Box_Vmhd Video Media Header - * Box}; overall information (video track only) - *
          • smhd -- {@link Zend_Media_Iso14496_Box_Smhd Sound Media Header - * Box}; overall information (sound track only) - *
          • hmhd -- {@link Zend_Media_Iso14496_Box_Hmhd Hint Media Header - * Box}; overall information (hint track only) - *
          • nmhd -- {@link Zend_Media_Iso14496_Box_Nmhd Null Media Header - * Box}; overall information (some tracks only) - *
          • dinf -- {@link Zend_Media_Iso14496_Box_Dinf Data - * Information Box} - *
              - *
            • dref -- {@link Zend_Media_Iso14496_Box_Dref Data - * Reference Box} - *
            - *
          • stbl -- {@link Zend_Media_Iso14496_Box_Stbl Sample - * Table Box} - *
              - *
            • stsd -- {@link Zend_Media_Iso14496_Box_Stsd Sample - * Descriptions Box} - *
            • stts -- {@link Zend_Media_Iso14496_Box_Stts Decoding - * Time To Sample Box} - *
            • ctts -- {@link Zend_Media_Iso14496_Box_Ctts Composition Time - * To Sample Box} - *
            • stsc -- {@link Zend_Media_Iso14496_Box_Stsc Sample To - * Chunk Box} - *
            • stsz -- {@link Zend_Media_Iso14496_Box_Stsz Sample Size - * Box} - *
            • stz2 -- {@link Zend_Media_Iso14496_Box_Stz2 Compact Sample - * Size Box} - *
            • stco -- {@link Zend_Media_Iso14496_Box_Stco Chunk - * Offset Box}; 32-bit - *
            • co64 -- {@link Zend_Media_Iso14496_Box_Co64 Chunk Ooffset - * Box}; 64-bit - *
            • stss -- {@link Zend_Media_Iso14496_Box_Stss Sync Sample - * Table Box} - *
            • stsh -- {@link Zend_Media_Iso14496_Box_Stsh Shadow Sync - * Sample Table Box} - *
            • padb -- {@link Zend_Media_Iso14496_Box_Padb Padding Bits - * Box} - *
            • stdp -- {@link Zend_Media_Iso14496_Box_Stdp Sample - * Degradation Priority Box} - *
            • sdtp -- {@link Zend_Media_Iso14496_Box_Sdtp Independent and - * Disposable Samples Box} - *
            • sbgp -- {@link Zend_Media_Iso14496_Box_Sbgp Sample To Group - * Box} - *
            • sgpd -- {@link Zend_Media_Iso14496_Box_Sgpd Sample Group - * Description} - *
            • subs -- {@link Zend_Media_Iso14496_Box_Subs Sub-Sample - * Information Box} - *
            - *
          - *
        - *
      - *
    • mvex -- {@link Zend_Media_Iso14496_Box_Mvex Movie Extends Box} - *
        - *
      • mehd -- {@link Zend_Media_Iso14496_Box_Mehd Movie Extends Header - * Box} - *
      • trex -- {@link Zend_Media_Iso14496_Box_Trex Track Extends - * Box} - *
      - *
    • ipmc -- {@link Zend_Media_Iso14496_Box_Ipmc IPMP Control Box} - *
    - *
  • moof -- {@link Zend_Media_Iso14496_Box_Moof Movie Fragment Box} - *
      - *
    • mfhd -- {@link Zend_Media_Iso14496_Box_Mfhd Movie Fragment - * Header Box} - *
    • traf -- {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box} - *
        - *
      • tfhd -- {@link Zend_Media_Iso14496_Box_Tfhd Track Fragment - * Header Box} - *
      • trun -- {@link Zend_Media_Iso14496_Box_Trun Track Fragment - * Run} - *
      • sdtp -- {@link Zend_Media_Iso14496_Box_Sdtp Independent and - * Disposable Samples} - *
      • sbgp -- {@link Zend_Media_Iso14496_Box_Sbgp !SampleToGroup - * Box} - *
      • subs -- {@link Zend_Media_Iso14496_Box_Subs Sub-Sample Information - * Box} - *
      - *
    - *
  • mfra -- {@link Zend_Media_Iso14496_Box_Mfra Movie Fragment Random - * Access Box} - *
      - *
    • tfra -- {@link Zend_Media_Iso14496_Box_Tfra Track Fragment Random - * Access Box} - *
    • mfro -- {@link Zend_Media_Iso14496_Box_Mfro Movie Fragment - * Random Access Offset Box} - *
    - *
  • mdat -- {@link Zend_Media_Iso14496_Box_Mdat Media Data Box} - *
  • free -- {@link Zend_Media_Iso14496_Box_Free Free Space Box} - *
  • skip -- {@link Zend_Media_Iso14496_Box_Skip Free Space Box} - *
      - *
    • udta -- {@link Zend_Media_Iso14496_Box_Udta User Data Box} - *
        - *
      • cprt -- {@link Zend_Media_Iso14496_Box_Cprt Copyright Box} - *
      - *
    - *
  • meta -- {@link Zend_Media_Iso14496_Box_Meta The Meta Box} - *
      - *
    • hdlr -- {@link Zend_Media_Iso14496_Box_Hdlr Handler Reference - * Box}; declares the metadata type - *
    • dinf -- {@link Zend_Media_Iso14496_Box_Dinf Data Information - * Box} - *
        - *
      • dref -- {@link Zend_Media_Iso14496_Box_Dref Data Reference - * Box}; declares source(s) of metadata items - *
      - *
    • ipmc -- {@link Zend_Media_Iso14496_Box_Ipmc IPMP Control Box} - *
    • iloc -- {@link Zend_Media_Iso14496_Box_Iloc Item Location Box} - *
    • ipro -- {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} - *
        - *
      • sinf -- {@link Zend_Media_Iso14496_Box_Sinf Protection Scheme - * Information Box} - *
          - *
        • frma -- {@link Zend_Media_Iso14496_Box_Frma Original Format - * Box} - *
        • imif -- {@link Zend_Media_Iso14496_Box_Imif IPMP Information - * Box} - *
        • schm -- {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box} - *
        • schi -- {@link Zend_Media_Iso14496_Box_Schi Scheme Information - * Box} - *
        - *
      - *
    • iinf -- {@link Zend_Media_Iso14496_Box_Iinf Item Information - * Box} - *
        - *
      • infe -- {@link Zend_Media_Iso14496_Box_Infe Item Information Entry - * Box} - *
      - *
    • xml -- {@link Zend_Media_Iso14496_Box_Xml XML Box} - *
    • bxml -- {@link Zend_Media_Iso14496_Box_Bxml Binary XML Box} - *
    • pitm -- {@link Zend_Media_Iso14496_Box_Pitm Primary Item Reference - * Box} - *
    - * - * - * There are two non-standard extensions to the ISO 14496 standard that add the - * ability to include file meta information. Both the boxes reside under - * moov.udta.meta. - * - *
      - *
    • moov -- {@link Zend_Media_Iso14496_Box_Moov Movie Box}; - * container for all the metadata - *
    • udta -- {@link Zend_Media_Iso14496_Box_Udta User Data Box} - *
    • meta -- {@link Zend_Media_Iso14496_Box_Meta The Meta Box} - *
        - *
      • ilst -- {@link Zend_Media_Iso14496_Box_Ilst The iTunes/iPod Tag - * Container Box} - *
      • id32 -- {@link Zend_Media_Iso14496_Box_Id32 The ID3v2 Box} - *
      - *
    - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iso14496.php 260 2012-03-05 19:06:21Z svollbehr $ - */ -final class Zend_Media_Iso14496 extends Zend_Media_Iso14496_Box -{ - /** @var string */ - private $_filename; - - /** @var boolean */ - private $_autoClose = false; - - /** - * Constructs the Zend_Media_Iso14496 class with given file and options. - * - * The following options are currently recognized: - * o base -- Indicates that only boxes with the given base path are parsed - * from the ISO base media file. Parsing all boxes can possibly have a - * significant impact on running time. Base path is a list of nested - * boxes separated by a dot. The use of base option implies readonly - * option. - * o readonly -- Indicates that the file is read from a temporary location - * or another source it cannot be written back to. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if (isset($options['base'])) { - $options['readonly'] = true; - } - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - try { - $this->_reader = new Zend_Io_FileReader($filename); - $this->_autoClose = true; - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception($e->getMessage()); - } - if (is_string($filename) && !isset($options['readonly'])) { - $this->_filename = $filename; - } - } - $this->setOptions($options); - $this->setOffset(0); - $this->setSize($this->_reader->getSize()); - $this->setType('file'); - $this->setContainer(true); - $this->constructBoxes(); - } - - /** - * Closes down the reader. - */ - public function __destruct() - { - parent::__destruct(); - if ($this->_autoClose === true && $this->_reader !== null) { - $this->_reader->close(); - } - } - - /** - * Writes the changes back to given media file. - * - * The write operation commits only changes made to the Movie Box. It - * further changes the order of the Movie Box and Media Data Box in a way - * compatible for progressive download from a web page. - * - * All box offsets must be assumed to be invalid after the write operation. - * - * @param string $filename The optional path to the file, use null to save - * to the same file. - */ - public function write($filename) - { - if ($filename === null && ($filename = $this->_filename) === null) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception - ('No file given to write to'); - } else if ($filename !== null && $this->_filename !== null && - realpath($filename) != realpath($this->_filename) && - !copy($this->_filename, $filename)) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception - ('Unable to copy source to destination: ' . - realpath($this->_filename) . '->' . realpath($filename)); - } - - if (($fd = fopen - ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception - ('Unable to open file for writing: ' . $filename); - } - - /* Calculate file size */ - fseek($fd, 0, SEEK_END); - $oldFileSize = ftell($fd); - $oldMoovSize = $this->moov->getSize(); - $this->moov->udta->meta->free->setSize(8); - $this->moov->udta->meta->hdlr->setHandlerType('mdir'); - $newFileSize = $oldFileSize - $oldMoovSize + $this->moov->getHeapSize(); - - /* Calculate free space size */ - if ($oldFileSize < $newFileSize || - $this->mdat->getOffset() < $this->moov->getOffset()) { - // Add constant 4096 bytes for free space to be used later - $this->moov->udta->meta->free->setSize(8 /* header */ + 4096); - ftruncate($fd, $newFileSize += 4096); - } else { - // Adjust free space to fill up the rest of the space - $this->moov->udta->meta->free->setSize - (8 + $oldFileSize - $newFileSize); - $newFileSize = $oldFileSize; - } - - /* Calculate positions */ - if ($this->mdat->getOffset() < $this->moov->getOffset()) { - $start = $this->mdat->getOffset(); - $until = $this->moov->getOffset(); - $where = $newFileSize; - $delta = $this->moov->getHeapSize(); - } else { - $start = $this->moov->getOffset(); - $until = $oldFileSize; - $where = $newFileSize; - $delta = $newFileSize - $oldFileSize; - } - - /* Move data to the end of the file */ - if ($newFileSize != $oldFileSize) { - for ($i = 1, $cur = $until; $cur > $start; $cur -= 1024, $i++) { - fseek - ($fd, $until - (($i * 1024) + - ($excess = $cur - 1024 > $start ? - 0 : $cur - $start - 1024))); - $buffer = fread($fd, 1024); - fseek($fd, $where - (($i * 1024) + $excess)); - fwrite($fd, $buffer, 1024); - } - } - - - /* Update stco/co64 to correspond the data move */ - foreach ($this->moov->getBoxesByIdentifier('trak') as $trak) { - $chunkOffsetBox = - (isset($trak->mdia->minf->stbl->stco) ? - $trak->mdia->minf->stbl->stco : - $trak->mdia->minf->stbl->co64); - $chunkOffsetTable = $chunkOffsetBox->getChunkOffsetTable(); - $chunkOffsetTableCount = count($chunkOffsetTable); - for ($i = 1; $i <= $chunkOffsetTableCount; $i++) { - $chunkOffsetTable[$i] += $delta; - } - $chunkOffsetBox->setChunkOffsetTable($chunkOffsetTable); - } - - /* Write moov box */ - fseek($fd, $start); - $this->moov->write(new Zend_Io_Writer($fd)); - fclose($fd); - } -} + + *
  • ftyp -- {@link Zend_Media_Iso14496_Box_Ftyp File Type Box}; + * file type and compatibility + *
  • pdin -- {@link Zend_Media_Iso14496_Box_Pdin Progressive Download + * Information Box} + *
  • moov -- {@link Zend_Media_Iso14496_Box_Moov Movie Box}; + * container for all the metadata + *
      + *
    • mvhd -- {@link Zend_Media_Iso14496_Box_Mvhd Movie Header + * Box}; overall declarations + *
    • trak -- {@link Zend_Media_Iso14496_Box_Trak Track Box}; + * container for an individual track or stream + *
        + *
      • tkhd -- {@link Zend_Media_Iso14496_Box_Tkhd Track Header + * Box}; overall information about the track + *
      • tref -- {@link Zend_Media_Iso14496_Box_Tref Track Reference + * Box} + *
      • edts -- {@link Zend_Media_Iso14496_Box_Edts Edit Box} + *
          + *
        • elst -- {@link Zend_Media_Iso14496_Box_Elst Edit List Box} + *
        + *
      • mdia -- {@link Zend_Media_Iso14496_Box_Mdia Media Box} + *
          + *
        • mdhd -- {@link Zend_Media_Iso14496_Box_Mdhd Media Header + * Box}; overall information about the media + *
        • hdlr -- {@link Zend_Media_Iso14496_Box_Hdlr Handler + * Reference Box}; declares the media type + *
        • minf -- {@link Zend_Media_Iso14496_Box_Minf Media + * Information Box} + *
            + *
          • vmhd -- {@link Zend_Media_Iso14496_Box_Vmhd Video Media Header + * Box}; overall information (video track only) + *
          • smhd -- {@link Zend_Media_Iso14496_Box_Smhd Sound Media Header + * Box}; overall information (sound track only) + *
          • hmhd -- {@link Zend_Media_Iso14496_Box_Hmhd Hint Media Header + * Box}; overall information (hint track only) + *
          • nmhd -- {@link Zend_Media_Iso14496_Box_Nmhd Null Media Header + * Box}; overall information (some tracks only) + *
          • dinf -- {@link Zend_Media_Iso14496_Box_Dinf Data + * Information Box} + *
              + *
            • dref -- {@link Zend_Media_Iso14496_Box_Dref Data + * Reference Box} + *
            + *
          • stbl -- {@link Zend_Media_Iso14496_Box_Stbl Sample + * Table Box} + *
              + *
            • stsd -- {@link Zend_Media_Iso14496_Box_Stsd Sample + * Descriptions Box} + *
            • stts -- {@link Zend_Media_Iso14496_Box_Stts Decoding + * Time To Sample Box} + *
            • ctts -- {@link Zend_Media_Iso14496_Box_Ctts Composition Time + * To Sample Box} + *
            • stsc -- {@link Zend_Media_Iso14496_Box_Stsc Sample To + * Chunk Box} + *
            • stsz -- {@link Zend_Media_Iso14496_Box_Stsz Sample Size + * Box} + *
            • stz2 -- {@link Zend_Media_Iso14496_Box_Stz2 Compact Sample + * Size Box} + *
            • stco -- {@link Zend_Media_Iso14496_Box_Stco Chunk + * Offset Box}; 32-bit + *
            • co64 -- {@link Zend_Media_Iso14496_Box_Co64 Chunk Ooffset + * Box}; 64-bit + *
            • stss -- {@link Zend_Media_Iso14496_Box_Stss Sync Sample + * Table Box} + *
            • stsh -- {@link Zend_Media_Iso14496_Box_Stsh Shadow Sync + * Sample Table Box} + *
            • padb -- {@link Zend_Media_Iso14496_Box_Padb Padding Bits + * Box} + *
            • stdp -- {@link Zend_Media_Iso14496_Box_Stdp Sample + * Degradation Priority Box} + *
            • sdtp -- {@link Zend_Media_Iso14496_Box_Sdtp Independent and + * Disposable Samples Box} + *
            • sbgp -- {@link Zend_Media_Iso14496_Box_Sbgp Sample To Group + * Box} + *
            • sgpd -- {@link Zend_Media_Iso14496_Box_Sgpd Sample Group + * Description} + *
            • subs -- {@link Zend_Media_Iso14496_Box_Subs Sub-Sample + * Information Box} + *
            + *
          + *
        + *
      + *
    • mvex -- {@link Zend_Media_Iso14496_Box_Mvex Movie Extends Box} + *
        + *
      • mehd -- {@link Zend_Media_Iso14496_Box_Mehd Movie Extends Header + * Box} + *
      • trex -- {@link Zend_Media_Iso14496_Box_Trex Track Extends + * Box} + *
      + *
    • ipmc -- {@link Zend_Media_Iso14496_Box_Ipmc IPMP Control Box} + *
    + *
  • moof -- {@link Zend_Media_Iso14496_Box_Moof Movie Fragment Box} + *
      + *
    • mfhd -- {@link Zend_Media_Iso14496_Box_Mfhd Movie Fragment + * Header Box} + *
    • traf -- {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box} + *
        + *
      • tfhd -- {@link Zend_Media_Iso14496_Box_Tfhd Track Fragment + * Header Box} + *
      • trun -- {@link Zend_Media_Iso14496_Box_Trun Track Fragment + * Run} + *
      • sdtp -- {@link Zend_Media_Iso14496_Box_Sdtp Independent and + * Disposable Samples} + *
      • sbgp -- {@link Zend_Media_Iso14496_Box_Sbgp !SampleToGroup + * Box} + *
      • subs -- {@link Zend_Media_Iso14496_Box_Subs Sub-Sample Information + * Box} + *
      + *
    + *
  • mfra -- {@link Zend_Media_Iso14496_Box_Mfra Movie Fragment Random + * Access Box} + *
      + *
    • tfra -- {@link Zend_Media_Iso14496_Box_Tfra Track Fragment Random + * Access Box} + *
    • mfro -- {@link Zend_Media_Iso14496_Box_Mfro Movie Fragment + * Random Access Offset Box} + *
    + *
  • mdat -- {@link Zend_Media_Iso14496_Box_Mdat Media Data Box} + *
  • free -- {@link Zend_Media_Iso14496_Box_Free Free Space Box} + *
  • skip -- {@link Zend_Media_Iso14496_Box_Skip Free Space Box} + *
      + *
    • udta -- {@link Zend_Media_Iso14496_Box_Udta User Data Box} + *
        + *
      • cprt -- {@link Zend_Media_Iso14496_Box_Cprt Copyright Box} + *
      + *
    + *
  • meta -- {@link Zend_Media_Iso14496_Box_Meta The Meta Box} + *
      + *
    • hdlr -- {@link Zend_Media_Iso14496_Box_Hdlr Handler Reference + * Box}; declares the metadata type + *
    • dinf -- {@link Zend_Media_Iso14496_Box_Dinf Data Information + * Box} + *
        + *
      • dref -- {@link Zend_Media_Iso14496_Box_Dref Data Reference + * Box}; declares source(s) of metadata items + *
      + *
    • ipmc -- {@link Zend_Media_Iso14496_Box_Ipmc IPMP Control Box} + *
    • iloc -- {@link Zend_Media_Iso14496_Box_Iloc Item Location Box} + *
    • ipro -- {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} + *
        + *
      • sinf -- {@link Zend_Media_Iso14496_Box_Sinf Protection Scheme + * Information Box} + *
          + *
        • frma -- {@link Zend_Media_Iso14496_Box_Frma Original Format + * Box} + *
        • imif -- {@link Zend_Media_Iso14496_Box_Imif IPMP Information + * Box} + *
        • schm -- {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box} + *
        • schi -- {@link Zend_Media_Iso14496_Box_Schi Scheme Information + * Box} + *
        + *
      + *
    • iinf -- {@link Zend_Media_Iso14496_Box_Iinf Item Information + * Box} + *
        + *
      • infe -- {@link Zend_Media_Iso14496_Box_Infe Item Information Entry + * Box} + *
      + *
    • xml -- {@link Zend_Media_Iso14496_Box_Xml XML Box} + *
    • bxml -- {@link Zend_Media_Iso14496_Box_Bxml Binary XML Box} + *
    • pitm -- {@link Zend_Media_Iso14496_Box_Pitm Primary Item Reference + * Box} + *
    + * + * + * There are two non-standard extensions to the ISO 14496 standard that add the + * ability to include file meta information. Both the boxes reside under + * moov.udta.meta. + * + *
      + *
    • moov -- {@link Zend_Media_Iso14496_Box_Moov Movie Box}; + * container for all the metadata + *
    • udta -- {@link Zend_Media_Iso14496_Box_Udta User Data Box} + *
    • meta -- {@link Zend_Media_Iso14496_Box_Meta The Meta Box} + *
        + *
      • ilst -- {@link Zend_Media_Iso14496_Box_Ilst The iTunes/iPod Tag + * Container Box} + *
      • id32 -- {@link Zend_Media_Iso14496_Box_Id32 The ID3v2 Box} + *
      + *
    + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iso14496.php 260 2012-03-05 19:06:21Z svollbehr $ + */ +final class Zend_Media_Iso14496 extends Zend_Media_Iso14496_Box +{ + /** @var string */ + private $_filename; + + /** @var boolean */ + private $_autoClose = false; + + /** + * Constructs the Zend_Media_Iso14496 class with given file and options. + * + * The following options are currently recognized: + * o base -- Indicates that only boxes with the given base path are parsed + * from the ISO base media file. Parsing all boxes can possibly have a + * significant impact on running time. Base path is a list of nested + * boxes separated by a dot. The use of base option implies readonly + * option. + * o readonly -- Indicates that the file is read from a temporary location + * or another source it cannot be written back to. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if (isset($options['base'])) { + $options['readonly'] = true; + } + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + try { + $this->_reader = new Zend_Io_FileReader($filename); + $this->_autoClose = true; + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception($e->getMessage()); + } + if (is_string($filename) && !isset($options['readonly'])) { + $this->_filename = $filename; + } + } + $this->setOptions($options); + $this->setOffset(0); + $this->setSize($this->_reader->getSize()); + $this->setType('file'); + $this->setContainer(true); + $this->constructBoxes(); + } + + /** + * Closes down the reader. + */ + public function __destruct() + { + parent::__destruct(); + if ($this->_autoClose === true && $this->_reader !== null) { + $this->_reader->close(); + } + } + + /** + * Writes the changes back to given media file. + * + * The write operation commits only changes made to the Movie Box. It + * further changes the order of the Movie Box and Media Data Box in a way + * compatible for progressive download from a web page. + * + * All box offsets must be assumed to be invalid after the write operation. + * + * @param string $filename The optional path to the file, use null to save + * to the same file. + */ + public function write($filename) + { + if ($filename === null && ($filename = $this->_filename) === null) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception + ('No file given to write to'); + } else if ($filename !== null && $this->_filename !== null && + realpath($filename) != realpath($this->_filename) && + !copy($this->_filename, $filename)) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception + ('Unable to copy source to destination: ' . + realpath($this->_filename) . '->' . realpath($filename)); + } + + if (($fd = fopen + ($filename, file_exists($filename) ? 'r+b' : 'wb')) === false) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception + ('Unable to open file for writing: ' . $filename); + } + + /* Calculate file size */ + fseek($fd, 0, SEEK_END); + $oldFileSize = ftell($fd); + $oldMoovSize = $this->moov->getSize(); + $this->moov->udta->meta->free->setSize(8); + $this->moov->udta->meta->hdlr->setHandlerType('mdir'); + $newFileSize = $oldFileSize - $oldMoovSize + $this->moov->getHeapSize(); + + /* Calculate free space size */ + if ($oldFileSize < $newFileSize || + $this->mdat->getOffset() < $this->moov->getOffset()) { + // Add constant 4096 bytes for free space to be used later + $this->moov->udta->meta->free->setSize(8 /* header */ + 4096); + ftruncate($fd, $newFileSize += 4096); + } else { + // Adjust free space to fill up the rest of the space + $this->moov->udta->meta->free->setSize + (8 + $oldFileSize - $newFileSize); + $newFileSize = $oldFileSize; + } + + /* Calculate positions */ + if ($this->mdat->getOffset() < $this->moov->getOffset()) { + $start = $this->mdat->getOffset(); + $until = $this->moov->getOffset(); + $where = $newFileSize; + $delta = $this->moov->getHeapSize(); + } else { + $start = $this->moov->getOffset(); + $until = $oldFileSize; + $where = $newFileSize; + $delta = $newFileSize - $oldFileSize; + } + + /* Move data to the end of the file */ + if ($newFileSize != $oldFileSize) { + for ($i = 1, $cur = $until; $cur > $start; $cur -= 1024, $i++) { + fseek + ($fd, $until - (($i * 1024) + + ($excess = $cur - 1024 > $start ? + 0 : $cur - $start - 1024))); + $buffer = fread($fd, 1024); + fseek($fd, $where - (($i * 1024) + $excess)); + fwrite($fd, $buffer, 1024); + } + } + + + /* Update stco/co64 to correspond the data move */ + foreach ($this->moov->getBoxesByIdentifier('trak') as $trak) { + $chunkOffsetBox = + (isset($trak->mdia->minf->stbl->stco) ? + $trak->mdia->minf->stbl->stco : + $trak->mdia->minf->stbl->co64); + $chunkOffsetTable = $chunkOffsetBox->getChunkOffsetTable(); + $chunkOffsetTableCount = count($chunkOffsetTable); + for ($i = 1; $i <= $chunkOffsetTableCount; $i++) { + $chunkOffsetTable[$i] += $delta; + } + $chunkOffsetBox->setChunkOffsetTable($chunkOffsetTable); + } + + /* Write moov box */ + fseek($fd, $start); + $this->moov->write(new Zend_Io_Writer($fd)); + fclose($fd); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box.php b/app/libs/vendor/Zend/Media/Iso14496/Box.php index c34f16f4..7794249c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box.php @@ -1,667 +1,667 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Box.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Iso14496_Box -{ - /** - * The reader object. - * - * @var Reader - */ - protected $_reader; - - /** @var Array */ - private $_options; - - /** @var integer */ - private $_offset = false; - - /** @var integer */ - private $_size = false; - - /** @var string */ - private $_type; - - /** @var Zend_Media_Iso14496_Box */ - private $_parent = null; - - /** @var boolean */ - private $_container = false; - - /** @var Array */ - private $_boxes = array(); - - /** @var Array */ - private static $_path = array(); - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - if (($this->_reader = $reader) === null) { - $this->_type = strtolower(substr(get_class($this), -4)); - } else { - $this->_offset = $this->_reader->getOffset(); - $this->_size = $this->_reader->readUInt32BE(); - $this->_type = $this->_reader->read(4); - - if ($this->_size == 1) { - $this->_size = $this->_reader->readInt64BE(); - } - if ($this->_size == 0) { - $this->_size = $this->_reader->getSize() - $this->_offset; - } - if ($this->_type == 'uuid') { - $this->_type = $this->_reader->readGUID(); - } - } - $this->_options = &$options; - } - - /** - * Releases any references to contained boxes and the parent. - */ - public function __destruct() - { - unset($this->_boxes); - unset($this->_parent); - } - - /** - * Returns the options array. - * - * @return Array - */ - public final function &getOptions() - { - return $this->_options; - } - - /** - * Returns the given option value, or the default value if the option is not - * defined. - * - * @param string $option The name of the option. - * @param mixed $defaultValue The default value to be returned. - */ - public final function getOption($option, $defaultValue = null) - { - if (isset($this->_options[$option])) { - return $this->_options[$option]; - } - return $defaultValue; - } - - /** - * Sets the options array. See {@link Zend_Media_Id3v2} class for available - * options. - * - * @param Array $options The options array. - */ - public final function setOptions(&$options) - { - $this->_options = &$options; - } - - /** - * Sets the given option the given value. - * - * @param string $option The name of the option. - * @param mixed $value The value to set for the option. - */ - public final function setOption($option, $value) - { - $this->_options[$option] = $value; - } - - /** - * Clears the given option value. - * - * @param string $option The name of the option. - */ - public final function clearOption($option) - { - unset($this->_options[$option]); - } - - /** - * Returns the file offset to box start, or false if the box was - * created on heap. - * - * @return integer - */ - public final function getOffset() - { - return $this->_offset; - } - - /** - * Sets the file offset where the box starts. - * - * @param integer $offset The file offset to box start. - */ - public final function setOffset($offset) - { - $this->_offset = $offset; - } - - /** - * Returns the box size in bytes read from the file, including the size and - * type header, fields, and all contained boxes, or false if the - * box was created on heap. - * - * @return integer - */ - public final function getSize() - { - return $this->_size; - } - - /** - * Sets the box size. The size must include the size and type header, - * fields, and all contained boxes. - * - * The method will propagate size change to box parents. - * - * @param integer $size The box size. - */ - protected final function setSize($size) - { - if ($this->_parent !== null) { - $this->_parent->setSize - (($this->_parent->getSize() > 0 ? - $this->_parent->getSize() : 0) + - $size - ($this->_size > 0 ? $this->_size : 0)); - } - $this->_size = $size; - } - - /** - * Returns the box type. - * - * @return string - */ - public final function getType() - { - return $this->_type; - } - - /** - * Sets the box type. - * - * @param string $type The box type. - */ - public final function setType($type) - { - $this->_type = $type; - } - - /** - * Returns the parent box containing this box. - * - * @return Zend_Media_Iso14496_Box - */ - public final function getParent() - { - return $this->_parent; - } - - /** - * Sets the parent containing box. - * - * @param Zend_Media_Iso14496_Box $parent The parent box. - */ - public function setParent(&$parent) - { - $this->_parent = $parent; - } - - /** - * Returns a boolean value corresponding to whether the box is a container. - * - * @return boolean - */ - public final function isContainer() - { - return $this->_container; - } - - /** - * Returns a boolean value corresponding to whether the box is a container. - * - * @return boolean - */ - public final function getContainer() - { - return $this->_container; - } - - /** - * Sets whether the box is a container. - * - * @param boolean $container Whether the box is a container. - */ - protected final function setContainer($container) - { - $this->_container = $container; - } - - /** - * Reads and constructs the boxes found within this box. - * - * @todo Does not parse iTunes internal ---- boxes. - */ - protected final function constructBoxes - ($defaultclassname = 'Zend_Media_Iso14496_Box') - { - $base = $this->getOption('base', ''); - if ($this->getType() != 'file') { - self::$_path[] = $this->getType(); - } - $path = implode(self::$_path, '.'); - - while (true) { - $offset = $this->_reader->getOffset(); - if ($offset >= $this->_offset + $this->_size) { - break; - } - $size = $this->_reader->readUInt32BE(); - $type = rtrim($this->_reader->read(4), ' '); - if ($size == 1) { - $size = $this->_reader->readInt64BE(); - } - if ($size == 0) { - $size = $this->_reader->getSize() - $offset; - } - - if (preg_match("/^\xa9?[a-z0-9]{3,4}$/i", $type) && - substr($base, 0, min(strlen($base), strlen - ($tmp = $path . ($path ? '.' : '') . $type))) == - substr($tmp, 0, min(strlen($base), strlen($tmp)))) - { - $this->_reader->setOffset($offset); - if (@fopen($filename = 'Zend/Media/Iso14496/Box/' . - ucfirst($type) . '.php', 'r', true) !== false) { - require_once($filename); - } - if (class_exists - ($classname = 'Zend_Media_Iso14496_Box_' . - ucfirst($type))) { - $box = new $classname($this->_reader, $this->_options); - } else { - $box = - new $defaultclassname($this->_reader, $this->_options); - } - $box->setParent($this); - if (!isset($this->_boxes[$box->getType()])) { - $this->_boxes[$box->getType()] = array(); - } - $this->_boxes[$box->getType()][] = $box; - } - $this->_reader->setOffset($offset + $size); - } - - array_pop(self::$_path); - } - - /** - * Checks whether the box given as an argument is present in the file. Returns - * true if one or more boxes are present, false - * otherwise. - * - * @param string $identifier The box identifier. - * @return boolean - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function hasBox($identifier) - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Box not a container'); - } - return isset($this->_boxes[$identifier]); - } - - /** - * Returns all the boxes the file contains as an associate array. The box - * identifiers work as keys having an array of boxes as associated value. - * - * @return Array - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function getBoxes() - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Box not a container'); - } - return $this->_boxes; - } - - /** - * Returns an array of boxes matching the given identifier or an empty array - * if no boxes matched the identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches - * any single character. - * - * Please note that one may also use the shorthand $obj->identifier to - * access the first box with the identifier given. Wildcards cannot be used - * with the shorthand and they will not work with user defined uuid types. - * - * @param string $identifier The box identifier. - * @return Array - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function getBoxesByIdentifier($identifier) - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Box not a container'); - } - $matches = array(); - $searchPattern = "/^" . - str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; - foreach ($this->_boxes as $identifier => $boxes) { - if (preg_match($searchPattern, $identifier)) { - foreach ($boxes as $box) { - $matches[] = $box; - } - } - } - return $matches; - } - - /** - * Removes any boxes matching the given box identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk - * matches against zero or more characters, and the question mark matches any - * single character. - * - * One may also use the shorthand unset($obj->identifier) to achieve the same - * result. Wildcards cannot be used with the shorthand method. - * - * @param string $identifier The box identifier. - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function removeBoxesByIdentifier($identifier) - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception("Box not a container"); - } - $searchPattern = "/^" . - str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; - foreach ($this->_objects as $identifier => $objects) { - if (preg_match($searchPattern, $identifier)) { - unset($this->_objects[$identifier]); - } - } - } - - /** - * Adds a new box into the current box and returns it. - * - * @param Zend_Media_Iso14496_Box $box The box to add - * @return Zend_Media_Iso14496_Box - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function addBox(&$box) - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Box not a container'); - } - $box->setParent($this); - $box->setOptions($this->_options); - if (!$this->hasBox($box->getType())) { - $this->_boxes[$box->getType()] = array(); - } - return $this->_boxes[$box->getType()][] = $box; - } - - /** - * Removes the given box. - * - * @param Zend_Media_Iso14496_Box $box The box to remove - * @throws Zend_Media_Iso14496_Exception if called on a non-container box - */ - public final function removeBox($box) - { - if (!$this->isContainer()) { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Box not a container'); - } - if ($this->hasBox($box->getType())) { - foreach ($this->_boxes[$box->getType()] as $key => $value) { - if ($box === $value) { - unset($this->_boxes[$box->getType()][$key]); - } - } - } - } - - /** - * Returns the number of boxes this box contains. - * - * @return integer - */ - public final function getBoxCount() - { - if (!$this->isContainer()) { - return 0; - } - return count($this->_boxes); - } - - /** - * Magic function so that $obj->value will work. If called on a container box, - * the method will first attempt to return the first contained box that - * matches the identifier, and if not found, invoke a getter method. - * - * If there are no boxes or getter methods with given name, the method - * attempts to create a frame with given identifier. - * - * If none of these work, an exception is thrown. - * - * @param string $name The box or field name. - * @return mixed - */ - public function __get($name) - { - if ($this->isContainer() && - isset($this->_boxes[str_pad($name, 4, ' ')])) { - return $this->_boxes[str_pad($name, 4, ' ')][0]; - } - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - if (@fopen($filename = 'Zend/Media/Iso14496/Box/' . - ucfirst($name) . '.php', 'r', true) !== false) { - require_once($filename); - } - if (class_exists - ($classname = 'Zend_Media_Iso14496_Box_' . ucfirst($name))) { - return $this->addBox(new $classname()); - } - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Unknown box/field: ' . $name); - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func(array($this, 'set' . ucfirst($name)), $value); - } else { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that isset($obj->value) will work. This method checks - * whether the box is a container and contains a box that matches the - * identifier. - * - * @param string $name The box name. - * @return boolean - */ - public function __isset($name) - { - return ($this->isContainer() && isset($this->_boxes[$name])); - } - - /** - * Magic function so that unset($obj->value) will work. This method removes - * all the boxes from this container that match the identifier. - * - * @param string $name The box name. - */ - public function __unset($name) - { - if ($this->isContainer()) { - unset($this->_boxes[$name]); - } - } - - /** - * Returns the box heap size in bytes, including the size and - * type header, fields, and all contained boxes. The box size is updated to - * reflect that of the heap size upon write. Subclasses should overwrite - * this method and call the parent method to get the calculated header and - * subbox sizes and then add their own bytes to that. - * - * @return integer - */ - public function getHeapSize() - { - $size = 8; - if ($this->isContainer()) { - foreach ($this->getBoxes() as $name => $boxes) { - foreach ($boxes as $box) { - $size += $box->getHeapSize(); - } - } - } - if ($size > 0xffffffff) { - $size += 8; - } - if (strlen($this->_type) > 4) { - $size += 16; - } - return $size; - } - - /** - * Writes the box header. Subclasses should overwrite this method and call - * the parent method first and then write the box related data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - if (get_class($this) == "Zend_Media_Iso14496_Box") { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception - ('Unknown box \'' . $this->getType() . '\' cannot be written.'); - } - - $this->_size = $this->getHeapSize(); - if ($this->_size > 0xffffffff) { - $writer->writeUInt32BE(1); - } else { - $writer->writeUInt32BE($this->_size); - } - if (strlen($this->_type) > 4) { - $writer->write('uuid'); - } else { - $writer->write($this->_type); - } - if ($this->_size > 0xffffffff) { - $writer->writeInt64BE($this->_size); - } - if (strlen($this->_type) > 4) { - $writer->writeGuid($this->_type); - } - } - - /** - * Writes the frame data with the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - public function write($writer) - { - if (get_class($this) == "Zend_Media_Iso14496_Box") { - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception - ('Unknown box \'' . $this->getType() . '\' cannot be written.'); - } - - $this->_writeData($writer); - if ($this->isContainer()) { - foreach ($this->getBoxes() as $name => $boxes) { - foreach ($boxes as $box) { - $box->write($writer); - } - } - } - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Box.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Iso14496_Box +{ + /** + * The reader object. + * + * @var Reader + */ + protected $_reader; + + /** @var Array */ + private $_options; + + /** @var integer */ + private $_offset = false; + + /** @var integer */ + private $_size = false; + + /** @var string */ + private $_type; + + /** @var Zend_Media_Iso14496_Box */ + private $_parent = null; + + /** @var boolean */ + private $_container = false; + + /** @var Array */ + private $_boxes = array(); + + /** @var Array */ + private static $_path = array(); + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + if (($this->_reader = $reader) === null) { + $this->_type = strtolower(substr(get_class($this), -4)); + } else { + $this->_offset = $this->_reader->getOffset(); + $this->_size = $this->_reader->readUInt32BE(); + $this->_type = $this->_reader->read(4); + + if ($this->_size == 1) { + $this->_size = $this->_reader->readInt64BE(); + } + if ($this->_size == 0) { + $this->_size = $this->_reader->getSize() - $this->_offset; + } + if ($this->_type == 'uuid') { + $this->_type = $this->_reader->readGUID(); + } + } + $this->_options = &$options; + } + + /** + * Releases any references to contained boxes and the parent. + */ + public function __destruct() + { + unset($this->_boxes); + unset($this->_parent); + } + + /** + * Returns the options array. + * + * @return Array + */ + public final function &getOptions() + { + return $this->_options; + } + + /** + * Returns the given option value, or the default value if the option is not + * defined. + * + * @param string $option The name of the option. + * @param mixed $defaultValue The default value to be returned. + */ + public final function getOption($option, $defaultValue = null) + { + if (isset($this->_options[$option])) { + return $this->_options[$option]; + } + return $defaultValue; + } + + /** + * Sets the options array. See {@link Zend_Media_Id3v2} class for available + * options. + * + * @param Array $options The options array. + */ + public final function setOptions(&$options) + { + $this->_options = &$options; + } + + /** + * Sets the given option the given value. + * + * @param string $option The name of the option. + * @param mixed $value The value to set for the option. + */ + public final function setOption($option, $value) + { + $this->_options[$option] = $value; + } + + /** + * Clears the given option value. + * + * @param string $option The name of the option. + */ + public final function clearOption($option) + { + unset($this->_options[$option]); + } + + /** + * Returns the file offset to box start, or false if the box was + * created on heap. + * + * @return integer + */ + public final function getOffset() + { + return $this->_offset; + } + + /** + * Sets the file offset where the box starts. + * + * @param integer $offset The file offset to box start. + */ + public final function setOffset($offset) + { + $this->_offset = $offset; + } + + /** + * Returns the box size in bytes read from the file, including the size and + * type header, fields, and all contained boxes, or false if the + * box was created on heap. + * + * @return integer + */ + public final function getSize() + { + return $this->_size; + } + + /** + * Sets the box size. The size must include the size and type header, + * fields, and all contained boxes. + * + * The method will propagate size change to box parents. + * + * @param integer $size The box size. + */ + protected final function setSize($size) + { + if ($this->_parent !== null) { + $this->_parent->setSize + (($this->_parent->getSize() > 0 ? + $this->_parent->getSize() : 0) + + $size - ($this->_size > 0 ? $this->_size : 0)); + } + $this->_size = $size; + } + + /** + * Returns the box type. + * + * @return string + */ + public final function getType() + { + return $this->_type; + } + + /** + * Sets the box type. + * + * @param string $type The box type. + */ + public final function setType($type) + { + $this->_type = $type; + } + + /** + * Returns the parent box containing this box. + * + * @return Zend_Media_Iso14496_Box + */ + public final function getParent() + { + return $this->_parent; + } + + /** + * Sets the parent containing box. + * + * @param Zend_Media_Iso14496_Box $parent The parent box. + */ + public function setParent(&$parent) + { + $this->_parent = $parent; + } + + /** + * Returns a boolean value corresponding to whether the box is a container. + * + * @return boolean + */ + public final function isContainer() + { + return $this->_container; + } + + /** + * Returns a boolean value corresponding to whether the box is a container. + * + * @return boolean + */ + public final function getContainer() + { + return $this->_container; + } + + /** + * Sets whether the box is a container. + * + * @param boolean $container Whether the box is a container. + */ + protected final function setContainer($container) + { + $this->_container = $container; + } + + /** + * Reads and constructs the boxes found within this box. + * + * @todo Does not parse iTunes internal ---- boxes. + */ + protected final function constructBoxes + ($defaultclassname = 'Zend_Media_Iso14496_Box') + { + $base = $this->getOption('base', ''); + if ($this->getType() != 'file') { + self::$_path[] = $this->getType(); + } + $path = implode(self::$_path, '.'); + + while (true) { + $offset = $this->_reader->getOffset(); + if ($offset >= $this->_offset + $this->_size) { + break; + } + $size = $this->_reader->readUInt32BE(); + $type = rtrim($this->_reader->read(4), ' '); + if ($size == 1) { + $size = $this->_reader->readInt64BE(); + } + if ($size == 0) { + $size = $this->_reader->getSize() - $offset; + } + + if (preg_match("/^\xa9?[a-z0-9]{3,4}$/i", $type) && + substr($base, 0, min(strlen($base), strlen + ($tmp = $path . ($path ? '.' : '') . $type))) == + substr($tmp, 0, min(strlen($base), strlen($tmp)))) + { + $this->_reader->setOffset($offset); + if (@fopen($filename = 'Zend/Media/Iso14496/Box/' . + ucfirst($type) . '.php', 'r', true) !== false) { + require_once($filename); + } + if (class_exists + ($classname = 'Zend_Media_Iso14496_Box_' . + ucfirst($type))) { + $box = new $classname($this->_reader, $this->_options); + } else { + $box = + new $defaultclassname($this->_reader, $this->_options); + } + $box->setParent($this); + if (!isset($this->_boxes[$box->getType()])) { + $this->_boxes[$box->getType()] = array(); + } + $this->_boxes[$box->getType()][] = $box; + } + $this->_reader->setOffset($offset + $size); + } + + array_pop(self::$_path); + } + + /** + * Checks whether the box given as an argument is present in the file. Returns + * true if one or more boxes are present, false + * otherwise. + * + * @param string $identifier The box identifier. + * @return boolean + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function hasBox($identifier) + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Box not a container'); + } + return isset($this->_boxes[$identifier]); + } + + /** + * Returns all the boxes the file contains as an associate array. The box + * identifiers work as keys having an array of boxes as associated value. + * + * @return Array + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function getBoxes() + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Box not a container'); + } + return $this->_boxes; + } + + /** + * Returns an array of boxes matching the given identifier or an empty array + * if no boxes matched the identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches + * any single character. + * + * Please note that one may also use the shorthand $obj->identifier to + * access the first box with the identifier given. Wildcards cannot be used + * with the shorthand and they will not work with user defined uuid types. + * + * @param string $identifier The box identifier. + * @return Array + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function getBoxesByIdentifier($identifier) + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Box not a container'); + } + $matches = array(); + $searchPattern = "/^" . + str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; + foreach ($this->_boxes as $identifier => $boxes) { + if (preg_match($searchPattern, $identifier)) { + foreach ($boxes as $box) { + $matches[] = $box; + } + } + } + return $matches; + } + + /** + * Removes any boxes matching the given box identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk + * matches against zero or more characters, and the question mark matches any + * single character. + * + * One may also use the shorthand unset($obj->identifier) to achieve the same + * result. Wildcards cannot be used with the shorthand method. + * + * @param string $identifier The box identifier. + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function removeBoxesByIdentifier($identifier) + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception("Box not a container"); + } + $searchPattern = "/^" . + str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; + foreach ($this->_objects as $identifier => $objects) { + if (preg_match($searchPattern, $identifier)) { + unset($this->_objects[$identifier]); + } + } + } + + /** + * Adds a new box into the current box and returns it. + * + * @param Zend_Media_Iso14496_Box $box The box to add + * @return Zend_Media_Iso14496_Box + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function addBox(&$box) + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Box not a container'); + } + $box->setParent($this); + $box->setOptions($this->_options); + if (!$this->hasBox($box->getType())) { + $this->_boxes[$box->getType()] = array(); + } + return $this->_boxes[$box->getType()][] = $box; + } + + /** + * Removes the given box. + * + * @param Zend_Media_Iso14496_Box $box The box to remove + * @throws Zend_Media_Iso14496_Exception if called on a non-container box + */ + public final function removeBox($box) + { + if (!$this->isContainer()) { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Box not a container'); + } + if ($this->hasBox($box->getType())) { + foreach ($this->_boxes[$box->getType()] as $key => $value) { + if ($box === $value) { + unset($this->_boxes[$box->getType()][$key]); + } + } + } + } + + /** + * Returns the number of boxes this box contains. + * + * @return integer + */ + public final function getBoxCount() + { + if (!$this->isContainer()) { + return 0; + } + return count($this->_boxes); + } + + /** + * Magic function so that $obj->value will work. If called on a container box, + * the method will first attempt to return the first contained box that + * matches the identifier, and if not found, invoke a getter method. + * + * If there are no boxes or getter methods with given name, the method + * attempts to create a frame with given identifier. + * + * If none of these work, an exception is thrown. + * + * @param string $name The box or field name. + * @return mixed + */ + public function __get($name) + { + if ($this->isContainer() && + isset($this->_boxes[str_pad($name, 4, ' ')])) { + return $this->_boxes[str_pad($name, 4, ' ')][0]; + } + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + if (@fopen($filename = 'Zend/Media/Iso14496/Box/' . + ucfirst($name) . '.php', 'r', true) !== false) { + require_once($filename); + } + if (class_exists + ($classname = 'Zend_Media_Iso14496_Box_' . ucfirst($name))) { + return $this->addBox(new $classname()); + } + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Unknown box/field: ' . $name); + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func(array($this, 'set' . ucfirst($name)), $value); + } else { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that isset($obj->value) will work. This method checks + * whether the box is a container and contains a box that matches the + * identifier. + * + * @param string $name The box name. + * @return boolean + */ + public function __isset($name) + { + return ($this->isContainer() && isset($this->_boxes[$name])); + } + + /** + * Magic function so that unset($obj->value) will work. This method removes + * all the boxes from this container that match the identifier. + * + * @param string $name The box name. + */ + public function __unset($name) + { + if ($this->isContainer()) { + unset($this->_boxes[$name]); + } + } + + /** + * Returns the box heap size in bytes, including the size and + * type header, fields, and all contained boxes. The box size is updated to + * reflect that of the heap size upon write. Subclasses should overwrite + * this method and call the parent method to get the calculated header and + * subbox sizes and then add their own bytes to that. + * + * @return integer + */ + public function getHeapSize() + { + $size = 8; + if ($this->isContainer()) { + foreach ($this->getBoxes() as $name => $boxes) { + foreach ($boxes as $box) { + $size += $box->getHeapSize(); + } + } + } + if ($size > 0xffffffff) { + $size += 8; + } + if (strlen($this->_type) > 4) { + $size += 16; + } + return $size; + } + + /** + * Writes the box header. Subclasses should overwrite this method and call + * the parent method first and then write the box related data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + if (get_class($this) == "Zend_Media_Iso14496_Box") { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception + ('Unknown box \'' . $this->getType() . '\' cannot be written.'); + } + + $this->_size = $this->getHeapSize(); + if ($this->_size > 0xffffffff) { + $writer->writeUInt32BE(1); + } else { + $writer->writeUInt32BE($this->_size); + } + if (strlen($this->_type) > 4) { + $writer->write('uuid'); + } else { + $writer->write($this->_type); + } + if ($this->_size > 0xffffffff) { + $writer->writeInt64BE($this->_size); + } + if (strlen($this->_type) > 4) { + $writer->writeGuid($this->_type); + } + } + + /** + * Writes the frame data with the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + public function write($writer) + { + if (get_class($this) == "Zend_Media_Iso14496_Box") { + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception + ('Unknown box \'' . $this->getType() . '\' cannot be written.'); + } + + $this->_writeData($writer); + if ($this->isContainer()) { + foreach ($this->getBoxes() as $name => $boxes) { + foreach ($boxes as $box) { + $box->write($writer); + } + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Bxml.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Bxml.php index 6c00ddf2..e99bf0b1 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Bxml.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Bxml.php @@ -1,118 +1,118 @@ -XML Box forms may be used. - * The Binary XML Box may only be used when there is a single well-defined - * binarization of the XML for that defined format as identified by the handler. - * - * Within an XML box the data is in UTF-8 format unless the data starts with a - * byte-order-mark (BOM), which indicates that the data is in UTF-16 format. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Bxml.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Bxml extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_xml; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_xml = $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - } - - /** - * Returns the XML data. - * - * @return string - */ - public function getXml() - { - return $this->_xml; - } - - /** - * Sets the binary data. - * - * @param string $xml The XML data. - */ - public function setXml($xml) - { - $this->_xml = $xml; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + strlen($this->_xml); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_xml); - } -} +XML Box forms may be used. + * The Binary XML Box may only be used when there is a single well-defined + * binarization of the XML for that defined format as identified by the handler. + * + * Within an XML box the data is in UTF-8 format unless the data starts with a + * byte-order-mark (BOM), which indicates that the data is in UTF-16 format. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Bxml.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Bxml extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_xml; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_xml = $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + } + + /** + * Returns the XML data. + * + * @return string + */ + public function getXml() + { + return $this->_xml; + } + + /** + * Sets the binary data. + * + * @param string $xml The XML data. + */ + public function setXml($xml) + { + $this->_xml = $xml; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + strlen($this->_xml); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_xml); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Cdsc.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Cdsc.php index e1725e84..c468e030 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Cdsc.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Cdsc.php @@ -1,119 +1,119 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Cdsc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Cdsc extends Zend_Media_Iso14496_Box -{ - /** @var Array */ - private $_trackId = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - while ($this->_reader->getOffset <= $this->getSize()) { - $this->_trackId[] = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns an array of integer references from the containing track to - * another track in the presentation. Track IDs are never re-used and cannot - * be equal to zero. - * - * @return integer - */ - public function getTrackId() - { - return $this->_trackId; - } - - /** - * Sets an array of integer references from the containing track to - * another track in the presentation. Track IDs are never re-used and cannot - * be equal to zero. - * - * @param Array $trackId The array of values. - */ - public function setTrackId($trackId) - { - $this->_trackId = $trackId; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + count($this->_trackId) * 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - for ($i = 0; $i < count($this->_trackId); $i++) { - $writer->writeUInt32BE($this->_trackId[$i]); - } - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Cdsc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Cdsc extends Zend_Media_Iso14496_Box +{ + /** @var Array */ + private $_trackId = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + while ($this->_reader->getOffset <= $this->getSize()) { + $this->_trackId[] = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns an array of integer references from the containing track to + * another track in the presentation. Track IDs are never re-used and cannot + * be equal to zero. + * + * @return integer + */ + public function getTrackId() + { + return $this->_trackId; + } + + /** + * Sets an array of integer references from the containing track to + * another track in the presentation. Track IDs are never re-used and cannot + * be equal to zero. + * + * @param Array $trackId The array of values. + */ + public function setTrackId($trackId) + { + $this->_trackId = $trackId; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + count($this->_trackId) * 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + for ($i = 0; $i < count($this->_trackId); $i++) { + $writer->writeUInt32BE($this->_trackId[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Chpl.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Chpl.php index 620153a0..820ad4d2 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Chpl.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Chpl.php @@ -1,109 +1,109 @@ -Nero Chapter List Box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Chpl.php 210 2010-12-28 16:46:58Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Chpl extends Zend_Media_Iso14496_FullBox -{ - private $_data; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_data = $reader->read($this->getSize() - 12); - } - - /** - * Returns the raw binary data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the raw binary data. - * - * @param string $data The data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + $this->getSize() - 12; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_data); - } -} +Nero Chapter List Box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Chpl.php 210 2010-12-28 16:46:58Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Chpl extends Zend_Media_Iso14496_FullBox +{ + private $_data; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_data = $reader->read($this->getSize() - 12); + } + + /** + * Returns the raw binary data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the raw binary data. + * + * @param string $data The data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + $this->getSize() - 12; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Co64.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Co64.php index 7979a989..41669072 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Co64.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Co64.php @@ -1,133 +1,133 @@ -Chunk Offset Box table gives the index of each chunk into the - * containing file. There are two variants, permitting the use of 32-bit or - * 64-bit offsets. The latter is useful when managing very large presentations. - * At most one of these variants will occur in any single instance of a sample - * table. - * - * Offsets are file offsets, not the offset into any box within the file (e.g. - * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}). This permits referring - * to media data in files without any box structure. It does also mean that care - * must be taken when constructing a self-contained ISO file with its metadata - * ({@link Zend_Media_Iso14496_Box_Moov Movie Box}) at the front, as the size of - * the {@link Zend_Media_Iso14496_Box_Moov Movie Box} will affect the chunk - * offsets to the media data. - * - * This box variant contains 64-bit offsets. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Co64.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Co64 extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_chunkOffsetTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_chunkOffsetTable[$i] = $this->_reader->readInt64BE(); - } - } - - /** - * Returns an array of values. Each entry has the entry number as its index - * and a 64 bit integer that gives the offset of the start of a chunk into - * its containing media file as its value. - * - * @return Array - */ - public function getChunkOffsetTable() - { - return $this->_chunkOffsetTable; - } - - /** - * Sets an array of chunk offsets. Each entry must have the entry number as - * its index and a 64 bit integer that gives the offset of the start of a - * chunk into its containing media file as its value. - * - * @param Array $chunkOffsetTable The chunk offset array. - */ - public function setChunkOffsetTable($chunkOffsetTable) - { - $this->_chunkOffsetTable = $chunkOffsetTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + count($this->_chunkOffsetTable) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - $writer->writeUInt32BE($entryCount = count($this->_chunkOffsetTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeInt64BE($this->_chunkOffsetTable[$i]); - } - } -} +Chunk Offset Box table gives the index of each chunk into the + * containing file. There are two variants, permitting the use of 32-bit or + * 64-bit offsets. The latter is useful when managing very large presentations. + * At most one of these variants will occur in any single instance of a sample + * table. + * + * Offsets are file offsets, not the offset into any box within the file (e.g. + * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}). This permits referring + * to media data in files without any box structure. It does also mean that care + * must be taken when constructing a self-contained ISO file with its metadata + * ({@link Zend_Media_Iso14496_Box_Moov Movie Box}) at the front, as the size of + * the {@link Zend_Media_Iso14496_Box_Moov Movie Box} will affect the chunk + * offsets to the media data. + * + * This box variant contains 64-bit offsets. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Co64.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Co64 extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_chunkOffsetTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_chunkOffsetTable[$i] = $this->_reader->readInt64BE(); + } + } + + /** + * Returns an array of values. Each entry has the entry number as its index + * and a 64 bit integer that gives the offset of the start of a chunk into + * its containing media file as its value. + * + * @return Array + */ + public function getChunkOffsetTable() + { + return $this->_chunkOffsetTable; + } + + /** + * Sets an array of chunk offsets. Each entry must have the entry number as + * its index and a 64 bit integer that gives the offset of the start of a + * chunk into its containing media file as its value. + * + * @param Array $chunkOffsetTable The chunk offset array. + */ + public function setChunkOffsetTable($chunkOffsetTable) + { + $this->_chunkOffsetTable = $chunkOffsetTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + count($this->_chunkOffsetTable) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + $writer->writeUInt32BE($entryCount = count($this->_chunkOffsetTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeInt64BE($this->_chunkOffsetTable[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Cprt.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Cprt.php index 85b18901..3d8b6b68 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Cprt.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Cprt.php @@ -1,150 +1,150 @@ -Copyright Box contains a copyright declaration which applies to - * the entire presentation, when contained within the - * {@link Zend_Media_Iso14496_Box_Moov Movie Box}, or, when contained in a - * track, to that entire track. There may be multiple copyright boxes using - * different language codes. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Cprt.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Cprt extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_language; - - /** @var string */ - private $_notice; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - * @todo Distinguish UTF-16? - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_language = chr - (((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + 0x60) . - chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); - $this->_notice = $this->_reader->readString8 - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - } - - /** - * Returns the three byte language code to describe the language of the - * notice, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO 639-2/T}. - * - * @return string - */ - public function getLanguage() - { - return $this->_language; - } - - /** - * Sets the three byte language code to describe the language of this - * media, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO 639-2/T}. - * - * @param string $language The language code. - */ - public function setLanguage($language) - { - $this->_language = $language; - } - - /** - * Returns the copyright notice. - * - * @return string - */ - public function getNotice() - { - return $this->_notice; - } - - /** - * Returns the copyright notice. - * - * @param string $notice The copyright notice. - */ - public function setNotice($notice) - { - $this->_notice = $notice; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 3 + strlen($this->_notice); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE((ord($this->_language[0]) - 0x60) << 10 | - (ord($this->_language[1])- 0x60) << 5 | - (ord($this->_language[2])- 0x60)) - ->writeString8($this->_notice, 1); - } -} +Copyright Box contains a copyright declaration which applies to + * the entire presentation, when contained within the + * {@link Zend_Media_Iso14496_Box_Moov Movie Box}, or, when contained in a + * track, to that entire track. There may be multiple copyright boxes using + * different language codes. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Cprt.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Cprt extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_language; + + /** @var string */ + private $_notice; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + * @todo Distinguish UTF-16? + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_language = chr + (((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + 0x60) . + chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); + $this->_notice = $this->_reader->readString8 + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + } + + /** + * Returns the three byte language code to describe the language of the + * notice, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO 639-2/T}. + * + * @return string + */ + public function getLanguage() + { + return $this->_language; + } + + /** + * Sets the three byte language code to describe the language of this + * media, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO 639-2/T}. + * + * @param string $language The language code. + */ + public function setLanguage($language) + { + $this->_language = $language; + } + + /** + * Returns the copyright notice. + * + * @return string + */ + public function getNotice() + { + return $this->_notice; + } + + /** + * Returns the copyright notice. + * + * @param string $notice The copyright notice. + */ + public function setNotice($notice) + { + $this->_notice = $notice; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 3 + strlen($this->_notice); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE((ord($this->_language[0]) - 0x60) << 10 | + (ord($this->_language[1])- 0x60) << 5 | + (ord($this->_language[2])- 0x60)) + ->writeString8($this->_notice, 1); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Ctts.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Ctts.php index c393b913..bb46565e 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Ctts.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Ctts.php @@ -1,139 +1,139 @@ -Composition Time to Sample Box provides the offset between - * decoding time and composition time. Since decoding time must be less than the - * composition time, the offsets are expressed as unsigned numbers such that - * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for - * sample n. - * - * The composition time to sample table is optional and must only be present if - * DT and CT differ for any samples. Hint tracks do not use this box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ctts.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Ctts extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_compositionOffsetTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_compositionOffsetTable[$i] = array - ('sampleCount' => $this->_reader->readUInt32BE(), - 'sampleOffset' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o sampleCount -- an integer that counts the number of consecutive - * samples that have the given offset. - * o sampleOffset -- a non-negative integer that gives the offset between - * CT and DT, such that CT(n) = DT(n) + CTTS(n). - * - * @return Array - */ - public function getCompositionOffsetTable() - { - return $this->_compositionOffsetTable; - } - - /** - * Sets an array of values. Each entry must have an array containing the - * following keys. - * o sampleCount -- an integer that counts the number of consecutive - * samples that have the given offset. - * o sampleOffset -- a non-negative integer that gives the offset between - * CT and DT, such that CT(n) = DT(n) + CTTS(n). - * - * @param Array $compositionOffsetTable The array of values. - */ - public function setCompositionOffsetTable($compositionOffsetTable) - { - $this->_compositionOffsetTable = $compositionOffsetTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + - count($this->_compositionOffsetTable) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_compositionOffsetTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE - ($this->_compositionOffsetTable[$i]['sampleCount']) - ->writeUInt32BE - ($this->_compositionOffsetTable[$i]['sampleOffset']); - } - } -} +Composition Time to Sample Box provides the offset between + * decoding time and composition time. Since decoding time must be less than the + * composition time, the offsets are expressed as unsigned numbers such that + * CT(n) = DT(n) + CTTS(n) where CTTS(n) is the (uncompressed) table entry for + * sample n. + * + * The composition time to sample table is optional and must only be present if + * DT and CT differ for any samples. Hint tracks do not use this box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ctts.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Ctts extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_compositionOffsetTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_compositionOffsetTable[$i] = array + ('sampleCount' => $this->_reader->readUInt32BE(), + 'sampleOffset' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o sampleCount -- an integer that counts the number of consecutive + * samples that have the given offset. + * o sampleOffset -- a non-negative integer that gives the offset between + * CT and DT, such that CT(n) = DT(n) + CTTS(n). + * + * @return Array + */ + public function getCompositionOffsetTable() + { + return $this->_compositionOffsetTable; + } + + /** + * Sets an array of values. Each entry must have an array containing the + * following keys. + * o sampleCount -- an integer that counts the number of consecutive + * samples that have the given offset. + * o sampleOffset -- a non-negative integer that gives the offset between + * CT and DT, such that CT(n) = DT(n) + CTTS(n). + * + * @param Array $compositionOffsetTable The array of values. + */ + public function setCompositionOffsetTable($compositionOffsetTable) + { + $this->_compositionOffsetTable = $compositionOffsetTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + + count($this->_compositionOffsetTable) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_compositionOffsetTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE + ($this->_compositionOffsetTable[$i]['sampleCount']) + ->writeUInt32BE + ($this->_compositionOffsetTable[$i]['sampleOffset']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Dinf.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Dinf.php index db643d66..824314ac 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Dinf.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Dinf.php @@ -1,72 +1,72 @@ -Data Information Box contains objects that declare the location - * of the media information in a track. - * - - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Dinf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Dinf extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Data Information Box contains objects that declare the location + * of the media information in a track. + * + + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Dinf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Dinf extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Dref.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Dref.php index 34a6a48b..54ee4cec 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Dref.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Dref.php @@ -1,100 +1,100 @@ -Data Reference Box contains a table of data references (normally - * URLs) that declare the location(s) of the media data used within the - * presentation. The data reference index in the sample description ties entries - * in this table to the samples in the track. A track may be split over several - * sources in this way. - * - * This box may either contain {@link Zend_Media_Iso14496_Box_Urn urn} or - * {@link Zend_Media_Iso14496_Box_Url url} boxes. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Dref.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Dref extends Zend_Media_Iso14496_FullBox -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->_reader->skip(4); - $this->constructBoxes(); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->getBoxCount()); - } -} +Data Reference Box contains a table of data references (normally + * URLs) that declare the location(s) of the media data used within the + * presentation. The data reference index in the sample description ties entries + * in this table to the samples in the track. A track may be split over several + * sources in this way. + * + * This box may either contain {@link Zend_Media_Iso14496_Box_Urn urn} or + * {@link Zend_Media_Iso14496_Box_Url url} boxes. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Dref.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Dref extends Zend_Media_Iso14496_FullBox +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->_reader->skip(4); + $this->constructBoxes(); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->getBoxCount()); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Edts.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Edts.php index 2bbae535..1c76267a 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Edts.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Edts.php @@ -1,76 +1,76 @@ -Edit Box maps the presentation time-line to the media time-line as - * it is stored in the file. The Edit Box is a container for the edit lists. - * - * The Edit Box is optional. In the absence of this box, there is an implicit - * one-to-one mapping of these time-lines, and the presentation of a track - * starts at the beginning of the presentation. An empty edit is used to offset - * the start time of a track. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Edts.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Edts extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Edit Box maps the presentation time-line to the media time-line as + * it is stored in the file. The Edit Box is a container for the edit lists. + * + * The Edit Box is optional. In the absence of this box, there is an implicit + * one-to-one mapping of these time-lines, and the presentation of a track + * starts at the beginning of the presentation. An empty edit is used to offset + * the start time of a track. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Edts.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Edts extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Elst.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Elst.php index 52da7c9d..18c31771 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Elst.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Elst.php @@ -1,169 +1,169 @@ -Edit List Box contains an explicit timeline map. Each entry - * defines part of the track time-line: by mapping part of the media time-line, - * or by indicating empty time, or by defining a dwell, where a single - * time-point in the media is held for a period. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Elst.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Elst extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_entries = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 0; $i < $entryCount; $i++) { - $entry = array(); - if ($this->getVersion() == 1) { - $entry['segmentDuration'] = $this->_reader->readInt64BE(); - $entry['mediaTime'] = $this->_reader->readInt64BE(); - } else { - $entry['segmentDuration'] = $this->_reader->readUInt32BE(); - $entry['mediaTime'] = $this->_reader->readInt32BE(); - } - $entry['mediaRate'] = - (float)($this->_reader->readInt16BE() . "." . - $this->_reader->readInt16BE()); - $this->_entries[] = $entry; - } - } - - /** - * Returns an array of entries. Each entry is an array containing the - * following keys. - * o segmentDuration: specifies the duration of this edit segment in units - * of the timescale in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. - * o mediaTime: the starting time within the media of this edit segment - * (in media time scale units, in composition time). If this field is - * set to –1, it is an empty edit. The last edit in a track shall never - * be an empty edit. Any difference between the duration in the - * {@link Zend_Media_Iso14496_Box_MVHD Movie Header Box}, and the - * track's duration is expressed as an implicit empty edit at the end. - * o mediaRate: the relative rate at which to play the media corresponding - * to this edit segment. If this value is 0, then the edit is specifying - * a dwell: the media at media-time is presented for the - * segment-duration. Otherwise this field shall contain the value 1. - * - * @return Array - */ - public function getEntries() - { - return $this->_entries; - } - - /** - * Sets the array of entries. Each entry must be an array containing the - * following keys. - * o segmentDuration: specifies the duration of this edit segment in units - * of the timescale in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. - * o mediaTime: the starting time within the media of this edit segment - * (in media time scale units, in composition time). If this field is - * set to –1, it is an empty edit. The last edit in a track shall never - * be an empty edit. Any difference between the duration in the - * {@link Zend_Media_Iso14496_Box_MVHD Movie Header Box}, and the - * track's duration is expressed as an implicit empty edit at the end. - * o mediaRate: the relative rate at which to play the media corresponding - * to this edit segment. If this value is 0, then the edit is specifying - * a dwell: the media at media-time is presented for the - * segment-duration. Otherwise this field shall contain the value 1. - * - * @param Array $entries The array of entries; - */ - public function setEntries($entries) - { - $this->_entries = $entries; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + count($this->_entries) * - ($this->getVersion() == 1 ? 20 : 12); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_entries)); - for ($i = 0; $i < $entryCount; $i++) { - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_entries[$i]['segmentDuration']) - ->writeInt64BE($this->_entries[$i]['mediaTime']); - } else { - $writer->writeUInt32BE($this->_entries[$i]['segmentDuration']) - ->writeInt32BE($this->_entries[$i]['mediaTime']); - } - @list($mediaRateInteger, $mediaRateFraction) = explode - ('.', (float)$this->_entries[$i]['mediaRate']); - $writer->writeInt16BE($mediaRateInteger) - ->writeInt16BE($mediaRateFraction); - } - } -} +Edit List Box contains an explicit timeline map. Each entry + * defines part of the track time-line: by mapping part of the media time-line, + * or by indicating empty time, or by defining a dwell, where a single + * time-point in the media is held for a period. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Elst.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Elst extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_entries = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 0; $i < $entryCount; $i++) { + $entry = array(); + if ($this->getVersion() == 1) { + $entry['segmentDuration'] = $this->_reader->readInt64BE(); + $entry['mediaTime'] = $this->_reader->readInt64BE(); + } else { + $entry['segmentDuration'] = $this->_reader->readUInt32BE(); + $entry['mediaTime'] = $this->_reader->readInt32BE(); + } + $entry['mediaRate'] = + (float)($this->_reader->readInt16BE() . "." . + $this->_reader->readInt16BE()); + $this->_entries[] = $entry; + } + } + + /** + * Returns an array of entries. Each entry is an array containing the + * following keys. + * o segmentDuration: specifies the duration of this edit segment in units + * of the timescale in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. + * o mediaTime: the starting time within the media of this edit segment + * (in media time scale units, in composition time). If this field is + * set to –1, it is an empty edit. The last edit in a track shall never + * be an empty edit. Any difference between the duration in the + * {@link Zend_Media_Iso14496_Box_MVHD Movie Header Box}, and the + * track's duration is expressed as an implicit empty edit at the end. + * o mediaRate: the relative rate at which to play the media corresponding + * to this edit segment. If this value is 0, then the edit is specifying + * a dwell: the media at media-time is presented for the + * segment-duration. Otherwise this field shall contain the value 1. + * + * @return Array + */ + public function getEntries() + { + return $this->_entries; + } + + /** + * Sets the array of entries. Each entry must be an array containing the + * following keys. + * o segmentDuration: specifies the duration of this edit segment in units + * of the timescale in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. + * o mediaTime: the starting time within the media of this edit segment + * (in media time scale units, in composition time). If this field is + * set to –1, it is an empty edit. The last edit in a track shall never + * be an empty edit. Any difference between the duration in the + * {@link Zend_Media_Iso14496_Box_MVHD Movie Header Box}, and the + * track's duration is expressed as an implicit empty edit at the end. + * o mediaRate: the relative rate at which to play the media corresponding + * to this edit segment. If this value is 0, then the edit is specifying + * a dwell: the media at media-time is presented for the + * segment-duration. Otherwise this field shall contain the value 1. + * + * @param Array $entries The array of entries; + */ + public function setEntries($entries) + { + $this->_entries = $entries; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + count($this->_entries) * + ($this->getVersion() == 1 ? 20 : 12); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_entries)); + for ($i = 0; $i < $entryCount; $i++) { + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_entries[$i]['segmentDuration']) + ->writeInt64BE($this->_entries[$i]['mediaTime']); + } else { + $writer->writeUInt32BE($this->_entries[$i]['segmentDuration']) + ->writeInt32BE($this->_entries[$i]['mediaTime']); + } + @list($mediaRateInteger, $mediaRateFraction) = explode + ('.', (float)$this->_entries[$i]['mediaRate']); + $writer->writeInt16BE($mediaRateInteger) + ->writeInt16BE($mediaRateFraction); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Free.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Free.php index c7cdfe13..1250fa37 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Free.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Free.php @@ -1,89 +1,89 @@ -Free Space Box are irrelevant and may be ignored, or - * the object deleted, without affecting the presentation. (Care should be - * exercised when deleting the object, as this may invalidate the offsets used - * in the sample table, unless this object is after all the media data). - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Free.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Free extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return ($this->getSize() >= 8 ? $this->getSize() : 0); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - if ($this->getSize() >= 8) { - parent::_writeData($writer); - $writer->write(str_repeat("\0", $this->getSize() - 8)); - } - } -} +Free Space Box are irrelevant and may be ignored, or + * the object deleted, without affecting the presentation. (Care should be + * exercised when deleting the object, as this may invalidate the offsets used + * in the sample table, unless this object is after all the media data). + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Free.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Free extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return ($this->getSize() >= 8 ? $this->getSize() : 0); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + if ($this->getSize() >= 8) { + parent::_writeData($writer); + $writer->write(str_repeat("\0", $this->getSize() - 8)); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Frma.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Frma.php index 6b79271e..1e76e50c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Frma.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Frma.php @@ -1,116 +1,116 @@ -Original Format Box contains the four-character-code of the - * original un-transformed sample description. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Frma.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Frma extends Zend_Media_Iso14496_Box -{ - /** @var string */ - private $_dataFormat; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_dataFormat = $this->_reader->read(4); - } - - /** - * Returns the four-character-code of the original un-transformed sample - * entry (e.g. mp4v if the stream contains protected MPEG-4 visual - * material). - * - * @return string - */ - public function getDataFormat() - { - return $this->_dataFormat; - } - - /** - * Sets the four-character-code of the original un-transformed sample - * entry (e.g. mp4v if the stream contains protected MPEG-4 visual - * material). - * - * @param string $dataFormat The data format. - */ - public function setDataFormat($dataFormat) - { - $this->_dataFormat = $dataFormat; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - - $writer->write(substr($this->_dataFormat, 0, 4)); - } -} +Original Format Box contains the four-character-code of the + * original un-transformed sample description. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Frma.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Frma extends Zend_Media_Iso14496_Box +{ + /** @var string */ + private $_dataFormat; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_dataFormat = $this->_reader->read(4); + } + + /** + * Returns the four-character-code of the original un-transformed sample + * entry (e.g. mp4v if the stream contains protected MPEG-4 visual + * material). + * + * @return string + */ + public function getDataFormat() + { + return $this->_dataFormat; + } + + /** + * Sets the four-character-code of the original un-transformed sample + * entry (e.g. mp4v if the stream contains protected MPEG-4 visual + * material). + * + * @param string $dataFormat The data format. + */ + public function setDataFormat($dataFormat) + { + $this->_dataFormat = $dataFormat; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + + $writer->write(substr($this->_dataFormat, 0, 4)); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Ftyp.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Ftyp.php index 90639ba7..fc9877c1 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Ftyp.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Ftyp.php @@ -1,210 +1,210 @@ -File Type Box is placed as early as possible in the file (e.g. - * after any obligatory signature, but before any significant variable-size - * boxes such as a {@link Zend_Media_Iso14496_Box_Moov Movie Box}, - * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}, or - * {@link Zend_Media_Iso14496_Box_Free Free Space}). It identifies which - * specification is the best use of the file, and a minor version of - * that specification; and also a set of others specifications to which the - * file complies. - * - * The minor version is informative only. It does not appear for - * compatible-brands, and must not be used to determine the conformance of a - * file to a standard. It may allow more precise identification of the major - * specification, for inspection, debugging, or improved decoding. - * - * The type isom (ISO Base Media file) is defined as identifying files - * that conform to the first version of the ISO Base Media File Format. More - * specific identifiers can be used to identify precise versions of - * specifications providing more detail. This brand is not be used as the major - * brand; this base file format should be derived into another specification to - * be used. There is therefore no defined normal file extension, or mime type - * assigned to this brand, nor definition of the minor version when isom - * is the major brand. - * - * Files would normally be externally identified (e.g. with a file extension or - * mime type) that identifies the best use (major brand), or the brand - * that the author believes will provide the greatest compatibility. - * - * The brand iso2 shall be used to indicate compatibility with the - * amended version of the ISO Base Media File Format; it may be used in addition - * to or instead of the isom brand and the same usage rules apply. If - * used without the brand isom identifying the first version of the - * specification, it indicates that support for some or all of the technology - * introduced by the amended version of the ISO Base Media File Format is - * required. - * - * The brand avc1 shall be used to indicate that the file is conformant - * with the AVC Extensions. If used without other brands, this implies - * that support for those extensions is required. The use of avc1 as a - * major-brand may be permitted by specifications; in that case, that - * specification defines the file extension and required behavior. - * - * If a Meta-box with an MPEG-7 handler type is used at the file level, then the - * brand mp71 is a member of the compatible-brands list in the file-type - * box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ftyp.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Ftyp extends Zend_Media_Iso14496_Box -{ - /** @var integer */ - private $_majorBrand; - - /** @var integer */ - private $_minorVersion; - - /** @var integer */ - private $_compatibleBrands = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_majorBrand = $this->_reader->readString8(4); - $this->_minorVersion = $this->_reader->readUInt32BE(); - while ($this->_reader->getOffset() < $this->getSize()) { - if (($brand = $this->_reader->readString8(4)) != '') { - $this->_compatibleBrands[] = $brand; - } - } - } - - /** - * Returns the major version brand. - * - * @return string - */ - public function getMajorBrand() - { - return $this->_majorBrand; - } - - /** - * Sets the major version brand. - * - * @param string $majorBrand The major version brand. - */ - public function setMajorBrand($majorBrand) - { - $this->_majorBrand = $majorBrand; - } - - /** - * Returns the minor version number. - * - * @return integer - */ - public function getMinorVersion() - { - return $this->_minorVersion; - } - - /** - * Sets the minor version number. - * - * @param integer $minorVersion The minor version number. - */ - public function setMinorVersion($minorVersion) - { - $this->_minorVersion = $minorVersion; - } - - /** - * Returns the array of compatible version brands. - * - * @return Array - */ - public function getCompatibleBrands() - { - return $this->_compatibleBrands; - } - - /** - * Sets the array of compatible version brands. - * - * @param Array $compatibleBrands The array of compatible version brands. - */ - public function setCompatibleBrands($compatibleBrands) - { - $this->_compatibleBrands = $compatibleBrands; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 8 + 4 * count($this->_compatibleBrands); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - - $writer->writeString8(substr($this->_majorBrand, 0, 4)) - ->writeUInt32BE($this->_minorVersion); - for ($i = 0; $i < count($this->_compatibleBrands); $i++) { - $writer->writeString8(substr($this->_compatibleBrands[$i], 0, 4)); - } - } -} +File Type Box is placed as early as possible in the file (e.g. + * after any obligatory signature, but before any significant variable-size + * boxes such as a {@link Zend_Media_Iso14496_Box_Moov Movie Box}, + * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}, or + * {@link Zend_Media_Iso14496_Box_Free Free Space}). It identifies which + * specification is the best use of the file, and a minor version of + * that specification; and also a set of others specifications to which the + * file complies. + * + * The minor version is informative only. It does not appear for + * compatible-brands, and must not be used to determine the conformance of a + * file to a standard. It may allow more precise identification of the major + * specification, for inspection, debugging, or improved decoding. + * + * The type isom (ISO Base Media file) is defined as identifying files + * that conform to the first version of the ISO Base Media File Format. More + * specific identifiers can be used to identify precise versions of + * specifications providing more detail. This brand is not be used as the major + * brand; this base file format should be derived into another specification to + * be used. There is therefore no defined normal file extension, or mime type + * assigned to this brand, nor definition of the minor version when isom + * is the major brand. + * + * Files would normally be externally identified (e.g. with a file extension or + * mime type) that identifies the best use (major brand), or the brand + * that the author believes will provide the greatest compatibility. + * + * The brand iso2 shall be used to indicate compatibility with the + * amended version of the ISO Base Media File Format; it may be used in addition + * to or instead of the isom brand and the same usage rules apply. If + * used without the brand isom identifying the first version of the + * specification, it indicates that support for some or all of the technology + * introduced by the amended version of the ISO Base Media File Format is + * required. + * + * The brand avc1 shall be used to indicate that the file is conformant + * with the AVC Extensions. If used without other brands, this implies + * that support for those extensions is required. The use of avc1 as a + * major-brand may be permitted by specifications; in that case, that + * specification defines the file extension and required behavior. + * + * If a Meta-box with an MPEG-7 handler type is used at the file level, then the + * brand mp71 is a member of the compatible-brands list in the file-type + * box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ftyp.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Ftyp extends Zend_Media_Iso14496_Box +{ + /** @var integer */ + private $_majorBrand; + + /** @var integer */ + private $_minorVersion; + + /** @var integer */ + private $_compatibleBrands = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_majorBrand = $this->_reader->readString8(4); + $this->_minorVersion = $this->_reader->readUInt32BE(); + while ($this->_reader->getOffset() < $this->getSize()) { + if (($brand = $this->_reader->readString8(4)) != '') { + $this->_compatibleBrands[] = $brand; + } + } + } + + /** + * Returns the major version brand. + * + * @return string + */ + public function getMajorBrand() + { + return $this->_majorBrand; + } + + /** + * Sets the major version brand. + * + * @param string $majorBrand The major version brand. + */ + public function setMajorBrand($majorBrand) + { + $this->_majorBrand = $majorBrand; + } + + /** + * Returns the minor version number. + * + * @return integer + */ + public function getMinorVersion() + { + return $this->_minorVersion; + } + + /** + * Sets the minor version number. + * + * @param integer $minorVersion The minor version number. + */ + public function setMinorVersion($minorVersion) + { + $this->_minorVersion = $minorVersion; + } + + /** + * Returns the array of compatible version brands. + * + * @return Array + */ + public function getCompatibleBrands() + { + return $this->_compatibleBrands; + } + + /** + * Sets the array of compatible version brands. + * + * @param Array $compatibleBrands The array of compatible version brands. + */ + public function setCompatibleBrands($compatibleBrands) + { + $this->_compatibleBrands = $compatibleBrands; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 8 + 4 * count($this->_compatibleBrands); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + + $writer->writeString8(substr($this->_majorBrand, 0, 4)) + ->writeUInt32BE($this->_minorVersion); + for ($i = 0; $i < count($this->_compatibleBrands); $i++) { + $writer->writeString8(substr($this->_compatibleBrands[$i], 0, 4)); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Hdlr.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Hdlr.php index 406534c7..8b944d32 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Hdlr.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Hdlr.php @@ -1,174 +1,174 @@ -Handler Reference Box is within a - * {@link Zend_Media_Iso14496_Box_Mdia Media Box} declares the process by which - * the media-data in the track is presented, and thus, the nature of the media - * in a track. For example, a video track would be handled by a video handler. - * - * This box when present within a {@link Zend_Media_Iso14496_Box_Meta Meta Box}, - * declares the structure or format of the meta box contents. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Hdlr.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Hdlr extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_handlerType; - - /** @var string */ - private $_name; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_reader->skip(4); - $this->_handlerType = $this->_reader->read(4); - $this->_reader->skip(12); - $this->_name = $this->_reader->readString8 - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - } - - /** - * Returns the handler type. - * - * When present in a media box, the returned value contains one of the - * following values, or a value from a derived specification: - * o vide Video track - * o soun Audio track - * o hint Hint track - * - * When present in a meta box, the returned value contains an appropriate - * value to indicate the format of the meta box contents. - * - * @return integer - */ - public function getHandlerType() - { - return $this->_handlerType; - } - - /** - * Sets the handler type. - * - * When present in a media box, the value must be set to one of the - * following values, or a value from a derived specification: - * o vide Video track - * o soun Audio track - * o hint Hint track - * - * When present in a meta box, the value must be set to an appropriate value - * to indicate the format of the meta box contents. - * - * @param string $handlerType The handler type. - */ - public function setHandlerType($handlerType) - { - $this->_handlerType = $handlerType; - } - - /** - * Returns the name string. The name is in UTF-8 characters and gives a - * human-readable name for the track type (for debugging and inspection - * purposes). - * - * @return integer - */ - public function getName() - { - return $this->_name; - } - - /** - * Sets the name string. The name must be in UTF-8 and give a human-readable - * name for the track type (for debugging and inspection purposes). - * - * @param string $name The human-readable description. - */ - public function setName($name) - { - $this->_name = $name; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 21 + strlen($this->_name); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write(str_pad('', 4, "\0")) - ->write($this->_handlerType) - ->writeUInt32BE(0) - ->writeUInt32BE(0) - ->writeUInt32BE(0) - ->writeString8($this->_name, 1); - } -} +Handler Reference Box is within a + * {@link Zend_Media_Iso14496_Box_Mdia Media Box} declares the process by which + * the media-data in the track is presented, and thus, the nature of the media + * in a track. For example, a video track would be handled by a video handler. + * + * This box when present within a {@link Zend_Media_Iso14496_Box_Meta Meta Box}, + * declares the structure or format of the meta box contents. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Hdlr.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Hdlr extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_handlerType; + + /** @var string */ + private $_name; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_reader->skip(4); + $this->_handlerType = $this->_reader->read(4); + $this->_reader->skip(12); + $this->_name = $this->_reader->readString8 + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + } + + /** + * Returns the handler type. + * + * When present in a media box, the returned value contains one of the + * following values, or a value from a derived specification: + * o vide Video track + * o soun Audio track + * o hint Hint track + * + * When present in a meta box, the returned value contains an appropriate + * value to indicate the format of the meta box contents. + * + * @return integer + */ + public function getHandlerType() + { + return $this->_handlerType; + } + + /** + * Sets the handler type. + * + * When present in a media box, the value must be set to one of the + * following values, or a value from a derived specification: + * o vide Video track + * o soun Audio track + * o hint Hint track + * + * When present in a meta box, the value must be set to an appropriate value + * to indicate the format of the meta box contents. + * + * @param string $handlerType The handler type. + */ + public function setHandlerType($handlerType) + { + $this->_handlerType = $handlerType; + } + + /** + * Returns the name string. The name is in UTF-8 characters and gives a + * human-readable name for the track type (for debugging and inspection + * purposes). + * + * @return integer + */ + public function getName() + { + return $this->_name; + } + + /** + * Sets the name string. The name must be in UTF-8 and give a human-readable + * name for the track type (for debugging and inspection purposes). + * + * @param string $name The human-readable description. + */ + public function setName($name) + { + $this->_name = $name; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 21 + strlen($this->_name); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write(str_pad('', 4, "\0")) + ->write($this->_handlerType) + ->writeUInt32BE(0) + ->writeUInt32BE(0) + ->writeUInt32BE(0) + ->writeString8($this->_name, 1); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Hint.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Hint.php index 9ebb6935..55805552 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Hint.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Hint.php @@ -1,120 +1,120 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Hint.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Hint extends Zend_Media_Iso14496_Box -{ - /** @var Array */ - private $_trackId = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - while ($this->_reader->getOffset <= $this->getSize()) { - $this->_trackId[] = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns an array of integer references from the containing track to - * another track in the presentation. Track IDs are never re-used and cannot - * be equal to zero. - * - * @return Array - */ - public function getTrackId() - { - return $this->_trackId; - } - - /** - * Sets an array of integer references from the containing track to - * another track in the presentation. Track IDs are never re-used and cannot - * be equal to zero. - * - * @param Array $trackId The array of values. - */ - public function setTrackId($trackId) - { - $this->_trackId = $trackId; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + count($this->_trackId) * 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - for ($i = 0; $i < count($this->_trackId); $i++) { - $writer->writeUInt32BE($this->_trackId[$i]); - } - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Hint.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Hint extends Zend_Media_Iso14496_Box +{ + /** @var Array */ + private $_trackId = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + while ($this->_reader->getOffset <= $this->getSize()) { + $this->_trackId[] = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns an array of integer references from the containing track to + * another track in the presentation. Track IDs are never re-used and cannot + * be equal to zero. + * + * @return Array + */ + public function getTrackId() + { + return $this->_trackId; + } + + /** + * Sets an array of integer references from the containing track to + * another track in the presentation. Track IDs are never re-used and cannot + * be equal to zero. + * + * @param Array $trackId The array of values. + */ + public function setTrackId($trackId) + { + $this->_trackId = $trackId; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + count($this->_trackId) * 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + for ($i = 0; $i < count($this->_trackId); $i++) { + $writer->writeUInt32BE($this->_trackId[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Hmhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Hmhd.php index 03c6effb..e185d794 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Hmhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Hmhd.php @@ -1,187 +1,187 @@ -Hint Media Header Box header contains general information, - * independent of the protocol, for hint tracks. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Hmhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Hmhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_maxPDUSize; - - /** @var integer */ - private $_avgPDUSize; - - /** @var integer */ - private $_maxBitrate; - - /** @var integer */ - private $_avgBitrate; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_maxPDUSize = $this->_reader->readUInt16BE(); - $this->_avgPDUSize = $this->_reader->readUInt16BE(); - $this->_maxBitrate = $this->_reader->readUInt32BE(); - $this->_avgBitrate = $this->_reader->readUInt32BE(); - } - - /** - * Returns the size in bytes of the largest PDU in this (hint) stream. - * - * @return integer - */ - public function getMaxPDUSize() - { - return $this->_maxPDUSize; - } - - /** - * Returns the size in bytes of the largest PDU in this (hint) stream. - * - * @param integer $maxPDUSize The maximum size. - */ - public function setMaxPDUSize($maxPDUSize) - { - $this->_maxPDUSize = $maxPDUSize; - } - - /** - * Returns the average size of a PDU over the entire presentation. - * - * @return integer - */ - public function getAvgPDUSize() - { - return $this->_avgPDUSize; - } - - /** - * Sets the average size of a PDU over the entire presentation. - * - * @param integer $avgPDUSize The average size. - */ - public function setAvgPDUSize() - { - $this->_avgPDUSize = $avgPDUSize; - } - - /** - * Returns the maximum rate in bits/second over any window of one second. - * - * @return integer - */ - public function getMaxBitrate() - { - return $this->_maxBitrate; - } - - /** - * Sets the maximum rate in bits/second over any window of one second. - * - * @param integer $maxBitrate The maximum bitrate. - */ - public function setMaxBitrate($maxBitrate) - { - $this->_maxBitrate = $maxBitrate; - } - - /** - * Returns the average rate in bits/second over the entire presentation. - * - * @return integer - */ - public function getAvgBitrate() - { - return $this->_avgBitrate; - } - - /** - * Sets the average rate in bits/second over the entire presentation. - * - * @param integer $maxbitrate The agerage bitrate. - */ - public function setAvgBitrate($avgBitrate) - { - $this->_avgBitrate = $avgBitrate; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 2; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - - $writer->writeUInt16BE($this->_maxPDUSize) - ->writeUInt16BE($this->_avgPDUSize) - ->writeUInt16BE($this->_maxBitrate) - ->writeUInt16BE($this->_avgBitrate); - } -} +Hint Media Header Box header contains general information, + * independent of the protocol, for hint tracks. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Hmhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Hmhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_maxPDUSize; + + /** @var integer */ + private $_avgPDUSize; + + /** @var integer */ + private $_maxBitrate; + + /** @var integer */ + private $_avgBitrate; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_maxPDUSize = $this->_reader->readUInt16BE(); + $this->_avgPDUSize = $this->_reader->readUInt16BE(); + $this->_maxBitrate = $this->_reader->readUInt32BE(); + $this->_avgBitrate = $this->_reader->readUInt32BE(); + } + + /** + * Returns the size in bytes of the largest PDU in this (hint) stream. + * + * @return integer + */ + public function getMaxPDUSize() + { + return $this->_maxPDUSize; + } + + /** + * Returns the size in bytes of the largest PDU in this (hint) stream. + * + * @param integer $maxPDUSize The maximum size. + */ + public function setMaxPDUSize($maxPDUSize) + { + $this->_maxPDUSize = $maxPDUSize; + } + + /** + * Returns the average size of a PDU over the entire presentation. + * + * @return integer + */ + public function getAvgPDUSize() + { + return $this->_avgPDUSize; + } + + /** + * Sets the average size of a PDU over the entire presentation. + * + * @param integer $avgPDUSize The average size. + */ + public function setAvgPDUSize() + { + $this->_avgPDUSize = $avgPDUSize; + } + + /** + * Returns the maximum rate in bits/second over any window of one second. + * + * @return integer + */ + public function getMaxBitrate() + { + return $this->_maxBitrate; + } + + /** + * Sets the maximum rate in bits/second over any window of one second. + * + * @param integer $maxBitrate The maximum bitrate. + */ + public function setMaxBitrate($maxBitrate) + { + $this->_maxBitrate = $maxBitrate; + } + + /** + * Returns the average rate in bits/second over the entire presentation. + * + * @return integer + */ + public function getAvgBitrate() + { + return $this->_avgBitrate; + } + + /** + * Sets the average rate in bits/second over the entire presentation. + * + * @param integer $maxbitrate The agerage bitrate. + */ + public function setAvgBitrate($avgBitrate) + { + $this->_avgBitrate = $avgBitrate; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 2; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + + $writer->writeUInt16BE($this->_maxPDUSize) + ->writeUInt16BE($this->_avgPDUSize) + ->writeUInt16BE($this->_maxBitrate) + ->writeUInt16BE($this->_avgBitrate); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Id32.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Id32.php index 65c08830..a421d71f 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Id32.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Id32.php @@ -1,161 +1,161 @@ -ID3v2 Box resides under the - * {@link Zend_Media_Iso14496_Box_Meta Meta Box} and stores ID3 version 2 - * meta-data. There may be more than one Id3v2 Box present each with a different - * language code. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Id32.php 259 2012-03-05 18:58:07Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Id32 extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_language = 'und'; - - /** @var Zend_Media_Id3v2 */ - private $_tag; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_language = - chr(((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + - 0x60) . - chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); - $this->_tag = new Zend_Media_Id3v2 - ($this->_reader, array('readonly' => true)); - } - - /** - * Returns the three byte language code to describe the language of this - * media, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO 639-2/T}. - * - * @return string - */ - public function getLanguage() - { - return $this->_language; - } - - /** - * Sets the three byte language code as specified in the - * {@link http://www.loc.gov/standards/iso639-2/ ISO 639-2} standard. - * - * @param string $language The language code. - */ - public function setLanguage($language) - { - $this->_language = $language; - } - - /** - * Returns the {@link Zend_Media_Id3v2 Id3v2} tag class instance. - * - * @return string - */ - public function getTag() - { - return $this->_tag; - } - - /** - * Sets the {@link Zend_Media_Id3v2 Id3v2} tag class instance using given - * language. - * - * @param Zend_Media_Id3v2 $tag The tag instance. - * @param string $language The language code. - */ - public function setTag($tag, $language = null) - { - $this->_tag = $tag; - if ($language !== null) { - $this->_language = $language; - } - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - * @todo There has got to be a better way to do this - */ - public function getHeapSize() - { - $writer = new Zend_Io_StringWriter(); - $this->_tag->write($writer); - return parent::getHeapSize() + 2 + $writer->getSize(); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE - (((ord($this->_language[0]) - 0x60) << 10) | - ((ord($this->_language[1]) - 0x60) << 5) | - ord($this->_language[2]) - 0x60); - $this->_tag->write($writer); - } -} +ID3v2 Box resides under the + * {@link Zend_Media_Iso14496_Box_Meta Meta Box} and stores ID3 version 2 + * meta-data. There may be more than one Id3v2 Box present each with a different + * language code. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Id32.php 259 2012-03-05 18:58:07Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Id32 extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_language = 'und'; + + /** @var Zend_Media_Id3v2 */ + private $_tag; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_language = + chr(((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + + 0x60) . + chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); + $this->_tag = new Zend_Media_Id3v2 + ($this->_reader, array('readonly' => true)); + } + + /** + * Returns the three byte language code to describe the language of this + * media, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO 639-2/T}. + * + * @return string + */ + public function getLanguage() + { + return $this->_language; + } + + /** + * Sets the three byte language code as specified in the + * {@link http://www.loc.gov/standards/iso639-2/ ISO 639-2} standard. + * + * @param string $language The language code. + */ + public function setLanguage($language) + { + $this->_language = $language; + } + + /** + * Returns the {@link Zend_Media_Id3v2 Id3v2} tag class instance. + * + * @return string + */ + public function getTag() + { + return $this->_tag; + } + + /** + * Sets the {@link Zend_Media_Id3v2 Id3v2} tag class instance using given + * language. + * + * @param Zend_Media_Id3v2 $tag The tag instance. + * @param string $language The language code. + */ + public function setTag($tag, $language = null) + { + $this->_tag = $tag; + if ($language !== null) { + $this->_language = $language; + } + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + * @todo There has got to be a better way to do this + */ + public function getHeapSize() + { + $writer = new Zend_Io_StringWriter(); + $this->_tag->write($writer); + return parent::getHeapSize() + 2 + $writer->getSize(); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE + (((ord($this->_language[0]) - 0x60) << 10) | + ((ord($this->_language[1]) - 0x60) << 5) | + ord($this->_language[2]) - 0x60); + $this->_tag->write($writer); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Iinf.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Iinf.php index a4921d59..299d01a5 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Iinf.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Iinf.php @@ -1,100 +1,100 @@ -Item Information Box provides extra information about selected - * items, including symbolic (file) names. It may optionally occur, but - * if it does, it must be interpreted, as item protection or content encoding - * may have changed the format of the data in the item. If both content encoding - * and protection are indicated for an item, a reader should first un-protect - * the item, and then decode the item's content encoding. If more control is - * needed, an IPMP sequence code may be used. - * - - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iinf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Iinf extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->_reader->skip(2); - $this->constructBoxes(); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 2; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE($this->getBoxCount()); - } -} +Item Information Box provides extra information about selected + * items, including symbolic (file) names. It may optionally occur, but + * if it does, it must be interpreted, as item protection or content encoding + * may have changed the format of the data in the item. If both content encoding + * and protection are indicated for an item, a reader should first un-protect + * the item, and then decode the item's content encoding. If more control is + * needed, an IPMP sequence code may be used. + * + + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iinf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Iinf extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->_reader->skip(2); + $this->constructBoxes(); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 2; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE($this->getBoxCount()); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Iloc.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Iloc.php index d819920c..731c293a 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Iloc.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Iloc.php @@ -1,245 +1,245 @@ -The Item Location Box provides a directory of resources in this or - * other files, by locating their containing file, their offset within that - * file, and their length. Placing this in binary format enables common handling - * of this data, even by systems which do not understand the particular metadata - * system (handler) used. For example, a system might integrate all the - * externally referenced metadata resources into one file, re-adjusting file - * offsets and file references accordingly. - * - * Items may be stored fragmented into extents, e.g. to enable interleaving. An - * extent is a contiguous subset of the bytes of the resource; the resource is - * formed by concatenating the extents. If only one extent is used then either - * or both of the offset and length may be implied: - * - * o If the offset is not identified (the field has a length of zero), then - * the beginning of the file (offset 0) is implied. - * o If the length is not specified, or specified as zero, then the entire - * file length is implied. References into the same file as this metadata, - * or items divided into more than one extent, should have an explicit - * offset and length, or use a MIME type requiring a different - * interpretation of the file, to avoid infinite recursion. - * - * The size of the item is the sum of the extentLengths. Note: extents may be - * interleaved with the chunks defined by the sample tables of tracks. - * - * The dataReferenceIndex may take the value 0, indicating a reference into the - * same file as this metadata, or an index into the dataReference table. - * - * Some referenced data may itself use offset/length techniques to address - * resources within it (e.g. an MP4 file might be included in this way). - * Normally such offsets are relative to the beginning of the containing file. - * The field base offset provides an additional offset for offset calculations - * within that contained data. For example, if an MP4 file is included within a - * file formatted to this specification, then normally data-offsets within that - * MP4 section are relative to the beginning of file; baseOffset adds to those - * offsets. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iloc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Iloc extends Zend_Media_Iso14496_Box -{ - /** @var Array */ - private $_items = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $offsetSize = (($tmp = $this->_reader->readUInt16BE()) >> 12) & 0xf; - $lengthSize = ($tmp >> 8) & 0xf; - $baseOffsetSize = ($tmp >> 4) & 0xf; - $itemCount = $this->_reader->readUInt16BE(); - for ($i = 0; $i < $itemCount; $i++) { - $item = array(); - $item['itemId'] = $this->_reader->readUInt16BE(); - $item['dataReferenceIndex'] = $this->_reader->readUInt16BE(); - $item['baseOffset'] = - ($baseOffsetSize == 4 ? $this->_reader->readUInt32BE() : - ($baseOffsetSize == 8 ? $this->_reader->readInt64BE() : 0)); - $extentCount = $this->_reader->readUInt16BE(); - $item['extents'] = array(); - for ($j = 0; $j < $extentCount; $j++) { - $extent = array(); - $extent['offset'] = - ($offsetSize == 4 ? $this->_reader->readUInt32BE() : - ($offsetSize == 8 ? $this->_reader->readInt64BE() : 0)); - $extent['length'] = - ($lengthSize == 4 ? $this->_reader->readUInt32BE() : - ($lengthSize == 8 ? $this->_reader->readInt64BE() : 0)); - $item['extents'][] = $extent; - } - $this->_items[] = $item; - } - } - - /** - * Returns the array of items. Each entry has the following keys set: - * itemId, dataReferenceIndex, baseOffset, and extents. - * - * @return Array - */ - public function getItems() - { - return $this->_items; - } - - /** - * Sets the array of items. Each entry must have the following keys set: - * itemId, dataReferenceIndex, baseOffset, and extents. - * - * @return Array - */ - public function setItems($items) - { - $this->_items = $items; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - $totalSize = 4; - for ($i = 0; $i < count($this->_itemId); $i++) { - $totalSize += 6; - if ($this->_itemId[$i]['baseOffset'] > 0xffffffff) { - $totalSize += 8; - } else { - $totalSize += 4; - } - $extentCount = count($this->_itemId[$i]['extents']); - for ($j = 0; $j < $extentCount; $j++) { - if ($this->_itemId[$i]['extents'][$j]['offset'] > 0xffffffff) { - $totalSize += 8 * $extentCount; - } else { - $totalSize += 4 * $extentCount; - } - if ($this->_itemId[$i]['extents'][$j]['length'] > 0xffffffff) { - $totalSize += 8 * $extentCount; - } else { - $totalSize += 4 * $extentCount; - } - } - } - return parent::getHeapSize() + $totalSize; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - - $offsetSize = 4; - $lengthSize = 4; - $baseOffsetSize = 4; - - $itemCount = count($this->_itemId); - for ($i = 0; $i < $itemCount; $i++) { - if ($this->_itemId[$i]['baseOffset'] > 0xffffffff) { - $baseOffsetSize = 8; - } - for ($j = 0; $j < count($this->_itemId[$i]['extents']); $j++) { - if ($this->_itemId[$i]['extents'][$j]['offset'] > 0xffffffff) { - $offsetSize = 8; - } - if ($this->_itemId[$i]['extents'][$j]['length'] > 0xffffffff) { - $lengthSize = 8; - } - } - } - - $writer->writeUInt16BE - ((($offsetSize & 0xf) << 12) | (($lengthSize & 0xf) << 8) | - (($baseOffsetSize & 0xf) << 4)) - ->writeUInt16BE($itemCount); - for ($i = 0; $i < $itemCount; $i++) { - $writer->writeUInt16BE($this->_itemId[$i]['itemId']) - ->writeUInt16BE($this->_itemId[$i]['dataReferenceIndex']); - if ($baseOffsetSize == 4) { - $writer->writeUInt32BE($this->_itemId[$i]['baseOffset']); - } - if ($baseOffsetSize == 8) { - $writer->writeInt64BE($this->_itemId[$i]['baseOffset']); - } - $writer->writeUInt16BE - ($extentCount = count($this->_itemId[$i]['extents'])); - for ($j = 0; $j < $extentCount; $j++) { - if ($offsetSize == 4) { - $writer->writeUInt32BE - ($this->_itemId[$i]['extents'][$j]['offset']); - } - if ($offsetSize == 8) { - $writer->writeInt64BE - ($this->_itemId[$i]['extents'][$j]['offset']); - } - if ($offsetSize == 4) { - $writer->writeUInt32BE - ($this->_itemId[$i]['extents'][$j]['length']); - } - if ($offsetSize == 8) { - $writer->writeInt64BE - ($this->_itemId[$i]['extents'][$j]['length']); - } - } - } - } -} +The Item Location Box provides a directory of resources in this or + * other files, by locating their containing file, their offset within that + * file, and their length. Placing this in binary format enables common handling + * of this data, even by systems which do not understand the particular metadata + * system (handler) used. For example, a system might integrate all the + * externally referenced metadata resources into one file, re-adjusting file + * offsets and file references accordingly. + * + * Items may be stored fragmented into extents, e.g. to enable interleaving. An + * extent is a contiguous subset of the bytes of the resource; the resource is + * formed by concatenating the extents. If only one extent is used then either + * or both of the offset and length may be implied: + * + * o If the offset is not identified (the field has a length of zero), then + * the beginning of the file (offset 0) is implied. + * o If the length is not specified, or specified as zero, then the entire + * file length is implied. References into the same file as this metadata, + * or items divided into more than one extent, should have an explicit + * offset and length, or use a MIME type requiring a different + * interpretation of the file, to avoid infinite recursion. + * + * The size of the item is the sum of the extentLengths. Note: extents may be + * interleaved with the chunks defined by the sample tables of tracks. + * + * The dataReferenceIndex may take the value 0, indicating a reference into the + * same file as this metadata, or an index into the dataReference table. + * + * Some referenced data may itself use offset/length techniques to address + * resources within it (e.g. an MP4 file might be included in this way). + * Normally such offsets are relative to the beginning of the containing file. + * The field base offset provides an additional offset for offset calculations + * within that contained data. For example, if an MP4 file is included within a + * file formatted to this specification, then normally data-offsets within that + * MP4 section are relative to the beginning of file; baseOffset adds to those + * offsets. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iloc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Iloc extends Zend_Media_Iso14496_Box +{ + /** @var Array */ + private $_items = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $offsetSize = (($tmp = $this->_reader->readUInt16BE()) >> 12) & 0xf; + $lengthSize = ($tmp >> 8) & 0xf; + $baseOffsetSize = ($tmp >> 4) & 0xf; + $itemCount = $this->_reader->readUInt16BE(); + for ($i = 0; $i < $itemCount; $i++) { + $item = array(); + $item['itemId'] = $this->_reader->readUInt16BE(); + $item['dataReferenceIndex'] = $this->_reader->readUInt16BE(); + $item['baseOffset'] = + ($baseOffsetSize == 4 ? $this->_reader->readUInt32BE() : + ($baseOffsetSize == 8 ? $this->_reader->readInt64BE() : 0)); + $extentCount = $this->_reader->readUInt16BE(); + $item['extents'] = array(); + for ($j = 0; $j < $extentCount; $j++) { + $extent = array(); + $extent['offset'] = + ($offsetSize == 4 ? $this->_reader->readUInt32BE() : + ($offsetSize == 8 ? $this->_reader->readInt64BE() : 0)); + $extent['length'] = + ($lengthSize == 4 ? $this->_reader->readUInt32BE() : + ($lengthSize == 8 ? $this->_reader->readInt64BE() : 0)); + $item['extents'][] = $extent; + } + $this->_items[] = $item; + } + } + + /** + * Returns the array of items. Each entry has the following keys set: + * itemId, dataReferenceIndex, baseOffset, and extents. + * + * @return Array + */ + public function getItems() + { + return $this->_items; + } + + /** + * Sets the array of items. Each entry must have the following keys set: + * itemId, dataReferenceIndex, baseOffset, and extents. + * + * @return Array + */ + public function setItems($items) + { + $this->_items = $items; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + $totalSize = 4; + for ($i = 0; $i < count($this->_itemId); $i++) { + $totalSize += 6; + if ($this->_itemId[$i]['baseOffset'] > 0xffffffff) { + $totalSize += 8; + } else { + $totalSize += 4; + } + $extentCount = count($this->_itemId[$i]['extents']); + for ($j = 0; $j < $extentCount; $j++) { + if ($this->_itemId[$i]['extents'][$j]['offset'] > 0xffffffff) { + $totalSize += 8 * $extentCount; + } else { + $totalSize += 4 * $extentCount; + } + if ($this->_itemId[$i]['extents'][$j]['length'] > 0xffffffff) { + $totalSize += 8 * $extentCount; + } else { + $totalSize += 4 * $extentCount; + } + } + } + return parent::getHeapSize() + $totalSize; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + + $offsetSize = 4; + $lengthSize = 4; + $baseOffsetSize = 4; + + $itemCount = count($this->_itemId); + for ($i = 0; $i < $itemCount; $i++) { + if ($this->_itemId[$i]['baseOffset'] > 0xffffffff) { + $baseOffsetSize = 8; + } + for ($j = 0; $j < count($this->_itemId[$i]['extents']); $j++) { + if ($this->_itemId[$i]['extents'][$j]['offset'] > 0xffffffff) { + $offsetSize = 8; + } + if ($this->_itemId[$i]['extents'][$j]['length'] > 0xffffffff) { + $lengthSize = 8; + } + } + } + + $writer->writeUInt16BE + ((($offsetSize & 0xf) << 12) | (($lengthSize & 0xf) << 8) | + (($baseOffsetSize & 0xf) << 4)) + ->writeUInt16BE($itemCount); + for ($i = 0; $i < $itemCount; $i++) { + $writer->writeUInt16BE($this->_itemId[$i]['itemId']) + ->writeUInt16BE($this->_itemId[$i]['dataReferenceIndex']); + if ($baseOffsetSize == 4) { + $writer->writeUInt32BE($this->_itemId[$i]['baseOffset']); + } + if ($baseOffsetSize == 8) { + $writer->writeInt64BE($this->_itemId[$i]['baseOffset']); + } + $writer->writeUInt16BE + ($extentCount = count($this->_itemId[$i]['extents'])); + for ($j = 0; $j < $extentCount; $j++) { + if ($offsetSize == 4) { + $writer->writeUInt32BE + ($this->_itemId[$i]['extents'][$j]['offset']); + } + if ($offsetSize == 8) { + $writer->writeInt64BE + ($this->_itemId[$i]['extents'][$j]['offset']); + } + if ($offsetSize == 4) { + $writer->writeUInt32BE + ($this->_itemId[$i]['extents'][$j]['length']); + } + if ($offsetSize == 8) { + $writer->writeInt64BE + ($this->_itemId[$i]['extents'][$j]['length']); + } + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Ilst.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Ilst.php index 7821a4d3..a040315e 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Ilst.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Ilst.php @@ -1,326 +1,326 @@ - - *
  • _nam -- Name of the track
  • - *
  • _ART -- Name of the artist
  • - *
  • aART -- Name of the album artist
  • - *
  • _alb -- Name of the album
  • - *
  • _grp -- Grouping
  • - *
  • _day -- Year of publication
  • - *
  • trkn -- Track number (number/total)
  • - *
  • disk -- Disk number (number/total)
  • - *
  • tmpo -- BPM tempo
  • - *
  • _wrt -- Name of the composer
  • - *
  • _cmt -- Comments
  • - *
  • _gen -- Genre as string
  • - *
  • gnre -- Genre as an ID3v1 code, added by one
  • - *
  • cpil -- Part of a compilation (0/1)
  • - *
  • tvsh -- Name of the (television) show
  • - *
  • sonm -- Sort name of the track
  • - *
  • soar -- Sort name of the artist
  • - *
  • soaa -- Sort name of the album artist
  • - *
  • soal -- Sort name of the album
  • - *
  • soco -- Sort name of the composer
  • - *
  • sosn -- Sort name of the show
  • - *
  • _lyr -- Lyrics
  • - *
  • covr -- Cover (or other) artwork binary data
  • - *
  • _too -- Information about the software
  • - * - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since iTunes/iPod specific - */ -final class Zend_Media_Iso14496_Box_Ilst extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes('Zend_Media_Iso14496_Box_Ilst_Container'); - } - - /** - * Override magic function so that $obj->value on a box will return the data - * box instead of the data container box. - * - * @param string $name The box or field name. - * @return mixed - */ - public function __get($name) - { - if (strlen($name) == 3) { - $name = "\xa9" . $name; - } - if ($name[0] == '_') { - $name = "\xa9" . substr($name, 1, 3); - } - if ($this->hasBox($name)) { - $boxes = $this->getBoxesByIdentifier($name); - return $boxes[0]->data; - } - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - return $this->addBox - (new Zend_Media_Iso14496_Box_Ilst_Container($name))->data; - } -} - -/** - * Generic iTunes/iPod DATA Box container. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since iTunes/iPod specific - * @ignore - */ -final class Zend_Media_Iso14496_Box_Ilst_Container - extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct(is_string($reader) ? null : $reader, $options); - $this->setContainer(true); - - if (is_string($reader)) { - $this->setType($reader); - $this->addBox(new Zend_Media_Iso14496_Box_Data()); - } else { - $this->constructBoxes(); - } - } -} - -/**#@+ @ignore */ -require_once 'Zend/Media/Iso14496/FullBox.php'; -/**#@-*/ - -/** - * A box that contains data for iTunes/iPod specific boxes. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ - * @since iTunes/iPod specific - */ -final class Zend_Media_Iso14496_Box_Data extends Zend_Media_Iso14496_FullBox -{ - /** @var mixed */ - private $_value; - - /** A flag to indicate that the data is an unsigned 8-bit integer. */ - const INTEGER = 0x0; - - /** - * A flag to indicate that the data is an unsigned 8-bit integer. Different - * value used in old versions of iTunes. - */ - const INTEGER_OLD_STYLE = 0x15; - - /** A flag to indicate that the data is a string. */ - const STRING = 0x1; - - /** A flag to indicate that the data is the contents of an JPEG image. */ - const JPEG = 0xd; - - /** A flag to indicate that the data is the contents of a PNG image. */ - const PNG = 0xe; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_reader->skip(4); - $data = $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - switch ($this->getFlags()) { - case self::INTEGER: - // break intentionally omitted - case self::INTEGER_OLD_STYLE: - for ($i = 0; $i < strlen($data); $i++) { - $this->_value .= ord($data[$i]); - } - break; - case self::STRING: - // break intentionally omitted - default: - $this->_value = $data; - break; - } - } - - /** - * Returns the value this box contains. - * - * @return mixed - */ - public function getValue() - { - return $this->_value; - } - - /** - * Sets the value this box contains. - * - * @return mixed - */ - public function setValue($value, $type = null) - { - $this->_value = (string)$value; - if ($type === null && is_string($value)) { - $this->_flags = self::STRING; - } - if ($type === null && is_int($value)) { - $this->_flags = self::INTEGER; - } - if ($type !== null) { - $this->_flags = $type; - } - } - - /** - * Override magic function so that $obj->data will return the current box - * instead of an error. For other values the method will attempt to call a - * getter method. - * - * If there are no getter methods with given name, the method will yield an - * exception. - * - * @param string $name The box or field name. - * @return mixed - */ - public function __get($name) - { - if ($name == 'data') { - return $this; - } - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - require_once 'Zend/Media/Iso14496/Exception.php'; - throw new Zend_Media_Iso14496_Exception('Unknown box/field: ' . $name); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + strlen($this->_value); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write("\0\0\0\0"); - switch ($this->getFlags()) { - case self::INTEGER: - // break intentionally omitted - case self::INTEGER_OLD_STYLE: - for ($i = 0; $i < strlen($this->_value); $i++) { - $writer->writeInt8($this->_value[$i]); - } - break; - case self::STRING: - // break intentionally omitted - default: - $writer->write($this->_value); - break; - } - } -} + + *
  • _nam -- Name of the track
  • + *
  • _ART -- Name of the artist
  • + *
  • aART -- Name of the album artist
  • + *
  • _alb -- Name of the album
  • + *
  • _grp -- Grouping
  • + *
  • _day -- Year of publication
  • + *
  • trkn -- Track number (number/total)
  • + *
  • disk -- Disk number (number/total)
  • + *
  • tmpo -- BPM tempo
  • + *
  • _wrt -- Name of the composer
  • + *
  • _cmt -- Comments
  • + *
  • _gen -- Genre as string
  • + *
  • gnre -- Genre as an ID3v1 code, added by one
  • + *
  • cpil -- Part of a compilation (0/1)
  • + *
  • tvsh -- Name of the (television) show
  • + *
  • sonm -- Sort name of the track
  • + *
  • soar -- Sort name of the artist
  • + *
  • soaa -- Sort name of the album artist
  • + *
  • soal -- Sort name of the album
  • + *
  • soco -- Sort name of the composer
  • + *
  • sosn -- Sort name of the show
  • + *
  • _lyr -- Lyrics
  • + *
  • covr -- Cover (or other) artwork binary data
  • + *
  • _too -- Information about the software
  • + * + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since iTunes/iPod specific + */ +final class Zend_Media_Iso14496_Box_Ilst extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes('Zend_Media_Iso14496_Box_Ilst_Container'); + } + + /** + * Override magic function so that $obj->value on a box will return the data + * box instead of the data container box. + * + * @param string $name The box or field name. + * @return mixed + */ + public function __get($name) + { + if (strlen($name) == 3) { + $name = "\xa9" . $name; + } + if ($name[0] == '_') { + $name = "\xa9" . substr($name, 1, 3); + } + if ($this->hasBox($name)) { + $boxes = $this->getBoxesByIdentifier($name); + return $boxes[0]->data; + } + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + return $this->addBox + (new Zend_Media_Iso14496_Box_Ilst_Container($name))->data; + } +} + +/** + * Generic iTunes/iPod DATA Box container. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since iTunes/iPod specific + * @ignore + */ +final class Zend_Media_Iso14496_Box_Ilst_Container + extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct(is_string($reader) ? null : $reader, $options); + $this->setContainer(true); + + if (is_string($reader)) { + $this->setType($reader); + $this->addBox(new Zend_Media_Iso14496_Box_Data()); + } else { + $this->constructBoxes(); + } + } +} + +/**#@+ @ignore */ +require_once 'Zend/Media/Iso14496/FullBox.php'; +/**#@-*/ + +/** + * A box that contains data for iTunes/iPod specific boxes. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ilst.php 177 2010-03-09 13:13:34Z svollbehr $ + * @since iTunes/iPod specific + */ +final class Zend_Media_Iso14496_Box_Data extends Zend_Media_Iso14496_FullBox +{ + /** @var mixed */ + private $_value; + + /** A flag to indicate that the data is an unsigned 8-bit integer. */ + const INTEGER = 0x0; + + /** + * A flag to indicate that the data is an unsigned 8-bit integer. Different + * value used in old versions of iTunes. + */ + const INTEGER_OLD_STYLE = 0x15; + + /** A flag to indicate that the data is a string. */ + const STRING = 0x1; + + /** A flag to indicate that the data is the contents of an JPEG image. */ + const JPEG = 0xd; + + /** A flag to indicate that the data is the contents of a PNG image. */ + const PNG = 0xe; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_reader->skip(4); + $data = $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + switch ($this->getFlags()) { + case self::INTEGER: + // break intentionally omitted + case self::INTEGER_OLD_STYLE: + for ($i = 0; $i < strlen($data); $i++) { + $this->_value .= ord($data[$i]); + } + break; + case self::STRING: + // break intentionally omitted + default: + $this->_value = $data; + break; + } + } + + /** + * Returns the value this box contains. + * + * @return mixed + */ + public function getValue() + { + return $this->_value; + } + + /** + * Sets the value this box contains. + * + * @return mixed + */ + public function setValue($value, $type = null) + { + $this->_value = (string)$value; + if ($type === null && is_string($value)) { + $this->_flags = self::STRING; + } + if ($type === null && is_int($value)) { + $this->_flags = self::INTEGER; + } + if ($type !== null) { + $this->_flags = $type; + } + } + + /** + * Override magic function so that $obj->data will return the current box + * instead of an error. For other values the method will attempt to call a + * getter method. + * + * If there are no getter methods with given name, the method will yield an + * exception. + * + * @param string $name The box or field name. + * @return mixed + */ + public function __get($name) + { + if ($name == 'data') { + return $this; + } + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + require_once 'Zend/Media/Iso14496/Exception.php'; + throw new Zend_Media_Iso14496_Exception('Unknown box/field: ' . $name); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + strlen($this->_value); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write("\0\0\0\0"); + switch ($this->getFlags()) { + case self::INTEGER: + // break intentionally omitted + case self::INTEGER_OLD_STYLE: + for ($i = 0; $i < strlen($this->_value); $i++) { + $writer->writeInt8($this->_value[$i]); + } + break; + case self::STRING: + // break intentionally omitted + default: + $writer->write($this->_value); + break; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Imif.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Imif.php index 89c89606..89e4423b 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Imif.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Imif.php @@ -1,91 +1,91 @@ -IPMP Information Box contains IPMP Descriptors which document the - * protection applied to the stream. - * - * IPMP_Descriptor is defined in 14496-1. This is a part of the MPEG-4 object - * descriptors (OD) that describe how an object can be accessed and decoded. - * Here, in the ISO Base Media File Format, IPMP Descriptor can be carried - * directly in IPMP Information Box without the need for OD stream. - * - * The presence of IPMP Descriptor in this box indicates the associated media - * stream is protected by the IPMP Tool described in the IPMP Descriptor. - * - * Each IPMP_Descriptor has an IPMP_ToolID, which identifies the required IPMP - * tool for protection. An independent registration authority (RA) is used so - * any party can register its own IPMP Tool and identify this without - * collisions. - * - * The IPMP_Descriptor carries IPMP information for one or more IPMP Tool - * instances, it includes but not limited to IPMP Rights Data, IPMP Key Data, - * Tool Configuration Data, etc. - * - * More than one IPMP Descriptors can be carried in this box if this media - * stream is protected by more than one IPMP Tools. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Imif.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Imif extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +IPMP Information Box contains IPMP Descriptors which document the + * protection applied to the stream. + * + * IPMP_Descriptor is defined in 14496-1. This is a part of the MPEG-4 object + * descriptors (OD) that describe how an object can be accessed and decoded. + * Here, in the ISO Base Media File Format, IPMP Descriptor can be carried + * directly in IPMP Information Box without the need for OD stream. + * + * The presence of IPMP Descriptor in this box indicates the associated media + * stream is protected by the IPMP Tool described in the IPMP Descriptor. + * + * Each IPMP_Descriptor has an IPMP_ToolID, which identifies the required IPMP + * tool for protection. An independent registration authority (RA) is used so + * any party can register its own IPMP Tool and identify this without + * collisions. + * + * The IPMP_Descriptor carries IPMP information for one or more IPMP Tool + * instances, it includes but not limited to IPMP Rights Data, IPMP Key Data, + * Tool Configuration Data, etc. + * + * More than one IPMP Descriptors can be carried in this box if this media + * stream is protected by more than one IPMP Tools. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Imif.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Imif extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Infe.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Infe.php index 48327451..3805ddb3 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Infe.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Infe.php @@ -1,233 +1,233 @@ -Item Information Entry Box contains the entry information. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Infe.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Infe extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_itemId; - - /** @var integer */ - private $_itemProtectionIndex; - - /** @var string */ - private $_itemName; - - /** @var string */ - private $_contentType; - - /** @var string */ - private $_contentEncoding; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_itemId = $this->_reader->readUInt16BE(); - $this->_itemProtectionIndex = $this->_reader->readUInt16BE(); - list($this->_itemName, $this->_contentType, $this->_contentEncoding) = - preg_split - ("/\\x00/", $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset())); - } - - /** - * Returns the item identifier. The value is either 0 for the primary - * resource (e.g. the XML contained in an - * {@link Zend_Media_Iso14496_Box_Xml XML Box}) or the ID of the item for - * which the following information is defined. - * - * @return integer - */ - public function getItemId() - { - return $this->_itemId; - } - - /** - * Sets the item identifier. The value must be either 0 for the primary - * resource (e.g. the XML contained in an - * {@link Zend_Media_Iso14496_Box_Xml XML Box}) or the ID of the item for - * which the following information is defined. - * - * @param integer $itemId The item identifier. - */ - public function setItemId($itemId) - { - $this->_itemId = $itemId; - } - - /** - * Returns the item protection index. The value is either 0 for an - * unprotected item, or the one-based index into the - * {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} defining the - * protection applied to this item (the first box in the item protection box - * has the index 1). - * - * @return integer - */ - public function getItemProtectionIndex() - { - return $this->_itemProtectionIndex; - } - - /** - * Sets the item protection index. The value must be either 0 for an - * unprotected item, or the one-based index into the - * {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} defining the - * protection applied to this item (the first box in the item protection box - * has the index 1). - * - * @param integer $itemProtectionIndex The index. - */ - public function setItemProtectionIndex($itemProtectionIndex) - { - $this->_itemProtectionIndex = $itemProtectionIndex; - } - - /** - * Returns the symbolic name of the item. - * - * @return string - */ - public function getItemName() - { - return $this->_itemName; - } - - /** - * Sets the symbolic name of the item. - * - * @param string $itemName The item name. - */ - public function setItemName($itemName) - { - $this->_itemName = $itemName; - } - - /** - * Returns the MIME type for the item. - * - * @return string - */ - public function getContentType() - { - return $this->_contentType; - } - - /** - * Sets the MIME type for the item. - * - * @param string $contentType The content type. - */ - public function setContentType($contentType) - { - $this->_contentType = $contentType; - } - - /** - * Returns the optional content encoding type as defined for - * Content-Encoding for HTTP /1.1. Some possible values are gzip, - * compress and deflate. An empty string indicates no content - * encoding. - * - * @return string - */ - public function getContentEncoding() - { - return $this->_contentEncoding; - } - - /** - * Sets the optional content encoding type as defined for - * Content-Encoding for HTTP /1.1. Some possible values are gzip, - * compress and deflate. An empty string indicates no content - * encoding. - * - * @param string $contentEncoding The content encoding. - */ - public function setContentEncoding($contentEncoding) - { - $this->_contentEncoding = $contentEncoding; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 7 + strlen($this->_itemName) + - strlen($this->_contentType) + strlen($this->_contentEncoding); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE($this->_itemId) - ->writeUInt16BE($this->_itemProtectionIndex) - ->writeString8($this->_itemName, 1) - ->writeString8($this->_contentType, 1) - ->writeString8($this->_contentEncoding, 1); - } -} +Item Information Entry Box contains the entry information. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Infe.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Infe extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_itemId; + + /** @var integer */ + private $_itemProtectionIndex; + + /** @var string */ + private $_itemName; + + /** @var string */ + private $_contentType; + + /** @var string */ + private $_contentEncoding; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_itemId = $this->_reader->readUInt16BE(); + $this->_itemProtectionIndex = $this->_reader->readUInt16BE(); + list($this->_itemName, $this->_contentType, $this->_contentEncoding) = + preg_split + ("/\\x00/", $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset())); + } + + /** + * Returns the item identifier. The value is either 0 for the primary + * resource (e.g. the XML contained in an + * {@link Zend_Media_Iso14496_Box_Xml XML Box}) or the ID of the item for + * which the following information is defined. + * + * @return integer + */ + public function getItemId() + { + return $this->_itemId; + } + + /** + * Sets the item identifier. The value must be either 0 for the primary + * resource (e.g. the XML contained in an + * {@link Zend_Media_Iso14496_Box_Xml XML Box}) or the ID of the item for + * which the following information is defined. + * + * @param integer $itemId The item identifier. + */ + public function setItemId($itemId) + { + $this->_itemId = $itemId; + } + + /** + * Returns the item protection index. The value is either 0 for an + * unprotected item, or the one-based index into the + * {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} defining the + * protection applied to this item (the first box in the item protection box + * has the index 1). + * + * @return integer + */ + public function getItemProtectionIndex() + { + return $this->_itemProtectionIndex; + } + + /** + * Sets the item protection index. The value must be either 0 for an + * unprotected item, or the one-based index into the + * {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} defining the + * protection applied to this item (the first box in the item protection box + * has the index 1). + * + * @param integer $itemProtectionIndex The index. + */ + public function setItemProtectionIndex($itemProtectionIndex) + { + $this->_itemProtectionIndex = $itemProtectionIndex; + } + + /** + * Returns the symbolic name of the item. + * + * @return string + */ + public function getItemName() + { + return $this->_itemName; + } + + /** + * Sets the symbolic name of the item. + * + * @param string $itemName The item name. + */ + public function setItemName($itemName) + { + $this->_itemName = $itemName; + } + + /** + * Returns the MIME type for the item. + * + * @return string + */ + public function getContentType() + { + return $this->_contentType; + } + + /** + * Sets the MIME type for the item. + * + * @param string $contentType The content type. + */ + public function setContentType($contentType) + { + $this->_contentType = $contentType; + } + + /** + * Returns the optional content encoding type as defined for + * Content-Encoding for HTTP /1.1. Some possible values are gzip, + * compress and deflate. An empty string indicates no content + * encoding. + * + * @return string + */ + public function getContentEncoding() + { + return $this->_contentEncoding; + } + + /** + * Sets the optional content encoding type as defined for + * Content-Encoding for HTTP /1.1. Some possible values are gzip, + * compress and deflate. An empty string indicates no content + * encoding. + * + * @param string $contentEncoding The content encoding. + */ + public function setContentEncoding($contentEncoding) + { + $this->_contentEncoding = $contentEncoding; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 7 + strlen($this->_itemName) + + strlen($this->_contentType) + strlen($this->_contentEncoding); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE($this->_itemId) + ->writeUInt16BE($this->_itemProtectionIndex) + ->writeString8($this->_itemName, 1) + ->writeString8($this->_contentType, 1) + ->writeString8($this->_contentEncoding, 1); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Ipro.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Ipro.php index a0f8ee82..7be029f3 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Ipro.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Ipro.php @@ -1,95 +1,95 @@ -Item Protection Box provides an array of item protection - * information, for use by the - * {@link Zend_Media_Iso14496_Box_Iinf Item Information Box}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ipro.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Ipro extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->_reader->skip(2); - $this->constructBoxes(); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 2; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE($this->getBoxCount()); - } -} +Item Protection Box provides an array of item protection + * information, for use by the + * {@link Zend_Media_Iso14496_Box_Iinf Item Information Box}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ipro.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Ipro extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->_reader->skip(2); + $this->constructBoxes(); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 2; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE($this->getBoxCount()); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mdhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mdhd.php index f92fc1d9..6f985360 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mdhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mdhd.php @@ -1,243 +1,243 @@ -Media Header Box declares overall information that is - * media-independent, and relevant to characteristics of the media in a track. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mdhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mdhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_creationTime; - - /** @var integer */ - private $_modificationTime; - - /** @var integer */ - private $_timescale; - - /** @var integer */ - private $_duration; - - /** @var string */ - private $_language = 'und'; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->getVersion() == 1) { - $this->_creationTime = $this->_reader->readInt64BE(); - $this->_modificationTime = $this->_reader->readInt64BE(); - $this->_timescale = $this->_reader->readUInt32BE(); - $this->_duration = $this->_reader->readInt64BE(); - } else { - $this->_creationTime = $this->_reader->readUInt32BE(); - $this->_modificationTime = $this->_reader->readUInt32BE(); - $this->_timescale = $this->_reader->readUInt32BE(); - $this->_duration = $this->_reader->readUInt32BE(); - } - $this->_language = chr - (((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + 0x60) . - chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); - } - - /** - * Returns the creation time of the media in this track, in seconds since - * midnight, Jan. 1, 1904, in UTC time. - * - * @return integer - */ - public function getCreationTime() - { - return $this->_creationTime; - } - - /** - * Sets the creation time of the media in this track, in seconds since - * midnight, Jan. 1, 1904, in UTC time. - * - * @param integer $creationTime The creation time. - */ - public function setCreationTime($creationTime) - { - $this->_creationTime = $creationTime; - } - - /** - * Returns the most recent time the media in this track was modified in - * seconds since midnight, Jan. 1, 1904, in UTC time. - * - * @return integer - */ - public function getModificationTime() - { - return $this->_modificationTime; - } - - /** - * Sets the most recent time the media in this track was modified in - * seconds since midnight, Jan. 1, 1904, in UTC time. - * - * @param integer $modificationTime The modification time. - */ - public function setModificationTime($modificationTime) - { - $this->_modificationTime = $modificationTime; - } - - /** - * Returns the time-scale for this media. This is the number of time units - * that pass in one second. For example, a time coordinate system that - * measures time in sixtieths of a second has a time scale of 60. - * - * @return integer - */ - public function getTimescale() - { - return $this->_timescale; - } - - /** - * Sets the time-scale for this media. This is the number of time units - * that pass in one second. For example, a time coordinate system that - * measures time in sixtieths of a second has a time scale of 60. - * - * @param integer $timescale The time-scale. - */ - public function setTimescale($timescale) - { - $this->_timescale = $timescale; - } - - /** - * Returns the duration of this media (in the scale of the timescale). - * - * @return integer - */ - public function getDuration() - { - return $this->_duration; - } - - /** - * Sets the duration of this media (in the scale of the timescale). - * - * @param integer $duration The duration. - */ - public function setDuration($duration) - { - $this->_duration = $duration; - } - - /** - * Returns the three byte language code to describe the language of this - * media, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO 639-2/T}. - * - * @return string - */ - public function getLanguage() - { - return $this->_language; - } - - /** - * Sets the three byte language code to describe the language of this - * media, according to {@link http://www.loc.gov/standards/iso639-2/ - * ISO 639-2/T}. - * - * @param string $language The language code. - */ - public function setLanguage($language) - { - $this->_language = $language; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + - ($this->getVersion() == 1 ? 28 : 16) + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_creationTime) - ->writeInt64BE($this->_modificationTime) - ->writeUInt32BE($this->_timescale) - ->writeInt64BE($this->_duration); - } else { - $writer->writeUInt32BE($this->_creationTime) - ->writeUInt32BE($this->_modificationTime) - ->writeUInt32BE($this->_timescale) - ->writeUInt32BE($this->_duration); - } - $writer->writeUInt16BE((ord($this->_language[0]) - 0x60) << 10 | - (ord($this->_language[1])- 0x60) << 5 | - (ord($this->_language[2])- 0x60)) - ->write(str_pad('', 2, "\0")); - } -} +Media Header Box declares overall information that is + * media-independent, and relevant to characteristics of the media in a track. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mdhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mdhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_creationTime; + + /** @var integer */ + private $_modificationTime; + + /** @var integer */ + private $_timescale; + + /** @var integer */ + private $_duration; + + /** @var string */ + private $_language = 'und'; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->getVersion() == 1) { + $this->_creationTime = $this->_reader->readInt64BE(); + $this->_modificationTime = $this->_reader->readInt64BE(); + $this->_timescale = $this->_reader->readUInt32BE(); + $this->_duration = $this->_reader->readInt64BE(); + } else { + $this->_creationTime = $this->_reader->readUInt32BE(); + $this->_modificationTime = $this->_reader->readUInt32BE(); + $this->_timescale = $this->_reader->readUInt32BE(); + $this->_duration = $this->_reader->readUInt32BE(); + } + $this->_language = chr + (((($tmp = $this->_reader->readUInt16BE()) >> 10) & 0x1f) + 0x60) . + chr((($tmp >> 5) & 0x1f) + 0x60) . chr(($tmp & 0x1f) + 0x60); + } + + /** + * Returns the creation time of the media in this track, in seconds since + * midnight, Jan. 1, 1904, in UTC time. + * + * @return integer + */ + public function getCreationTime() + { + return $this->_creationTime; + } + + /** + * Sets the creation time of the media in this track, in seconds since + * midnight, Jan. 1, 1904, in UTC time. + * + * @param integer $creationTime The creation time. + */ + public function setCreationTime($creationTime) + { + $this->_creationTime = $creationTime; + } + + /** + * Returns the most recent time the media in this track was modified in + * seconds since midnight, Jan. 1, 1904, in UTC time. + * + * @return integer + */ + public function getModificationTime() + { + return $this->_modificationTime; + } + + /** + * Sets the most recent time the media in this track was modified in + * seconds since midnight, Jan. 1, 1904, in UTC time. + * + * @param integer $modificationTime The modification time. + */ + public function setModificationTime($modificationTime) + { + $this->_modificationTime = $modificationTime; + } + + /** + * Returns the time-scale for this media. This is the number of time units + * that pass in one second. For example, a time coordinate system that + * measures time in sixtieths of a second has a time scale of 60. + * + * @return integer + */ + public function getTimescale() + { + return $this->_timescale; + } + + /** + * Sets the time-scale for this media. This is the number of time units + * that pass in one second. For example, a time coordinate system that + * measures time in sixtieths of a second has a time scale of 60. + * + * @param integer $timescale The time-scale. + */ + public function setTimescale($timescale) + { + $this->_timescale = $timescale; + } + + /** + * Returns the duration of this media (in the scale of the timescale). + * + * @return integer + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * Sets the duration of this media (in the scale of the timescale). + * + * @param integer $duration The duration. + */ + public function setDuration($duration) + { + $this->_duration = $duration; + } + + /** + * Returns the three byte language code to describe the language of this + * media, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO 639-2/T}. + * + * @return string + */ + public function getLanguage() + { + return $this->_language; + } + + /** + * Sets the three byte language code to describe the language of this + * media, according to {@link http://www.loc.gov/standards/iso639-2/ + * ISO 639-2/T}. + * + * @param string $language The language code. + */ + public function setLanguage($language) + { + $this->_language = $language; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + + ($this->getVersion() == 1 ? 28 : 16) + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_creationTime) + ->writeInt64BE($this->_modificationTime) + ->writeUInt32BE($this->_timescale) + ->writeInt64BE($this->_duration); + } else { + $writer->writeUInt32BE($this->_creationTime) + ->writeUInt32BE($this->_modificationTime) + ->writeUInt32BE($this->_timescale) + ->writeUInt32BE($this->_duration); + } + $writer->writeUInt16BE((ord($this->_language[0]) - 0x60) << 10 | + (ord($this->_language[1])- 0x60) << 5 | + (ord($this->_language[2])- 0x60)) + ->write(str_pad('', 2, "\0")); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mdia.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mdia.php index 6002a7f3..0214bd1c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mdia.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mdia.php @@ -1,71 +1,71 @@ -Media Box contains all the objects that declare information about - * the media data within a track. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mdia.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mdia extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Media Box contains all the objects that declare information about + * the media data within a track. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mdia.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mdia extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mehd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mehd.php index d0744bfa..35d0936c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mehd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mehd.php @@ -1,128 +1,128 @@ -Movie Extends Header Box is optional, and provides the overall - * duration, including fragments, of a fragmented movie. If this box is not - * present, the overall duration must be computed by examining each fragment. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mehd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mehd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_fragmentDuration; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->getVersion() == 1) { - $this->_fragmentDuration = $this->_reader->readInt64BE(); - } else { - $this->_fragmentDuration = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns the length of the presentation of the whole movie including - * fragments (in the timescale indicated in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of - * this field corresponds to the duration of the longest track, including - * movie fragments. - * - * @return integer - */ - public function getFragmentDuration() - { - return $this->_fragmentDuration; - } - - /** - * Sets the length of the presentation of the whole movie including - * fragments (in the timescale indicated in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of - * this field must correspond to the duration of the longest track, - * including movie fragments. - * - * @param integer $fragmentDuration The fragment duration. - */ - public function setFragmentDuration($fragmentDuration) - { - $this->_fragmentDuration = $fragmentDuration; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + ($this->getVersion() == 1 ? 8 : 4); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_fragmentDuration); - } else { - $writer->writeUInt32BE($this->_fragmentDuration); - } - } -} +Movie Extends Header Box is optional, and provides the overall + * duration, including fragments, of a fragmented movie. If this box is not + * present, the overall duration must be computed by examining each fragment. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mehd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mehd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_fragmentDuration; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->getVersion() == 1) { + $this->_fragmentDuration = $this->_reader->readInt64BE(); + } else { + $this->_fragmentDuration = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns the length of the presentation of the whole movie including + * fragments (in the timescale indicated in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of + * this field corresponds to the duration of the longest track, including + * movie fragments. + * + * @return integer + */ + public function getFragmentDuration() + { + return $this->_fragmentDuration; + } + + /** + * Sets the length of the presentation of the whole movie including + * fragments (in the timescale indicated in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of + * this field must correspond to the duration of the longest track, + * including movie fragments. + * + * @param integer $fragmentDuration The fragment duration. + */ + public function setFragmentDuration($fragmentDuration) + { + $this->_fragmentDuration = $fragmentDuration; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + ($this->getVersion() == 1 ? 8 : 4); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_fragmentDuration); + } else { + $writer->writeUInt32BE($this->_fragmentDuration); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Meta.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Meta.php index 2da0d365..7dea09fa 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Meta.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Meta.php @@ -1,91 +1,91 @@ -Meta Box contains descriptive or annotative metadata. The - * meta box is required to contain a - * {@link Zend_Media_Iso14496_Box_Hdlr hdlr} box indicating the structure or - * format of the meta box contents. That metadata is located either - * within a box within this box (e.g. an XML box), or is located by the item - * identified by a primary item box. - * - * All other contained boxes are specific to the format specified by the handler - * box. - * - * The other boxes defined here may be defined as optional or mandatory for a - * given format. If they are used, then they must take the form specified here. - * These optional boxes include a data-information box, which documents other - * files in which metadata values (e.g. pictures) are placed, and a item - * location box, which documents where in those files each item is located (e.g. - * in the common case of multiple pictures stored in the same file). At most one - * meta box may occur at each of the file level, movie level, or track level. - * - * If an {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} occurs, then - * some or all of the meta-data, including possibly the primary resource, may - * have been protected and be un-readable unless the protection system is taken - * into account. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Meta.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Meta extends Zend_Media_Iso14496_FullBox -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Meta Box contains descriptive or annotative metadata. The + * meta box is required to contain a + * {@link Zend_Media_Iso14496_Box_Hdlr hdlr} box indicating the structure or + * format of the meta box contents. That metadata is located either + * within a box within this box (e.g. an XML box), or is located by the item + * identified by a primary item box. + * + * All other contained boxes are specific to the format specified by the handler + * box. + * + * The other boxes defined here may be defined as optional or mandatory for a + * given format. If they are used, then they must take the form specified here. + * These optional boxes include a data-information box, which documents other + * files in which metadata values (e.g. pictures) are placed, and a item + * location box, which documents where in those files each item is located (e.g. + * in the common case of multiple pictures stored in the same file). At most one + * meta box may occur at each of the file level, movie level, or track level. + * + * If an {@link Zend_Media_Iso14496_Box_Ipro Item Protection Box} occurs, then + * some or all of the meta-data, including possibly the primary resource, may + * have been protected and be un-readable unless the protection system is taken + * into account. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Meta.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Meta extends Zend_Media_Iso14496_FullBox +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfhd.php index 21e03dd6..68cec213 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfhd.php @@ -1,114 +1,114 @@ -Movie Fragment Header Box contains a sequence number, as a safety - * check. The sequence number usually starts at 1 and must increase for each - * movie fragment in the file, in the order in which they occur. This allows - * readers to verify integrity of the sequence; it is an error to construct a - * file where the fragments are out of sequence. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mfhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mfhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_sequenceNumber; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_sequenceNumber = $this->_reader->readUInt32BE(); - } - - /** - * Returns the ordinal number of this fragment, in increasing order. - * - * @return integer - */ - public function getSequenceNumber() - { - return $this->_sequenceNumber; - } - - /** - * Sets the ordinal number of this fragment, in increasing order. - * - * @param integer $sequenceNumber The sequence number. - */ - public function setSequenceNumber($sequenceNumber) - { - $this->_sequenceNumber = $sequenceNumber; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_sequenceNumber); - } -} +Movie Fragment Header Box contains a sequence number, as a safety + * check. The sequence number usually starts at 1 and must increase for each + * movie fragment in the file, in the order in which they occur. This allows + * readers to verify integrity of the sequence; it is an error to construct a + * file where the fragments are out of sequence. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mfhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mfhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_sequenceNumber; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_sequenceNumber = $this->_reader->readUInt32BE(); + } + + /** + * Returns the ordinal number of this fragment, in increasing order. + * + * @return integer + */ + public function getSequenceNumber() + { + return $this->_sequenceNumber; + } + + /** + * Sets the ordinal number of this fragment, in increasing order. + * + * @param integer $sequenceNumber The sequence number. + */ + public function setSequenceNumber($sequenceNumber) + { + $this->_sequenceNumber = $sequenceNumber; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_sequenceNumber); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfra.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfra.php index 825823c5..123497cc 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfra.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfra.php @@ -1,86 +1,86 @@ -Movie Fragment Random Access Box provides a table which may assist - * readers in finding random access points in a file using movie fragments. It - * contains a track fragment random access box for each track for which - * information is provided (which may not be all tracks). It is usually placed - * at or near the end of the file; the last box within the Movie Fragment Random - * Access Box provides a copy of the length field from the Movie Fragment Random - * Access Box. Readers may attempt to find this box by examining the last 32 - * bits of the file, or scanning backwards from the end of the file for a Movie - * Fragment Random Access Offset Box and using the size information in it, to - * see if that locates the beginning of a Movie Fragment Random Access Box. - * - * This box provides only a hint as to where random access points are; the movie - * fragments themselves are definitive. It is recommended that readers take care - * in both locating and using this box as modifications to the file after it was - * created may render either the pointers, or the declaration of random access - * points, incorrect. - * - - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mfra.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mfra extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Movie Fragment Random Access Box provides a table which may assist + * readers in finding random access points in a file using movie fragments. It + * contains a track fragment random access box for each track for which + * information is provided (which may not be all tracks). It is usually placed + * at or near the end of the file; the last box within the Movie Fragment Random + * Access Box provides a copy of the length field from the Movie Fragment Random + * Access Box. Readers may attempt to find this box by examining the last 32 + * bits of the file, or scanning backwards from the end of the file for a Movie + * Fragment Random Access Offset Box and using the size information in it, to + * see if that locates the beginning of a Movie Fragment Random Access Box. + * + * This box provides only a hint as to where random access points are; the movie + * fragments themselves are definitive. It is recommended that readers take care + * in both locating and using this box as modifications to the file after it was + * created may render either the pointers, or the declaration of random access + * points, incorrect. + * + + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mfra.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mfra extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfro.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfro.php index c16d58fe..8130ef5b 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mfro.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mfro.php @@ -1,123 +1,123 @@ -Movie Fragment Random Access Offset Box provides a copy of the - * length field from the enclosing {@link Zend_Media_Iso14496_Box_MFRA Movie Fragment - * Random Access Box}. It is placed last within that box, so that the size field - * is also last in the enclosing Movie Fragment Random Access Box. When the - * Movie Fragment Random Access Box is also last in the file this permits its - * easy location. The size field here must be correct. However, neither the - * presence of the Movie Fragment Random Access Box, nor its placement last in - * the file, are assured. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mfro.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mfro extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_parentSize; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_parentSize = $this->_reader->readUInt32BE(); - } - - /** - * Returns the number of bytes of the enclosing - * {@link Zend_Media_Iso14496_Box_Mfra} box. This field is placed at the - * last of the enclosing box to assist readers scanning from the end of the - * file in finding the mfra box. - * - * @return integer - */ - public function getParentSize() - { - return $this->_parentSize; - } - - /** - * Sets the number of bytes of the enclosing - * {@link Zend_Media_Iso14496_Box_Mfra} box. This field is placed at the - * last of the enclosing box to assist readers scanning from the end of the - * file in finding the mfra box. - * - * @param integer $parentSize The number of bytes. - */ - public function setParentSize($parentSize) - { - $this->_parentSize = $parentSize; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_parentSize); - } -} +Movie Fragment Random Access Offset Box provides a copy of the + * length field from the enclosing {@link Zend_Media_Iso14496_Box_MFRA Movie Fragment + * Random Access Box}. It is placed last within that box, so that the size field + * is also last in the enclosing Movie Fragment Random Access Box. When the + * Movie Fragment Random Access Box is also last in the file this permits its + * easy location. The size field here must be correct. However, neither the + * presence of the Movie Fragment Random Access Box, nor its placement last in + * the file, are assured. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mfro.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mfro extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_parentSize; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_parentSize = $this->_reader->readUInt32BE(); + } + + /** + * Returns the number of bytes of the enclosing + * {@link Zend_Media_Iso14496_Box_Mfra} box. This field is placed at the + * last of the enclosing box to assist readers scanning from the end of the + * file in finding the mfra box. + * + * @return integer + */ + public function getParentSize() + { + return $this->_parentSize; + } + + /** + * Sets the number of bytes of the enclosing + * {@link Zend_Media_Iso14496_Box_Mfra} box. This field is placed at the + * last of the enclosing box to assist readers scanning from the end of the + * file in finding the mfra box. + * + * @param integer $parentSize The number of bytes. + */ + public function setParentSize($parentSize) + { + $this->_parentSize = $parentSize; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_parentSize); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Minf.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Minf.php index e0e42fa2..c83e6096 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Minf.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Minf.php @@ -1,71 +1,71 @@ -Media Information Box contains all the objects that declare - * characteristic information of the media in the track. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Minf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Minf extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Media Information Box contains all the objects that declare + * characteristic information of the media in the track. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Minf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Minf extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Moof.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Moof.php index 6aaf5cc4..d0073ffd 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Moof.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Moof.php @@ -1,81 +1,81 @@ -Movie Fragment Box extend the presentation in time. They provide - * the information that would previously have been in the - * {@link Zend_Media_Iso14496_Box_Moov Movie Box}. The actual samples are in - * {@link Zend_Media_Iso14496_Box_Mdat Media Data Boxes}, as usual, if they are - * in the same file. The data reference index is in the sample description, so - * it is possible to build incremental presentations where the media data is in - * files other than the file containing the Movie Box. - * - * The Movie Fragment Box is a top-level box, (i.e. a peer to the Movie Box and - * Media Data boxes). It contains a - * {@link Zend_Media_Iso14496_Box_Mfhd Movie Fragment Header Box}, and then one - * or more {@link Zend_Media_Iso14496_Box_Traf Track Fragment Boxes}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Moof.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Moof extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Movie Fragment Box extend the presentation in time. They provide + * the information that would previously have been in the + * {@link Zend_Media_Iso14496_Box_Moov Movie Box}. The actual samples are in + * {@link Zend_Media_Iso14496_Box_Mdat Media Data Boxes}, as usual, if they are + * in the same file. The data reference index is in the sample description, so + * it is possible to build incremental presentations where the media data is in + * files other than the file containing the Movie Box. + * + * The Movie Fragment Box is a top-level box, (i.e. a peer to the Movie Box and + * Media Data boxes). It contains a + * {@link Zend_Media_Iso14496_Box_Mfhd Movie Fragment Header Box}, and then one + * or more {@link Zend_Media_Iso14496_Box_Traf Track Fragment Boxes}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Moof.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Moof extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Moov.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Moov.php index 29a95da3..9e81aeaa 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Moov.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Moov.php @@ -1,72 +1,72 @@ -Movie Box - * which occurs at the top-level of a file. Normally this box is close to the - * beginning or end of the file, though this is not required. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Moov.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Moov extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Movie Box + * which occurs at the top-level of a file. Normally this box is close to the + * beginning or end of the file, though this is not required. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Moov.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Moov extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mvex.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mvex.php index fdb56e4e..d06a52d3 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mvex.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mvex.php @@ -1,74 +1,74 @@ -Movie Extends Box warns readers that there might be - * {@link Zend_Media_Iso14496_Box_Mfra Movie Fragment Boxes} in this file. To - * know of all samples in the tracks, these Movie Fragment Boxes must be found - * and scanned in order, and their information logically added to that found in - * the {@link Zend_Media_Iso14496_Box_Moov Movie Box}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mvex.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mvex extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Movie Extends Box warns readers that there might be + * {@link Zend_Media_Iso14496_Box_Mfra Movie Fragment Boxes} in this file. To + * know of all samples in the tracks, these Movie Fragment Boxes must be found + * and scanned in order, and their information logically added to that found in + * the {@link Zend_Media_Iso14496_Box_Moov Movie Box}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mvex.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mvex extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Mvhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Mvhd.php index 21820f7d..4ee6cd84 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Mvhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Mvhd.php @@ -1,343 +1,343 @@ -Movie Header Box defines overall information which is - * media-independent, and relevant to the entire presentation considered as a - * whole. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Mvhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Mvhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_creationTime; - - /** @var integer */ - private $_modificationTime; - - /** @var integer */ - private $_timescale; - - /** @var integer */ - private $_duration; - - /** @var integer */ - private $_rate = 1.0; - - /** @var integer */ - private $_volume = 1.0; - - /** @var Array */ - private $_matrix = array - (0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000); - - /** @var integer */ - private $_nextTrackId; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->getVersion() == 1) { - $this->_creationTime = $this->_reader->readInt64BE(); - $this->_modificationTime = $this->_reader->readInt64BE(); - $this->_timescale = $this->_reader->readUInt32BE(); - $this->_duration = $this->_reader->readInt64BE(); - } else { - $this->_creationTime = $this->_reader->readUInt32BE(); - $this->_modificationTime = $this->_reader->readUInt32BE(); - $this->_timescale = $this->_reader->readUInt32BE(); - $this->_duration = $this->_reader->readUInt32BE(); - } - $this->_rate = - ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + - (float)("0." . ((string)($tmp & 0xffff))); - $this->_volume = - ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + - (float)("0." . ((string)($tmp & 0xff))); - $this->_reader->skip(10); - for ($i = 0; $i < 9; $i++) { - $this->_matrix[$i] = $this->_reader->readUInt32BE(); - } - $this->_reader->skip(24); - $this->_nextTrackId = $this->_reader->readUInt32BE(); - } - - /** - * Returns the creation time of the presentation. The value is in seconds - * since midnight, Jan. 1, 1904, in UTC time. - * - * @return integer - */ - public function getCreationTime() - { - return $this->_creationTime; - } - - /** - * Sets the creation time of the presentation in seconds since midnight, - * Jan. 1, 1904, in UTC time. - * - * @param integer $creationTime The creation time. - */ - public function setCreationTime($creationTime) - { - $this->_creationTime = $creationTime; - } - - /** - * Returns the most recent time the presentation was modified. The value is - * in seconds since midnight, Jan. 1, 1904, in UTC time. - * - * @return integer - */ - public function getModificationTime() - { - return $this->_modificationTime; - } - - /** - * Sets the most recent time the presentation was modified in seconds since - * midnight, Jan. 1, 1904, in UTC time. - * - * @param integer $modificationTime The most recent time the presentation - * was modified. - */ - public function setModificationTime($modificationTime) - { - $this->_modificationTime = $modificationTime; - } - - /** - * Returns the time-scale for the entire presentation. This is the number of - * time units that pass in one second. For example, a time coordinate system - * that measures time in sixtieths of a second has a time scale of 60. - * - * @return integer - */ - public function getTimescale() - { - return $this->_timescale; - } - - /** - * Sets the time-scale for the entire presentation. This is the number of - * time units that pass in one second. For example, a time coordinate system - * that measures time in sixtieths of a second has a time scale of 60. - * - * @param integer $timescale The time-scale for the entire presentation. - */ - public function setTimescale($timescale) - { - $this->_timescale = $timescale; - } - - /** - * Returns the length of the presentation in the indicated timescale. This - * property is derived from the presentation's tracks: the value of this - * field corresponds to the duration of the longest track in the - * presentation. - * - * @return integer - */ - public function getDuration() - { - return $this->_duration; - } - - /** - * Sets the length of the presentation in the indicated timescale. This - * property must be derived from the presentation's tracks: the value of - * this field must correspond to the duration of the longest track in the - * presentation. - * - * @param integer $duration The length of the presentation. - */ - public function setDuration($duration) - { - $this->_duration = $duration; - } - - /** - * Returns the preferred rate to play the presentation. 1.0 is normal - * forward playback. - * - * @return integer - */ - public function getRate() - { - return $this->_rate; - } - - /** - * Sets the preferred rate to play the presentation. 1.0 is normal - * forward playback. - * - * @param integer $rate The preferred play rate. - */ - public function setRate($rate) - { - $this->_rate = $rate; - } - - /** - * Returns the preferred playback volume. 1.0 is full volume. - * - * @return integer - */ - public function getVolume() - { - return $this->_volume; - } - - /** - * Sets the preferred playback volume. 1.0 is full volume. - * - * @param integer $volume The playback volume. - */ - public function setVolume($volume) - { - $this->_volume = $volume; - } - - /** - * Returns the transformation matrix for the video; (u,v,w) are restricted - * here to (0,0,1), hex values (0,0,0x40000000). - * - * @return Array - */ - public function getMatrix() - { - return $this->_matrix; - } - - /** - * Sets the transformation matrix for the video; (u,v,w) are restricted - * here to (0,0,1), hex values (0,0,0x40000000). - * - * @param Array $matrix The transformation matrix array of 9 values - */ - public function setMatrix($matrix) - { - $this->_matrix = $matrix; - } - - /** - * Returns a value to use for the track ID of the next track to be added to - * this presentation. Zero is not a valid track ID value. The value is - * larger than the largest track-ID in use. If this value is equal to or - * larger than 32-bit maxint, and a new media track is to be added, then a - * search must be made in the file for a unused track identifier. - * - * @return integer - */ - public function getNextTrackId() - { - return $this->_nextTrackId; - } - - /** - * Sets a value to use for the track ID of the next track to be added to - * this presentation. Zero is not a valid track ID value. The value must be - * larger than the largest track-ID in use. - * - * @param integer $nextTrackId The next track ID. - */ - public function setNextTrackId($nextTrackId) - { - $this->_nextTrackId = $nextTrackId; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + - ($this->getVersion() == 1 ? 28 : 16) + 80; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_creationTime) - ->writeInt64BE($this->_modificationTime) - ->writeUInt32BE($this->_timescale) - ->writeInt64BE($this->_duration); - } else { - $writer->writeUInt32BE($this->_creationTime) - ->writeUInt32BE($this->_modificationTime) - ->writeUInt32BE($this->_timescale) - ->writeUInt32BE($this->_duration); - } - - @list(, $rateDecimals) = explode('.', (float)$this->_rate); - @list(, $volumeDecimals) = explode('.', (float)$this->_volume); - $writer->writeUInt32BE(floor($this->_rate) << 16 | $rateDecimals) - ->writeUInt16BE(floor($this->_volume) << 8 | $volumeDecimals) - ->write(str_pad('', 10, "\0")); - for ($i = 0; $i < 9; $i++) { - $writer->writeUInt32BE($this->_matrix[$i]); - } - $writer->write(str_pad('', 24, "\0")) - ->writeUInt32BE($this->_nextTrackId); - } -} +Movie Header Box defines overall information which is + * media-independent, and relevant to the entire presentation considered as a + * whole. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Mvhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Mvhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_creationTime; + + /** @var integer */ + private $_modificationTime; + + /** @var integer */ + private $_timescale; + + /** @var integer */ + private $_duration; + + /** @var integer */ + private $_rate = 1.0; + + /** @var integer */ + private $_volume = 1.0; + + /** @var Array */ + private $_matrix = array + (0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000); + + /** @var integer */ + private $_nextTrackId; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->getVersion() == 1) { + $this->_creationTime = $this->_reader->readInt64BE(); + $this->_modificationTime = $this->_reader->readInt64BE(); + $this->_timescale = $this->_reader->readUInt32BE(); + $this->_duration = $this->_reader->readInt64BE(); + } else { + $this->_creationTime = $this->_reader->readUInt32BE(); + $this->_modificationTime = $this->_reader->readUInt32BE(); + $this->_timescale = $this->_reader->readUInt32BE(); + $this->_duration = $this->_reader->readUInt32BE(); + } + $this->_rate = + ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + + (float)("0." . ((string)($tmp & 0xffff))); + $this->_volume = + ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + + (float)("0." . ((string)($tmp & 0xff))); + $this->_reader->skip(10); + for ($i = 0; $i < 9; $i++) { + $this->_matrix[$i] = $this->_reader->readUInt32BE(); + } + $this->_reader->skip(24); + $this->_nextTrackId = $this->_reader->readUInt32BE(); + } + + /** + * Returns the creation time of the presentation. The value is in seconds + * since midnight, Jan. 1, 1904, in UTC time. + * + * @return integer + */ + public function getCreationTime() + { + return $this->_creationTime; + } + + /** + * Sets the creation time of the presentation in seconds since midnight, + * Jan. 1, 1904, in UTC time. + * + * @param integer $creationTime The creation time. + */ + public function setCreationTime($creationTime) + { + $this->_creationTime = $creationTime; + } + + /** + * Returns the most recent time the presentation was modified. The value is + * in seconds since midnight, Jan. 1, 1904, in UTC time. + * + * @return integer + */ + public function getModificationTime() + { + return $this->_modificationTime; + } + + /** + * Sets the most recent time the presentation was modified in seconds since + * midnight, Jan. 1, 1904, in UTC time. + * + * @param integer $modificationTime The most recent time the presentation + * was modified. + */ + public function setModificationTime($modificationTime) + { + $this->_modificationTime = $modificationTime; + } + + /** + * Returns the time-scale for the entire presentation. This is the number of + * time units that pass in one second. For example, a time coordinate system + * that measures time in sixtieths of a second has a time scale of 60. + * + * @return integer + */ + public function getTimescale() + { + return $this->_timescale; + } + + /** + * Sets the time-scale for the entire presentation. This is the number of + * time units that pass in one second. For example, a time coordinate system + * that measures time in sixtieths of a second has a time scale of 60. + * + * @param integer $timescale The time-scale for the entire presentation. + */ + public function setTimescale($timescale) + { + $this->_timescale = $timescale; + } + + /** + * Returns the length of the presentation in the indicated timescale. This + * property is derived from the presentation's tracks: the value of this + * field corresponds to the duration of the longest track in the + * presentation. + * + * @return integer + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * Sets the length of the presentation in the indicated timescale. This + * property must be derived from the presentation's tracks: the value of + * this field must correspond to the duration of the longest track in the + * presentation. + * + * @param integer $duration The length of the presentation. + */ + public function setDuration($duration) + { + $this->_duration = $duration; + } + + /** + * Returns the preferred rate to play the presentation. 1.0 is normal + * forward playback. + * + * @return integer + */ + public function getRate() + { + return $this->_rate; + } + + /** + * Sets the preferred rate to play the presentation. 1.0 is normal + * forward playback. + * + * @param integer $rate The preferred play rate. + */ + public function setRate($rate) + { + $this->_rate = $rate; + } + + /** + * Returns the preferred playback volume. 1.0 is full volume. + * + * @return integer + */ + public function getVolume() + { + return $this->_volume; + } + + /** + * Sets the preferred playback volume. 1.0 is full volume. + * + * @param integer $volume The playback volume. + */ + public function setVolume($volume) + { + $this->_volume = $volume; + } + + /** + * Returns the transformation matrix for the video; (u,v,w) are restricted + * here to (0,0,1), hex values (0,0,0x40000000). + * + * @return Array + */ + public function getMatrix() + { + return $this->_matrix; + } + + /** + * Sets the transformation matrix for the video; (u,v,w) are restricted + * here to (0,0,1), hex values (0,0,0x40000000). + * + * @param Array $matrix The transformation matrix array of 9 values + */ + public function setMatrix($matrix) + { + $this->_matrix = $matrix; + } + + /** + * Returns a value to use for the track ID of the next track to be added to + * this presentation. Zero is not a valid track ID value. The value is + * larger than the largest track-ID in use. If this value is equal to or + * larger than 32-bit maxint, and a new media track is to be added, then a + * search must be made in the file for a unused track identifier. + * + * @return integer + */ + public function getNextTrackId() + { + return $this->_nextTrackId; + } + + /** + * Sets a value to use for the track ID of the next track to be added to + * this presentation. Zero is not a valid track ID value. The value must be + * larger than the largest track-ID in use. + * + * @param integer $nextTrackId The next track ID. + */ + public function setNextTrackId($nextTrackId) + { + $this->_nextTrackId = $nextTrackId; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + + ($this->getVersion() == 1 ? 28 : 16) + 80; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_creationTime) + ->writeInt64BE($this->_modificationTime) + ->writeUInt32BE($this->_timescale) + ->writeInt64BE($this->_duration); + } else { + $writer->writeUInt32BE($this->_creationTime) + ->writeUInt32BE($this->_modificationTime) + ->writeUInt32BE($this->_timescale) + ->writeUInt32BE($this->_duration); + } + + @list(, $rateDecimals) = explode('.', (float)$this->_rate); + @list(, $volumeDecimals) = explode('.', (float)$this->_volume); + $writer->writeUInt32BE(floor($this->_rate) << 16 | $rateDecimals) + ->writeUInt16BE(floor($this->_volume) << 8 | $volumeDecimals) + ->write(str_pad('', 10, "\0")); + for ($i = 0; $i < 9; $i++) { + $writer->writeUInt32BE($this->_matrix[$i]); + } + $writer->write(str_pad('', 24, "\0")) + ->writeUInt32BE($this->_nextTrackId); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Ndrm.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Ndrm.php index f98e47dc..8c3301dc 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Ndrm.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Ndrm.php @@ -1,109 +1,109 @@ -Nero Digital Rights Management Box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ndrm.php 210 2010-12-28 16:46:58Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Ndrm extends Zend_Media_Iso14496_FullBox -{ - private $_data; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_data = $reader->read($this->getSize() - 12); - } - - /** - * Returns the raw binary data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the raw binary data. - * - * @param string $data The data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + $this->getSize() - 12; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_data); - } -} +Nero Digital Rights Management Box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ndrm.php 210 2010-12-28 16:46:58Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Ndrm extends Zend_Media_Iso14496_FullBox +{ + private $_data; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_data = $reader->read($this->getSize() - 12); + } + + /** + * Returns the raw binary data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the raw binary data. + * + * @param string $data The data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + $this->getSize() - 12; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Pdin.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Pdin.php index 5d2f4867..8652ce99 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Pdin.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Pdin.php @@ -1,143 +1,143 @@ -Progressive Download Information Box aids the progressive download - * of an ISO file. The box contains pairs of numbers (to the end of the box) - * specifying combinations of effective file download bitrate in units of - * bytes/sec and a suggested initial playback delay in units of milliseconds. - * - * A receiving party can estimate the download rate it is experiencing, and from - * that obtain an upper estimate for a suitable initial delay by linear - * interpolation between pairs, or by extrapolation from the first or last - * entry. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Pdin.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Pdin extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_progressiveDownloadInfo = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - while ($this->_reader->getOffset() < - $this->getOffset() + $this->getSize()) { - $this->_progressiveDownloadInfo[] = array - ('rate' => $this->_reader->readUInt32BE(), - 'initialDelay' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns the progressive download information array. The array consists of - * items having two keys. - * - * o rate -- the download rate expressed in bytes/second - * o initialDelay -- the suggested delay to use when playing the file, - * such that if download continues at the given rate, all data within - * the file will arrive in time for its use and playback should not need - * to stall. - * - * @return Array - */ - public function getProgressiveDownloadInfo() - { - return $this->_progressiveDownloadInfo; - } - - /** - * Sets the progressive download information array. The array must consist - * of items having two keys. - * - * o rate -- the download rate expressed in bytes/second - * o initialDelay -- the suggested delay to use when playing the file, - * such that if download continues at the given rate, all data within - * the file will arrive in time for its use and playback should not need - * to stall. - * - * @param Array $progressiveDownloadInfo The array of values. - */ - public function setProgressiveDownloadInfo($progressiveDownloadInfo) - { - $this->_progressiveDownloadInfo = $progressiveDownloadInfo; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + - count($this->_progressiveDownloadInfo) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - for ($i = 0; $i < count($this->_timeToSampleTable); $i++) { - $writer->writeUInt32BE - ($this->_progressiveDownloadInfo[$i]['rate']) - ->writeUInt32BE - ($this->_progressiveDownloadInfo[$i]['initialDelay']); - } - } -} +Progressive Download Information Box aids the progressive download + * of an ISO file. The box contains pairs of numbers (to the end of the box) + * specifying combinations of effective file download bitrate in units of + * bytes/sec and a suggested initial playback delay in units of milliseconds. + * + * A receiving party can estimate the download rate it is experiencing, and from + * that obtain an upper estimate for a suitable initial delay by linear + * interpolation between pairs, or by extrapolation from the first or last + * entry. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Pdin.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Pdin extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_progressiveDownloadInfo = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + while ($this->_reader->getOffset() < + $this->getOffset() + $this->getSize()) { + $this->_progressiveDownloadInfo[] = array + ('rate' => $this->_reader->readUInt32BE(), + 'initialDelay' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns the progressive download information array. The array consists of + * items having two keys. + * + * o rate -- the download rate expressed in bytes/second + * o initialDelay -- the suggested delay to use when playing the file, + * such that if download continues at the given rate, all data within + * the file will arrive in time for its use and playback should not need + * to stall. + * + * @return Array + */ + public function getProgressiveDownloadInfo() + { + return $this->_progressiveDownloadInfo; + } + + /** + * Sets the progressive download information array. The array must consist + * of items having two keys. + * + * o rate -- the download rate expressed in bytes/second + * o initialDelay -- the suggested delay to use when playing the file, + * such that if download continues at the given rate, all data within + * the file will arrive in time for its use and playback should not need + * to stall. + * + * @param Array $progressiveDownloadInfo The array of values. + */ + public function setProgressiveDownloadInfo($progressiveDownloadInfo) + { + $this->_progressiveDownloadInfo = $progressiveDownloadInfo; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + + count($this->_progressiveDownloadInfo) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + for ($i = 0; $i < count($this->_timeToSampleTable); $i++) { + $writer->writeUInt32BE + ($this->_progressiveDownloadInfo[$i]['rate']) + ->writeUInt32BE + ($this->_progressiveDownloadInfo[$i]['initialDelay']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Pitm.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Pitm.php index b85feb12..4c043abb 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Pitm.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Pitm.php @@ -1,116 +1,116 @@ -Primary Item - * Box must occur, or there must be a box within the meta-box (e.g. an - * {@link Zend_Media_Iso14496_Box_Xml XML Box}) containing the primary - * information in the format required by the identified handler. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Pitm.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Pitm extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_itemId; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_itemId = $this->_reader->readUInt16BE(); - } - - /** - * Returns the identifier of the primary item. - * - * @return integer - */ - public function getItemId() - { - return $this->_itemId; - } - - /** - * Sets the identifier of the primary item. - * - * @param integer $itemId The item identification. - */ - public function setItemId($itemId) - { - $this->_itemId = $itemId; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 2; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE($this->_itemId); - } -} +Primary Item + * Box must occur, or there must be a box within the meta-box (e.g. an + * {@link Zend_Media_Iso14496_Box_Xml XML Box}) containing the primary + * information in the format required by the identified handler. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Pitm.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Pitm extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_itemId; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_itemId = $this->_reader->readUInt16BE(); + } + + /** + * Returns the identifier of the primary item. + * + * @return integer + */ + public function getItemId() + { + return $this->_itemId; + } + + /** + * Sets the identifier of the primary item. + * + * @param integer $itemId The item identification. + */ + public function setItemId($itemId) + { + $this->_itemId = $itemId; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 2; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE($this->_itemId); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Pssh.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Pssh.php index 769daedf..3632bccb 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Pssh.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Pssh.php @@ -1,158 +1,158 @@ -PSSH Box contains information needed by a Content Protection - * System to play back the content. The data format is specified by the system - * identified by the ‘pssh’ parameter SystemID, and is considered opaque for the - * purposes of this specification. - * - * The data encapsulated in the Data field may be read by the identified - * Content Protection System to enable decryption key acquisition and decryption - * of media data. For license/rights-based systems, the header information may - * include data such as the URL of license server(s) or rights issuer(s) used, - * embedded licenses/rights, and/or other protection system specific metadata. - * - * A single file may be constructed to be playable by multiple key and digital - * rights management (DRM) systems, by including one Protection System Specific - * Header box for each system supported. Readers that process such presentations - * shall match the SystemID field in this box to the SystemID(s) of the DRM - * System(s) they support, and select the matching Protection System Specific - * Header box(es) for retrieval of Protection System Specific information - * interpreted or created by that DRM system. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Pssh.php 274 2012-11-28 19:03:18Z svollbehr@gmail.com $ - */ -final class Zend_Media_Iso14496_Box_Pssh extends Zend_Media_Iso14496_FullBox -{ - private $_systemId; - private $_data; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_systemId = $this->_reader->readGuid(); - $dataSize = $this->_reader->readUInt32BE(); - $this->_data = $reader->read($dataSize); - } - - /** - * Returns a UUID that uniquely identifies the content protection system - * that this header belongs to. - * - * @return string - */ - public function getSystemId() - { - return $this->_systemId; - } - - /** - * Sets a UUID that uniquely identifies the content protection system - * that this header belongs to. - * - * @param string $systemId The system ID. - */ - public function setSystemId($systemId) - { - $this->_systemId = $systemId; - } - - - /** - * Returns the content protection system specific data. - * - * @return string - */ - public function getData() - { - return $this->_data; - } - - /** - * Sets the content protection system specific data. - * - * @param string $data The data. - */ - public function setData($data) - { - $this->_data = $data; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 20 + strlen($this->_data); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeGuid($this->_systemId) - ->writeUInt32BE(strlen($this->_data)) - ->write($this->_data); - } -} +PSSH Box contains information needed by a Content Protection + * System to play back the content. The data format is specified by the system + * identified by the ‘pssh’ parameter SystemID, and is considered opaque for the + * purposes of this specification. + * + * The data encapsulated in the Data field may be read by the identified + * Content Protection System to enable decryption key acquisition and decryption + * of media data. For license/rights-based systems, the header information may + * include data such as the URL of license server(s) or rights issuer(s) used, + * embedded licenses/rights, and/or other protection system specific metadata. + * + * A single file may be constructed to be playable by multiple key and digital + * rights management (DRM) systems, by including one Protection System Specific + * Header box for each system supported. Readers that process such presentations + * shall match the SystemID field in this box to the SystemID(s) of the DRM + * System(s) they support, and select the matching Protection System Specific + * Header box(es) for retrieval of Protection System Specific information + * interpreted or created by that DRM system. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Pssh.php 274 2012-11-28 19:03:18Z svollbehr@gmail.com $ + */ +final class Zend_Media_Iso14496_Box_Pssh extends Zend_Media_Iso14496_FullBox +{ + private $_systemId; + private $_data; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_systemId = $this->_reader->readGuid(); + $dataSize = $this->_reader->readUInt32BE(); + $this->_data = $reader->read($dataSize); + } + + /** + * Returns a UUID that uniquely identifies the content protection system + * that this header belongs to. + * + * @return string + */ + public function getSystemId() + { + return $this->_systemId; + } + + /** + * Sets a UUID that uniquely identifies the content protection system + * that this header belongs to. + * + * @param string $systemId The system ID. + */ + public function setSystemId($systemId) + { + $this->_systemId = $systemId; + } + + + /** + * Returns the content protection system specific data. + * + * @return string + */ + public function getData() + { + return $this->_data; + } + + /** + * Sets the content protection system specific data. + * + * @param string $data The data. + */ + public function setData($data) + { + $this->_data = $data; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 20 + strlen($this->_data); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeGuid($this->_systemId) + ->writeUInt32BE(strlen($this->_data)) + ->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Sbgp.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Sbgp.php index 9edebe6f..44dd6e1f 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Sbgp.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Sbgp.php @@ -1,197 +1,197 @@ -Sample To Group Box table can be used to find the group that a - * sample belongs to and the associated description of that sample group. The - * table is compactly coded with each entry giving the index of the first sample - * of a run of samples with the same sample group descriptor. The sample group - * description ID is an index that refers to a - * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, which - * contains entries describing the characteristics of each sample group. - * - * There may be multiple instances of this box if there is more than one sample - * grouping for the samples in a track. Each instance of the Sample To Group Box - * has a type code that distinguishes different sample groupings. Within a - * track, there shall be at most one instance of this box with a particular - * grouping type. The associated Sample Group Description shall indicate the - * same value for the grouping type. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sbgp.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Sbgp extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_groupingType; - - /** @var Array */ - private $_sampleToGroupTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $groupingType = $this->_reader->readUInt32BE(); - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_sampleToGroupTable[$i] = array - ('sampleCount' => $this->_reader->readUInt32BE(), - 'groupDescriptionIndex' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns the grouping type that identifies the type (i.e. criterion used - * to form the sample groups) of the sample grouping and links it to its - * sample group description table with the same value for grouping type. At - * most one occurrence of this box with the same value for groupingType - * shall exist for a track. - * - * @return integer - */ - public function getGroupingType() - { - return $this->_groupingType; - } - - /** - * Sets the grouping type that identifies the type (i.e. criterion used - * to form the sample groups) of the sample grouping and links it to its - * sample group description table with the same value for grouping type. At - * most one occurrence of this box with the same value for groupingType - * shall exist for a track. - * - * @param integer $groupingType The grouping type. - */ - public function setGroupingType($groupingType) - { - $this->_groupingType = $groupingType; - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o sampleCount -- an integer that gives the number of consecutive - * samples with the same sample group descriptor. If the sum of the - * sample count in this box is less than the total sample count, then - * the reader should effectively extend it with an entry that associates - * the remaining samples with no group. It is an error for the total in - * this box to be greater than the sample_count documented elsewhere, - * and the reader behavior would then be undefined. - * o groupDescriptionIndex -- an integer that gives the index of the - * sample group entry which describes the samples in this group. The - * index ranges from 1 to the number of sample group entries in the - * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, - * or takes the value 0 to indicate that this sample is a member of no - * group of this type. - * - * @return Array - */ - public function getSampleToGroupTable() - { - return $this->_sampleToGroupTable; - } - - /** - * Sets the array of values. Each entry must be an array containing the - * following keys. - * o sampleCount -- an integer that gives the number of consecutive - * samples with the same sample group descriptor. If the sum of the - * sample count in this box is less than the total sample count, then - * the reader should effectively extend it with an entry that associates - * the remaining samples with no group. It is an error for the total in - * this box to be greater than the sample_count documented elsewhere, - * and the reader behavior would then be undefined. - * o groupDescriptionIndex -- an integer that gives the index of the - * sample group entry which describes the samples in this group. The - * index ranges from 1 to the number of sample group entries in the - * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, - * or takes the value 0 to indicate that this sample is a member of no - * group of this type. - * - * @param Array $sampleToGroupTable The array of entries - */ - public function setSampleToGroupTable($sampleToGroupTable) - { - $this->_sampleToGroupTable = $sampleToGroupTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 8 + - count($this->_sampleToGroupTable) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_groupingType); - $writer->writeUInt32BE($entryCount = count($this->_sampleToGroupTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE - ($this->_sampleToGroupTable[$i]['sampleCount']) - ->writeUInt32BE - ($this->_sampleToGroupTable[$i] - ['groupDescriptionIndex']); - } - } -} +Sample To Group Box table can be used to find the group that a + * sample belongs to and the associated description of that sample group. The + * table is compactly coded with each entry giving the index of the first sample + * of a run of samples with the same sample group descriptor. The sample group + * description ID is an index that refers to a + * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, which + * contains entries describing the characteristics of each sample group. + * + * There may be multiple instances of this box if there is more than one sample + * grouping for the samples in a track. Each instance of the Sample To Group Box + * has a type code that distinguishes different sample groupings. Within a + * track, there shall be at most one instance of this box with a particular + * grouping type. The associated Sample Group Description shall indicate the + * same value for the grouping type. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sbgp.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Sbgp extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_groupingType; + + /** @var Array */ + private $_sampleToGroupTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $groupingType = $this->_reader->readUInt32BE(); + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_sampleToGroupTable[$i] = array + ('sampleCount' => $this->_reader->readUInt32BE(), + 'groupDescriptionIndex' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns the grouping type that identifies the type (i.e. criterion used + * to form the sample groups) of the sample grouping and links it to its + * sample group description table with the same value for grouping type. At + * most one occurrence of this box with the same value for groupingType + * shall exist for a track. + * + * @return integer + */ + public function getGroupingType() + { + return $this->_groupingType; + } + + /** + * Sets the grouping type that identifies the type (i.e. criterion used + * to form the sample groups) of the sample grouping and links it to its + * sample group description table with the same value for grouping type. At + * most one occurrence of this box with the same value for groupingType + * shall exist for a track. + * + * @param integer $groupingType The grouping type. + */ + public function setGroupingType($groupingType) + { + $this->_groupingType = $groupingType; + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o sampleCount -- an integer that gives the number of consecutive + * samples with the same sample group descriptor. If the sum of the + * sample count in this box is less than the total sample count, then + * the reader should effectively extend it with an entry that associates + * the remaining samples with no group. It is an error for the total in + * this box to be greater than the sample_count documented elsewhere, + * and the reader behavior would then be undefined. + * o groupDescriptionIndex -- an integer that gives the index of the + * sample group entry which describes the samples in this group. The + * index ranges from 1 to the number of sample group entries in the + * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, + * or takes the value 0 to indicate that this sample is a member of no + * group of this type. + * + * @return Array + */ + public function getSampleToGroupTable() + { + return $this->_sampleToGroupTable; + } + + /** + * Sets the array of values. Each entry must be an array containing the + * following keys. + * o sampleCount -- an integer that gives the number of consecutive + * samples with the same sample group descriptor. If the sum of the + * sample count in this box is less than the total sample count, then + * the reader should effectively extend it with an entry that associates + * the remaining samples with no group. It is an error for the total in + * this box to be greater than the sample_count documented elsewhere, + * and the reader behavior would then be undefined. + * o groupDescriptionIndex -- an integer that gives the index of the + * sample group entry which describes the samples in this group. The + * index ranges from 1 to the number of sample group entries in the + * {@link Zend_Media_Iso14496_Box_Sgpd Sample Group Description Box}, + * or takes the value 0 to indicate that this sample is a member of no + * group of this type. + * + * @param Array $sampleToGroupTable The array of entries + */ + public function setSampleToGroupTable($sampleToGroupTable) + { + $this->_sampleToGroupTable = $sampleToGroupTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 8 + + count($this->_sampleToGroupTable) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_groupingType); + $writer->writeUInt32BE($entryCount = count($this->_sampleToGroupTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE + ($this->_sampleToGroupTable[$i]['sampleCount']) + ->writeUInt32BE + ($this->_sampleToGroupTable[$i] + ['groupDescriptionIndex']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Schi.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Schi.php index dc50857d..5f919829 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Schi.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Schi.php @@ -1,74 +1,74 @@ -Scheme Information Box is a container Box that is only interpreted - * by the scheme being used. Any information the encryption system needs is - * stored here. The content of this box is a series of boxes whose type and - * format are defined by the scheme declared in the - * {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Schi.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Schi extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Scheme Information Box is a container Box that is only interpreted + * by the scheme being used. Any information the encryption system needs is + * stored here. The content of this box is a series of boxes whose type and + * format are defined by the scheme declared in the + * {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Schi.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Schi extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Schm.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Schm.php index 40d691a1..bd0f1883 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Schm.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Schm.php @@ -1,177 +1,177 @@ -Scheme Type Box identifies the protection scheme. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Schm.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Schm extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_schemeType; - - /** @var integer */ - private $_schemeVersion; - - /** @var string */ - private $_schemeUri; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_schemeType = $this->_reader->read(4); - $this->_schemeVersion = $this->_reader->readUInt32BE(); - if ($this->hasFlag(1)) { - $this->_schemeUri = preg_split - ("/\\x00/", $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset())); - } - } - - /** - * Returns the code defining the protection scheme. - * - * @return string - */ - public function getSchemeType() - { - return $this->_schemeType; - } - - /** - * Sets the code defining the protection scheme. - * - * @param string $schemeType The scheme type. - */ - public function setSchemeType($schemeType) - { - $this->_schemeType = $schemeType; - } - - /** - * Returns the version of the scheme used to create the content. - * - * @return integer - */ - public function getSchemeVersion() - { - return $this->_schemeVersion; - } - - /** - * Sets the version of the scheme used to create the content. - * - * @param integer $schemeVersion The scheme version. - */ - public function setSchemeVersion($schemeVersion) - { - $this->_schemeVersion = $schemeVersion; - } - - /** - * Returns the optional scheme address to allow for the option of directing - * the user to a web-page if they do not have the scheme installed on their - * system. It is an absolute URI. - * - * @return string - */ - public function getSchemeUri() - { - return $this->_schemeUri; - } - - /** - * Sets the optional scheme address to allow for the option of directing - * the user to a web-page if they do not have the scheme installed on their - * system. It is an absolute URI. - * - * @param string $schemeUri The scheme URI. - */ - public function setSchemeUri($schemeUri) - { - $this->_schemeUri = $schemeUri; - if ($schemeUri === null) { - $this->setFlags(0); - } else { - $this->setFlags(1); - } - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 8 + - ($this->hasFlag(1) ? strlen($this->_schemeUri) + 1 : 0); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_schemeType); - $writer->writeUInt32BE($this->_schemeVersion); - if ($this->hasFlag(1)) { - $writer->writeString8($this->_schemeUri, 1); - } - } -} +Scheme Type Box identifies the protection scheme. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Schm.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Schm extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_schemeType; + + /** @var integer */ + private $_schemeVersion; + + /** @var string */ + private $_schemeUri; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_schemeType = $this->_reader->read(4); + $this->_schemeVersion = $this->_reader->readUInt32BE(); + if ($this->hasFlag(1)) { + $this->_schemeUri = preg_split + ("/\\x00/", $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset())); + } + } + + /** + * Returns the code defining the protection scheme. + * + * @return string + */ + public function getSchemeType() + { + return $this->_schemeType; + } + + /** + * Sets the code defining the protection scheme. + * + * @param string $schemeType The scheme type. + */ + public function setSchemeType($schemeType) + { + $this->_schemeType = $schemeType; + } + + /** + * Returns the version of the scheme used to create the content. + * + * @return integer + */ + public function getSchemeVersion() + { + return $this->_schemeVersion; + } + + /** + * Sets the version of the scheme used to create the content. + * + * @param integer $schemeVersion The scheme version. + */ + public function setSchemeVersion($schemeVersion) + { + $this->_schemeVersion = $schemeVersion; + } + + /** + * Returns the optional scheme address to allow for the option of directing + * the user to a web-page if they do not have the scheme installed on their + * system. It is an absolute URI. + * + * @return string + */ + public function getSchemeUri() + { + return $this->_schemeUri; + } + + /** + * Sets the optional scheme address to allow for the option of directing + * the user to a web-page if they do not have the scheme installed on their + * system. It is an absolute URI. + * + * @param string $schemeUri The scheme URI. + */ + public function setSchemeUri($schemeUri) + { + $this->_schemeUri = $schemeUri; + if ($schemeUri === null) { + $this->setFlags(0); + } else { + $this->setFlags(1); + } + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 8 + + ($this->hasFlag(1) ? strlen($this->_schemeUri) + 1 : 0); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_schemeType); + $writer->writeUInt32BE($this->_schemeVersion); + if ($this->hasFlag(1)) { + $writer->writeString8($this->_schemeUri, 1); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Sdtp.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Sdtp.php index 0b2e3055..d346e744 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Sdtp.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Sdtp.php @@ -1,187 +1,187 @@ -Independent and Disposable Samples Box optional table answers - * three questions about sample dependency: - * 1) does this sample depend on others (is it an I-picture)? - * 2) do no other samples depend on this one? - * 3) does this sample contain multiple (redundant) encodings of the data at - * this time-instant (possibly with different dependencies)? - * - * In the absence of this table: - * 1) the sync sample table answers the first question; in most video codecs, - * I-pictures are also sync points, - * 2) the dependency of other samples on this one is unknown. - * 3) the existence of redundant coding is unknown. - * - * When performing trick modes, such as fast-forward, it is possible to use the - * first piece of information to locate independently decodable samples. - * Similarly, when performing random access, it may be necessary to locate the - * previous sync point or random access recovery point, and roll-forward from - * the sync point or the pre-roll starting point of the random access recovery - * point to the desired point. While rolling forward, samples on which no others - * depend need not be retrieved or decoded. - * - - * The value of sampleIsDependedOn is independent of the existence of redundant - * codings. However, a redundant coding may have different dependencies from the - * primary coding; if redundant codings are available, the value of - * sampleDependsOn documents only the primary coding. - * - * A sample dependency Box may also occur in the - * {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sdtp.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Sdtp extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_sampleDependencyTypeTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $data = $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - $dataSize = strlen($data); - for ($i = 1; $i <= $dataSize; $i++) { - $this->_sampleDependencyTypeTable[$i] = array - ('sampleDependsOn' => (($tmp = ord($data[$i - 1])) >> 4) & 0x3, - 'sampleIsDependedOn' => ($tmp >> 2) & 0x3, - 'sampleHasRedundancy' => $tmp & 0x3); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o sampleDependsOn -- takes one of the following four values: - * 0: the dependency of this sample is unknown; - * 1: this sample does depend on others (not an I picture); - * 2: this sample does not depend on others (I picture); - * 3: reserved - * o sampleIsDependedOn -- takes one of the following four values: - * 0: the dependency of other samples on this sample is unknown; - * 1: other samples depend on this one (not disposable); - * 2: no other sample depends on this one (disposable); - * 3: reserved - * o sampleHasRedundancy -- takes one of the following four values: - * 0: it is unknown whether there is redundant coding in this sample; - * 1: there is redundant coding in this sample; - * 2: there is no redundant coding in this sample; - * 3: reserved - * - * @return Array - */ - public function getSampleDependencyTypeTable() - { - return $this->_sampleDependencyTypeTable; - } - - /** - * Sets the array of values. Each entry must be an array containing the - * following keys. - * o sampleDependsOn -- takes one of the following four values: - * 0: the dependency of this sample is unknown; - * 1: this sample does depend on others (not an I picture); - * 2: this sample does not depend on others (I picture); - * 3: reserved - * o sampleIsDependedOn -- takes one of the following four values: - * 0: the dependency of other samples on this sample is unknown; - * 1: other samples depend on this one (not disposable); - * 2: no other sample depends on this one (disposable); - * 3: reserved - * o sampleHasRedundancy -- takes one of the following four values: - * 0: it is unknown whether there is redundant coding in this sample; - * 1: there is redundant coding in this sample; - * 2: there is no redundant coding in this sample; - * 3: reserved - * - * @param Array $sampleDependencyTypeTable The array of values - */ - public function setSampleDependencyTypeTable($sampleDependencyTypeTable) - { - $this->_sampleDependencyTypeTable = $sampleDependencyTypeTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + count($this->_sampleDependencyTypeTable); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - for ($i = 1; $i <= count($this->_sampleDependencyTypeTable); $i++) { - $writer->write(chr( - (($this->_sampleDependencyTypeTable[$i] - ['sampleDependsOn'] & 0x3) << 4) | - (($this->_sampleDependencyTypeTable[$i] - ['sampleIsDependedOn'] & 0x3) << 2) | - (($this->_sampleDependencyTypeTable[$i] - ['sampleHasRedundancy'] & 0x3)))); - } - } -} +Independent and Disposable Samples Box optional table answers + * three questions about sample dependency: + * 1) does this sample depend on others (is it an I-picture)? + * 2) do no other samples depend on this one? + * 3) does this sample contain multiple (redundant) encodings of the data at + * this time-instant (possibly with different dependencies)? + * + * In the absence of this table: + * 1) the sync sample table answers the first question; in most video codecs, + * I-pictures are also sync points, + * 2) the dependency of other samples on this one is unknown. + * 3) the existence of redundant coding is unknown. + * + * When performing trick modes, such as fast-forward, it is possible to use the + * first piece of information to locate independently decodable samples. + * Similarly, when performing random access, it may be necessary to locate the + * previous sync point or random access recovery point, and roll-forward from + * the sync point or the pre-roll starting point of the random access recovery + * point to the desired point. While rolling forward, samples on which no others + * depend need not be retrieved or decoded. + * + + * The value of sampleIsDependedOn is independent of the existence of redundant + * codings. However, a redundant coding may have different dependencies from the + * primary coding; if redundant codings are available, the value of + * sampleDependsOn documents only the primary coding. + * + * A sample dependency Box may also occur in the + * {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sdtp.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Sdtp extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_sampleDependencyTypeTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $data = $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + $dataSize = strlen($data); + for ($i = 1; $i <= $dataSize; $i++) { + $this->_sampleDependencyTypeTable[$i] = array + ('sampleDependsOn' => (($tmp = ord($data[$i - 1])) >> 4) & 0x3, + 'sampleIsDependedOn' => ($tmp >> 2) & 0x3, + 'sampleHasRedundancy' => $tmp & 0x3); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o sampleDependsOn -- takes one of the following four values: + * 0: the dependency of this sample is unknown; + * 1: this sample does depend on others (not an I picture); + * 2: this sample does not depend on others (I picture); + * 3: reserved + * o sampleIsDependedOn -- takes one of the following four values: + * 0: the dependency of other samples on this sample is unknown; + * 1: other samples depend on this one (not disposable); + * 2: no other sample depends on this one (disposable); + * 3: reserved + * o sampleHasRedundancy -- takes one of the following four values: + * 0: it is unknown whether there is redundant coding in this sample; + * 1: there is redundant coding in this sample; + * 2: there is no redundant coding in this sample; + * 3: reserved + * + * @return Array + */ + public function getSampleDependencyTypeTable() + { + return $this->_sampleDependencyTypeTable; + } + + /** + * Sets the array of values. Each entry must be an array containing the + * following keys. + * o sampleDependsOn -- takes one of the following four values: + * 0: the dependency of this sample is unknown; + * 1: this sample does depend on others (not an I picture); + * 2: this sample does not depend on others (I picture); + * 3: reserved + * o sampleIsDependedOn -- takes one of the following four values: + * 0: the dependency of other samples on this sample is unknown; + * 1: other samples depend on this one (not disposable); + * 2: no other sample depends on this one (disposable); + * 3: reserved + * o sampleHasRedundancy -- takes one of the following four values: + * 0: it is unknown whether there is redundant coding in this sample; + * 1: there is redundant coding in this sample; + * 2: there is no redundant coding in this sample; + * 3: reserved + * + * @param Array $sampleDependencyTypeTable The array of values + */ + public function setSampleDependencyTypeTable($sampleDependencyTypeTable) + { + $this->_sampleDependencyTypeTable = $sampleDependencyTypeTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + count($this->_sampleDependencyTypeTable); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + for ($i = 1; $i <= count($this->_sampleDependencyTypeTable); $i++) { + $writer->write(chr( + (($this->_sampleDependencyTypeTable[$i] + ['sampleDependsOn'] & 0x3) << 4) | + (($this->_sampleDependencyTypeTable[$i] + ['sampleIsDependedOn'] & 0x3) << 2) | + (($this->_sampleDependencyTypeTable[$i] + ['sampleHasRedundancy'] & 0x3)))); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Sinf.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Sinf.php index d376f922..9177ad31 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Sinf.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Sinf.php @@ -1,87 +1,87 @@ -Protection Scheme Information Box contains all the information - * required both to understand the encryption transform applied and its - * parameters, and also to find other information such as the kind and location - * of the key management system. It also documents the original (unencrypted) - * format of the media. The Protection Scheme Info Box is a container Box. It is - * mandatory in a sample entry that uses a code indicating a protected stream. - * - * When used in a protected sample entry, this box must contain the original - * format box to document the original format. At least one of the following - * signaling methods must be used to identify the protection applied: - * - * a) MPEG-4 systems with IPMP: no other boxes, when IPMP descriptors in MPEG-4 - * systems streams are used; - * b) Standalone IPMP: an {@link Zend_Media_Iso14496_Box_Imif IPMP Info Box}, - * when IPMP descriptors outside MPEG-4 systems are used; - * c) Scheme signaling: a {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box} - * and {@link Zend_Media_Iso14496_Box_Schi Scheme Information Box}, when - * these are used (either both must occur, or neither). - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Sinf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Sinf extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Protection Scheme Information Box contains all the information + * required both to understand the encryption transform applied and its + * parameters, and also to find other information such as the kind and location + * of the key management system. It also documents the original (unencrypted) + * format of the media. The Protection Scheme Info Box is a container Box. It is + * mandatory in a sample entry that uses a code indicating a protected stream. + * + * When used in a protected sample entry, this box must contain the original + * format box to document the original format. At least one of the following + * signaling methods must be used to identify the protection applied: + * + * a) MPEG-4 systems with IPMP: no other boxes, when IPMP descriptors in MPEG-4 + * systems streams are used; + * b) Standalone IPMP: an {@link Zend_Media_Iso14496_Box_Imif IPMP Info Box}, + * when IPMP descriptors outside MPEG-4 systems are used; + * c) Scheme signaling: a {@link Zend_Media_Iso14496_Box_Schm Scheme Type Box} + * and {@link Zend_Media_Iso14496_Box_Schi Scheme Information Box}, when + * these are used (either both must occur, or neither). + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Sinf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Sinf extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Skip.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Skip.php index f38d51fb..cf43ca5f 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Skip.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Skip.php @@ -1,73 +1,73 @@ -Free Space Box are irrelevant and may be ignored, or - * the object deleted, without affecting the presentation. (Care should be - * exercised when deleting the object, as this may invalidate the offsets used - * in the sample table, unless this object is after all the media data). - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Skip.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Skip extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Free Space Box are irrelevant and may be ignored, or + * the object deleted, without affecting the presentation. (Care should be + * exercised when deleting the object, as this may invalidate the offsets used + * in the sample table, unless this object is after all the media data). + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Skip.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Skip extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Smhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Smhd.php index 70a4d59a..5de90872 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Smhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Smhd.php @@ -1,123 +1,123 @@ -Sound Media Header Box contains general presentation information, - * independent of the coding, for audio media. This header is used for all - * tracks containing audio. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Smhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Smhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_balance = 0; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_balance = - ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + - (float)("0." . ((string)($tmp & 0xff))); - $this->_reader->skip(2); - } - - /** - * Returns the number that places mono audio tracks in a stereo space; 0 is - * center (the normal value); full left is -1.0 and full right is 1.0. - * - * @return integer - */ - public function getBalance() - { - return $this->_balance; - } - - /** - * Sets the number that places mono audio tracks in a stereo space; 0 is - * center (the normal value); full left is -1.0 and full right is 1.0. - * - * @param integer $balance The balance. - */ - public function setBalance($balance) - { - $this->_balance = $balance; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - @list(, $balanceDecimals) = explode('.', (float)$this->_balance); - $writer->writeInt16BE(floor($this->_balance) << 8 | $balanceDecimals) - ->writeInt16BE(0); - } -} +Sound Media Header Box contains general presentation information, + * independent of the coding, for audio media. This header is used for all + * tracks containing audio. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Smhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Smhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_balance = 0; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_balance = + ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + + (float)("0." . ((string)($tmp & 0xff))); + $this->_reader->skip(2); + } + + /** + * Returns the number that places mono audio tracks in a stereo space; 0 is + * center (the normal value); full left is -1.0 and full right is 1.0. + * + * @return integer + */ + public function getBalance() + { + return $this->_balance; + } + + /** + * Sets the number that places mono audio tracks in a stereo space; 0 is + * center (the normal value); full left is -1.0 and full right is 1.0. + * + * @param integer $balance The balance. + */ + public function setBalance($balance) + { + $this->_balance = $balance; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + @list(, $balanceDecimals) = explode('.', (float)$this->_balance); + $writer->writeInt16BE(floor($this->_balance) << 8 | $balanceDecimals) + ->writeInt16BE(0); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stbl.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stbl.php index daba64c6..e0483f3c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stbl.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stbl.php @@ -1,92 +1,92 @@ -Sample Table Box contains all the time and data indexing of the - * media samples in a track. Using the tables here, it is possible to locate - * samples in time, determine their type (e.g. I-frame or not), and determine - * their size, container, and offset into that container. - * - * If the track that contains the Sample Table Box references no data, then the - * Sample Table Box does not need to contain any sub-boxes (this is not a very - * useful media track). - * - * If the track that the Sample Table Box is contained in does reference data, - * then the following sub-boxes are required: - * {@link Zend_Media_Iso14496_Box_Stsd Sample Description}, - * {@link Zend_Media_Iso14496_Box_Stsz Sample Size}, - * {@link Zend_Media_Iso14496_Box_Stsc Sample To Chunk}, and - * {@link Zend_Media_Iso14496_Box_Stco Chunk Offset}. Further, the - * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box} shall contain at - * least one entry. A Sample Description Box is required because it contains - * the data reference index field which indicates which - * {@link Zend_Media_Iso14496_Box_Dref Data Reference Box} to use to retrieve - * the media samples. Without the Sample Description, it is not possible to - * determine where the media samples are stored. The - * {@link Zend_Media_Iso14496_Box_Stss Sync Sample Box} is optional. If the - * Sync Sample Box is not present, all samples are sync samples. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stbl.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stbl extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Sample Table Box contains all the time and data indexing of the + * media samples in a track. Using the tables here, it is possible to locate + * samples in time, determine their type (e.g. I-frame or not), and determine + * their size, container, and offset into that container. + * + * If the track that contains the Sample Table Box references no data, then the + * Sample Table Box does not need to contain any sub-boxes (this is not a very + * useful media track). + * + * If the track that the Sample Table Box is contained in does reference data, + * then the following sub-boxes are required: + * {@link Zend_Media_Iso14496_Box_Stsd Sample Description}, + * {@link Zend_Media_Iso14496_Box_Stsz Sample Size}, + * {@link Zend_Media_Iso14496_Box_Stsc Sample To Chunk}, and + * {@link Zend_Media_Iso14496_Box_Stco Chunk Offset}. Further, the + * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box} shall contain at + * least one entry. A Sample Description Box is required because it contains + * the data reference index field which indicates which + * {@link Zend_Media_Iso14496_Box_Dref Data Reference Box} to use to retrieve + * the media samples. Without the Sample Description, it is not possible to + * determine where the media samples are stored. The + * {@link Zend_Media_Iso14496_Box_Stss Sync Sample Box} is optional. If the + * Sync Sample Box is not present, all samples are sync samples. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stbl.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stbl extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stco.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stco.php index 2b3142a5..77f3bdaf 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stco.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stco.php @@ -1,134 +1,134 @@ -Chunk Offset Box table gives the index of each chunk into the - * containing file. There are two variants, permitting the use of 32-bit or - * 64-bit offsets. The latter is useful when managing very large presentations. - * At most one of these variants will occur in any single instance of a sample - * table. - * - * Offsets are file offsets, not the offset into any box within the file (e.g. - * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}). This permits referring - * to media data in files without any box structure. It does also mean that care - * must be taken when constructing a self-contained ISO file with its metadata - * ({@link Zend_Media_Iso14496_Box_Moov Movie Box}) at the front, as the size of - * the {@link Zend_Media_Iso14496_Box_Moov Movie Box} will affect the chunk - * offsets to the media data. - * - * This box variant contains 32-bit offsets. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stco.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stco extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_chunkOffsetTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_chunkOffsetTable[$i] = $reader->readUInt32BE(); - } - } - - /** - * Returns an array of values. Each entry has the entry number as its index - * and a 32 bit integer that gives the offset of the start of a chunk into - * its containing media file as its value. - * - * @return Array - */ - public function getChunkOffsetTable() - { - return $this->_chunkOffsetTable; - } - - /** - * Sets an array of chunk offsets. Each entry must have the entry number as - * its index and a 32 bit integer that gives the offset of the start of a - * chunk into its containing media file as its value. - * - * @param Array $chunkOffsetTable The chunk offset array. - */ - public function setChunkOffsetTable($chunkOffsetTable) - { - $this->_chunkOffsetTable = $chunkOffsetTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + count($this->_chunkOffsetTable) * 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_chunkOffsetTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE($this->_chunkOffsetTable[$i]); - } - } -} +Chunk Offset Box table gives the index of each chunk into the + * containing file. There are two variants, permitting the use of 32-bit or + * 64-bit offsets. The latter is useful when managing very large presentations. + * At most one of these variants will occur in any single instance of a sample + * table. + * + * Offsets are file offsets, not the offset into any box within the file (e.g. + * {@link Zend_Media_Iso14496_Box_Mdat Media Data Box}). This permits referring + * to media data in files without any box structure. It does also mean that care + * must be taken when constructing a self-contained ISO file with its metadata + * ({@link Zend_Media_Iso14496_Box_Moov Movie Box}) at the front, as the size of + * the {@link Zend_Media_Iso14496_Box_Moov Movie Box} will affect the chunk + * offsets to the media data. + * + * This box variant contains 32-bit offsets. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stco.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stco extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_chunkOffsetTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_chunkOffsetTable[$i] = $reader->readUInt32BE(); + } + } + + /** + * Returns an array of values. Each entry has the entry number as its index + * and a 32 bit integer that gives the offset of the start of a chunk into + * its containing media file as its value. + * + * @return Array + */ + public function getChunkOffsetTable() + { + return $this->_chunkOffsetTable; + } + + /** + * Sets an array of chunk offsets. Each entry must have the entry number as + * its index and a 32 bit integer that gives the offset of the start of a + * chunk into its containing media file as its value. + * + * @param Array $chunkOffsetTable The chunk offset array. + */ + public function setChunkOffsetTable($chunkOffsetTable) + { + $this->_chunkOffsetTable = $chunkOffsetTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + count($this->_chunkOffsetTable) * 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_chunkOffsetTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE($this->_chunkOffsetTable[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stdp.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stdp.php index d390e067..8cbe76b4 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stdp.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stdp.php @@ -1,122 +1,122 @@ -Degradation Priority Box contains the degradation priority of each - * sample. Specifications derived from this define the exact meaning and - * acceptable range of the priority field. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stdp.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stdp extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_values = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - while ($this->_reader->getOffset() < - $this->getOffset() + $this->getSize()) { - $this->_values[] = array - ('priority' => $this->_reader->readUInt16BE()); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o priority: specifies the degradation priority for each sample segment. - * - * @return Array - */ - public function getValues() - { - return $this->_values; - } - - /** - * Sets an array of values. Each entry must have an array containing the - * following keys. - * o priority: specifies the degradation priority for each sample segment. - * - * @param Array $values The array of values. - */ - public function setValues($values) - { - $this->_values = $values; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + count($this->_values) * 2; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - for ($i = 0; $i < count($this->_values); $i++) { - $writer->writeUInt16BE($this->_values[$i]['priority']); - } - } -} +Degradation Priority Box contains the degradation priority of each + * sample. Specifications derived from this define the exact meaning and + * acceptable range of the priority field. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stdp.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stdp extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_values = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + while ($this->_reader->getOffset() < + $this->getOffset() + $this->getSize()) { + $this->_values[] = array + ('priority' => $this->_reader->readUInt16BE()); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o priority: specifies the degradation priority for each sample segment. + * + * @return Array + */ + public function getValues() + { + return $this->_values; + } + + /** + * Sets an array of values. Each entry must have an array containing the + * following keys. + * o priority: specifies the degradation priority for each sample segment. + * + * @param Array $values The array of values. + */ + public function setValues($values) + { + $this->_values = $values; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + count($this->_values) * 2; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + for ($i = 0; $i < count($this->_values); $i++) { + $writer->writeUInt16BE($this->_values[$i]['priority']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsc.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsc.php index 6b8a1730..1e8eeec0 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsc.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsc.php @@ -1,161 +1,161 @@ -Sample To Chunk Box table can be used to find the chunk that - * contains a sample, its position, and the associated sample description. - * - * The table is compactly coded. Each entry gives the index of the first chunk - * of a run of chunks with the same characteristics. By subtracting one entry - * here from the previous one, you can compute how many chunks are in this run. - * You can convert this to a sample count by multiplying by the appropriate - * samplesPerChunk. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stsc.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stsc extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_sampleToChunkTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_sampleToChunkTable[$i] = array - ('firstChunk' => $this->_reader->readUInt32BE(), - 'samplesPerChunk' => $this->_reader->readUInt32BE(), - 'sampleDescriptionIndex' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o firstChunk -- an integer that gives the index of the first chunk in - * this run of chunks that share the same samplesPerChunk and - * sampleDescriptionIndex; the index of the first chunk in a track has - * the value 1 (the firstChunk field in the first record of this box - * has the value 1, identifying that the first sample maps to the first - * chunk). - * o samplesPerChunk is an integer that gives the number of samples in - * each of these chunks. - * o sampleDescriptionIndex is an integer that gives the index of the - * sample entry that describes the samples in this chunk. The index - * ranges from 1 to the number of sample entries in the - * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box}. - * - * @return Array - */ - public function getSampleToChunkTable() - { - return $this->_sampleToChunkTable; - } - - /** - * Sets an array of values. Each entry is an array containing the - * following keys. - * o firstChunk -- an integer that gives the index of the first chunk in - * this run of chunks that share the same samplesPerChunk and - * sampleDescriptionIndex; the index of the first chunk in a track has - * the value 1 (the firstChunk field in the first record of this box - * has the value 1, identifying that the first sample maps to the first - * chunk). - * o samplesPerChunk is an integer that gives the number of samples in - * each of these chunks. - * o sampleDescriptionIndex is an integer that gives the index of the - * sample entry that describes the samples in this chunk. The index - * ranges from 1 to the number of sample entries in the - * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box}. - * - * @param Array $sampleToChunkTable The array of values. - */ - public function setSampleToChunkTable($sampleToChunkTable) - { - $this->_sampleToChunkTable = $sampleToChunkTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + - count($this->_sampleToChunkTable) * 12; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_sampleToChunkTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE - ($this->_sampleToChunkTable[$i]['firstChunk']) - ->writeUInt32BE - ($this->_sampleToChunkTable[$i]['samplesPerChunk']) - ->writeUInt32BE - ($this->_sampleToChunkTable[$i] - ['sampleDescriptionIndex']); - } - } -} +Sample To Chunk Box table can be used to find the chunk that + * contains a sample, its position, and the associated sample description. + * + * The table is compactly coded. Each entry gives the index of the first chunk + * of a run of chunks with the same characteristics. By subtracting one entry + * here from the previous one, you can compute how many chunks are in this run. + * You can convert this to a sample count by multiplying by the appropriate + * samplesPerChunk. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stsc.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stsc extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_sampleToChunkTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_sampleToChunkTable[$i] = array + ('firstChunk' => $this->_reader->readUInt32BE(), + 'samplesPerChunk' => $this->_reader->readUInt32BE(), + 'sampleDescriptionIndex' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o firstChunk -- an integer that gives the index of the first chunk in + * this run of chunks that share the same samplesPerChunk and + * sampleDescriptionIndex; the index of the first chunk in a track has + * the value 1 (the firstChunk field in the first record of this box + * has the value 1, identifying that the first sample maps to the first + * chunk). + * o samplesPerChunk is an integer that gives the number of samples in + * each of these chunks. + * o sampleDescriptionIndex is an integer that gives the index of the + * sample entry that describes the samples in this chunk. The index + * ranges from 1 to the number of sample entries in the + * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box}. + * + * @return Array + */ + public function getSampleToChunkTable() + { + return $this->_sampleToChunkTable; + } + + /** + * Sets an array of values. Each entry is an array containing the + * following keys. + * o firstChunk -- an integer that gives the index of the first chunk in + * this run of chunks that share the same samplesPerChunk and + * sampleDescriptionIndex; the index of the first chunk in a track has + * the value 1 (the firstChunk field in the first record of this box + * has the value 1, identifying that the first sample maps to the first + * chunk). + * o samplesPerChunk is an integer that gives the number of samples in + * each of these chunks. + * o sampleDescriptionIndex is an integer that gives the index of the + * sample entry that describes the samples in this chunk. The index + * ranges from 1 to the number of sample entries in the + * {@link Zend_Media_Iso14496_Box_Stsd Sample Description Box}. + * + * @param Array $sampleToChunkTable The array of values. + */ + public function setSampleToChunkTable($sampleToChunkTable) + { + $this->_sampleToChunkTable = $sampleToChunkTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + + count($this->_sampleToChunkTable) * 12; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_sampleToChunkTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE + ($this->_sampleToChunkTable[$i]['firstChunk']) + ->writeUInt32BE + ($this->_sampleToChunkTable[$i]['samplesPerChunk']) + ->writeUInt32BE + ($this->_sampleToChunkTable[$i] + ['sampleDescriptionIndex']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsd.php index 36b96e09..2ec960a3 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsd.php @@ -1,91 +1,91 @@ -Sample Description Box table gives detailed information about the - * coding type used, and any initialization information needed for that coding. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stsd.php 177 2010-03-09 13:13:34Z svollbehr $ - * @todo Implementation - */ -final class Zend_Media_Iso14496_Box_Stsd extends Zend_Media_Iso14496_FullBox -{ - private $_data; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_data = $reader->read($this->getSize() - 12); - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + $this->getSize() - 12; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_data); - } -} +Sample Description Box table gives detailed information about the + * coding type used, and any initialization information needed for that coding. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stsd.php 177 2010-03-09 13:13:34Z svollbehr $ + * @todo Implementation + */ +final class Zend_Media_Iso14496_Box_Stsd extends Zend_Media_Iso14496_FullBox +{ + private $_data; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_data = $reader->read($this->getSize() - 12); + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + $this->getSize() - 12; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_data); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsh.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsh.php index c974deb0..393bae97 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsh.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsh.php @@ -1,158 +1,158 @@ -Shadow Sync Sample Box table provides an optional set of sync - * samples that can be used when seeking or for similar purposes. In normal - * forward play they are ignored. - * - * Each entry in the Shadow Sync Table consists of a pair of sample numbers. The - * first entry (shadowedSampleNumber) indicates the number of the sample that a - * shadow sync will be defined for. This should always be a non-sync sample - * (e.g. a frame difference). The second sample number (syncSampleNumber) - * indicates the sample number of the sync sample (i.e. key frame) that can be - * used when there is a random access at, or before, the shadowedSampleNumber. - * - * The shadow sync samples are normally placed in an area of the track that is - * not presented during normal play (edited out by means of an edit list), - * though this is not a requirement. The shadow sync table can be ignored and - * the track will play (and seek) correctly if it is ignored (though perhaps not - * optimally). - * - * The Shadow Sync Sample replaces, not augments, the sample that it shadows - * (i.e. the next sample sent is shadowedSampleNumber+1). The shadow sync sample - * is treated as if it occurred at the time of the sample it shadows, having the - * duration of the sample it shadows. - * - * Hinting and transmission might become more complex if a shadow sample is used - * also as part of normal playback, or is used more than once as a shadow. In - * this case the hint track might need separate shadow syncs, all of which can - * get their media data from the one shadow sync in the media track, to allow - * for the different time-stamps etc. needed in their headers. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stsh.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stsh extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_shadowSyncSampleTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 0; $i < $entryCount; $i++) { - $this->_shadowSyncSampleTable[$i] = array - ('shadowedSampleNumber' => $this->_reader->readUInt32BE(), - 'syncSampleNumber' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o shadowedSampleNumber - gives the number of a sample for which there - * is an alternative sync sample. - * o syncSampleNumber - gives the number of the alternative sync sample. - * - * @return Array - */ - public function getShadowSyncSampleTable() - { - return $this->_shadowSyncSampleTable; - } - - /** - * Sets an array of values. Each entry must be an array containing the - * following keys. - * o shadowedSampleNumber - gives the number of a sample for which there - * is an alternative sync sample. - * o syncSampleNumber - gives the number of the alternative sync sample. - * - * @param Array $shadowSyncSampleTable The array of values. - */ - public function setShadowSyncSampleTable($shadowSyncSampleTable) - { - $this->_shadowSyncSampleTable = $shadowSyncSampleTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + - count($this->_shadowSyncSampleTable) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE - ($entryCount = count($this->_shadowSyncSampleTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE - ($this->_shadowSyncSampleTable[$i] - ['shadowedSampleNumber']) - ->writeUInt32BE - ($this->_shadowSyncSampleTable[$i]['syncSampleNumber']); - } - } -} +Shadow Sync Sample Box table provides an optional set of sync + * samples that can be used when seeking or for similar purposes. In normal + * forward play they are ignored. + * + * Each entry in the Shadow Sync Table consists of a pair of sample numbers. The + * first entry (shadowedSampleNumber) indicates the number of the sample that a + * shadow sync will be defined for. This should always be a non-sync sample + * (e.g. a frame difference). The second sample number (syncSampleNumber) + * indicates the sample number of the sync sample (i.e. key frame) that can be + * used when there is a random access at, or before, the shadowedSampleNumber. + * + * The shadow sync samples are normally placed in an area of the track that is + * not presented during normal play (edited out by means of an edit list), + * though this is not a requirement. The shadow sync table can be ignored and + * the track will play (and seek) correctly if it is ignored (though perhaps not + * optimally). + * + * The Shadow Sync Sample replaces, not augments, the sample that it shadows + * (i.e. the next sample sent is shadowedSampleNumber+1). The shadow sync sample + * is treated as if it occurred at the time of the sample it shadows, having the + * duration of the sample it shadows. + * + * Hinting and transmission might become more complex if a shadow sample is used + * also as part of normal playback, or is used more than once as a shadow. In + * this case the hint track might need separate shadow syncs, all of which can + * get their media data from the one shadow sync in the media track, to allow + * for the different time-stamps etc. needed in their headers. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stsh.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stsh extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_shadowSyncSampleTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 0; $i < $entryCount; $i++) { + $this->_shadowSyncSampleTable[$i] = array + ('shadowedSampleNumber' => $this->_reader->readUInt32BE(), + 'syncSampleNumber' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o shadowedSampleNumber - gives the number of a sample for which there + * is an alternative sync sample. + * o syncSampleNumber - gives the number of the alternative sync sample. + * + * @return Array + */ + public function getShadowSyncSampleTable() + { + return $this->_shadowSyncSampleTable; + } + + /** + * Sets an array of values. Each entry must be an array containing the + * following keys. + * o shadowedSampleNumber - gives the number of a sample for which there + * is an alternative sync sample. + * o syncSampleNumber - gives the number of the alternative sync sample. + * + * @param Array $shadowSyncSampleTable The array of values. + */ + public function setShadowSyncSampleTable($shadowSyncSampleTable) + { + $this->_shadowSyncSampleTable = $shadowSyncSampleTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + + count($this->_shadowSyncSampleTable) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE + ($entryCount = count($this->_shadowSyncSampleTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE + ($this->_shadowSyncSampleTable[$i] + ['shadowedSampleNumber']) + ->writeUInt32BE + ($this->_shadowSyncSampleTable[$i]['syncSampleNumber']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stss.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stss.php index 46c6195d..79909f84 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stss.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stss.php @@ -1,123 +1,123 @@ -Sync Sample Box provides a compact marking of the random access - * points within the stream. The table is arranged in strictly increasing order - * of sample number. If the sync sample box is not present, every sample is a - * random access point. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stss.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stss extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_syncSampleTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_syncSampleTable[$i] = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns an array of values. Each entry has the entry number as its index - * and an integer that gives the numbers of the samples that are random - * access points in the stream as its value. - * - * @return Array - */ - public function getSyncSampleTable() - { - return $this->_syncSampleTable; - } - - /** - * Sets an array of values. Each entry has the entry number as its index - * and an integer that gives the numbers of the samples that are random - * access points in the stream as its value. - * - * @param Array $syncSampleTable The array of values. - */ - public function setSyncSampleTable($syncSampleTable) - { - $this->_syncSampleTable = $syncSampleTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + count($this->_syncSampleTable) * 4; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_syncSampleTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE($this->_syncSampleTable[$i]); - } - } -} +Sync Sample Box provides a compact marking of the random access + * points within the stream. The table is arranged in strictly increasing order + * of sample number. If the sync sample box is not present, every sample is a + * random access point. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stss.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stss extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_syncSampleTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_syncSampleTable[$i] = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns an array of values. Each entry has the entry number as its index + * and an integer that gives the numbers of the samples that are random + * access points in the stream as its value. + * + * @return Array + */ + public function getSyncSampleTable() + { + return $this->_syncSampleTable; + } + + /** + * Sets an array of values. Each entry has the entry number as its index + * and an integer that gives the numbers of the samples that are random + * access points in the stream as its value. + * + * @param Array $syncSampleTable The array of values. + */ + public function setSyncSampleTable($syncSampleTable) + { + $this->_syncSampleTable = $syncSampleTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + count($this->_syncSampleTable) * 4; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_syncSampleTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE($this->_syncSampleTable[$i]); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsz.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsz.php index b1ee735b..bec9fe15 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stsz.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stsz.php @@ -1,164 +1,164 @@ -Sample Size Box contains the sample count and a table giving the - * size in bytes of each sample. This allows the media data itself to be - * unframed. The total number of samples in the media is always indicated in the - * sample count. - * - * There are two variants of the sample size box. The first variant has a fixed - * size 32-bit field for representing the sample sizes; it permits defining a - * constant size for all samples in a track. The second variant permits smaller - * size fields, to save space when the sizes are varying but small. One of these - * boxes must be present; the first version is preferred for maximum - * compatibility. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stsz.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stsz extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_sampleSize; - - /** @var Array */ - private $_sampleSizeTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_sampleSize = $this->_reader->readUInt32BE(); - $sampleCount = $this->_reader->readUInt32BE(); - if ($this->_sampleSize == 0) { - for ($i = 1; $i <= $sampleCount; $i++) { - $this->_sampleSizeTable[$i] = $this->_reader->readUInt32BE(); - } - } - } - - /** - * Returns the default sample size. If all the samples are the same size, - * this field contains that size value. If this field is set to 0, then the - * samples have different sizes, and those sizes are stored in the sample - * size table. - * - * @return integer - */ - public function getSampleSize() - { - return $this->_sampleSize; - } - - /** - * Sets the default sample size. If all the samples are the same size, - * this field contains that size value. If this field is set to 0, then the - * samples have different sizes, and those sizes are stored in the sample - * size table. - * - * @param integer $sampleSize The default sample size. - */ - public function setSampleSize($sampleSize) - { - $this->_sampleSize = $sampleSize; - } - - /** - * Returns an array of sample sizes specifying the size of a sample, indexed - * by its number. - * - * @return Array - */ - public function getSampleSizeTable() - { - return $this->_sampleSizeTable; - } - - /** - * Sets an array of sample sizes specifying the size of a sample, indexed - * by its number. - * - * @param Array $sampleSizeTable The array of sample sizes. - */ - public function setSampleSizeTable($sampleSizeTable) - { - $this->_sampleSizeTable = $sampleSizeTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 8 + - ($this->_sampleSize == 0 ? count($this->_sampleSizeTable) * 4 : 0); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_sampleSize); - $writer->writeUInt32BE($entryCount = count($this->_sampleSizeTable)); - if ($this->_sampleSize == 0) { - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE($this->_sampleSizeTable[$i]); - } - } - } -} +Sample Size Box contains the sample count and a table giving the + * size in bytes of each sample. This allows the media data itself to be + * unframed. The total number of samples in the media is always indicated in the + * sample count. + * + * There are two variants of the sample size box. The first variant has a fixed + * size 32-bit field for representing the sample sizes; it permits defining a + * constant size for all samples in a track. The second variant permits smaller + * size fields, to save space when the sizes are varying but small. One of these + * boxes must be present; the first version is preferred for maximum + * compatibility. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stsz.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stsz extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_sampleSize; + + /** @var Array */ + private $_sampleSizeTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_sampleSize = $this->_reader->readUInt32BE(); + $sampleCount = $this->_reader->readUInt32BE(); + if ($this->_sampleSize == 0) { + for ($i = 1; $i <= $sampleCount; $i++) { + $this->_sampleSizeTable[$i] = $this->_reader->readUInt32BE(); + } + } + } + + /** + * Returns the default sample size. If all the samples are the same size, + * this field contains that size value. If this field is set to 0, then the + * samples have different sizes, and those sizes are stored in the sample + * size table. + * + * @return integer + */ + public function getSampleSize() + { + return $this->_sampleSize; + } + + /** + * Sets the default sample size. If all the samples are the same size, + * this field contains that size value. If this field is set to 0, then the + * samples have different sizes, and those sizes are stored in the sample + * size table. + * + * @param integer $sampleSize The default sample size. + */ + public function setSampleSize($sampleSize) + { + $this->_sampleSize = $sampleSize; + } + + /** + * Returns an array of sample sizes specifying the size of a sample, indexed + * by its number. + * + * @return Array + */ + public function getSampleSizeTable() + { + return $this->_sampleSizeTable; + } + + /** + * Sets an array of sample sizes specifying the size of a sample, indexed + * by its number. + * + * @param Array $sampleSizeTable The array of sample sizes. + */ + public function setSampleSizeTable($sampleSizeTable) + { + $this->_sampleSizeTable = $sampleSizeTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 8 + + ($this->_sampleSize == 0 ? count($this->_sampleSizeTable) * 4 : 0); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_sampleSize); + $writer->writeUInt32BE($entryCount = count($this->_sampleSizeTable)); + if ($this->_sampleSize == 0) { + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE($this->_sampleSizeTable[$i]); + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Stts.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Stts.php index 114ba63b..db074a19 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Stts.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Stts.php @@ -1,148 +1,148 @@ -Decoding Time to Sample Box contains a compact version of a table - * that allows indexing from decoding time to sample number. Other tables give - * sample sizes and pointers, from the sample number. Each entry in the table - * gives the number of consecutive samples with the same time delta, and the - * delta of those samples. By adding the deltas a complete time-to-sample map - * may be built. - * - * The Decoding Time to Sample Box contains decode time delta's: DT(n+1) = DT(n) - * + STTS(n) where STTS(n) is the (uncompressed) table entry for sample n. - * - * The sample entries are ordered by decoding time stamps; therefore the deltas - * are all non-negative. - * - * The DT axis has a zero origin; DT(i) = SUM(for j=0 to i-1 of delta(j)), and - * the sum of all deltas gives the length of the media in the track (not mapped - * to the overall timescale, and not considering any edit list). - * - * The {@link Zend_Media_Iso14496_Box_Elst Edit List Box} provides the initial - * CT value if it is non-empty (non-zero). - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Stts.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Stts extends Zend_Media_Iso14496_FullBox -{ - /** @var Array */ - private $_timeToSampleTable = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 1; $i <= $entryCount; $i++) { - $this->_timeToSampleTable[$i] = array - ('sampleCount' => $this->_reader->readUInt32BE(), - 'sampleDelta' => $this->_reader->readUInt32BE()); - } - } - - /** - * Returns an array of values. Each entry is an array containing the - * following keys. - * o sampleCount -- an integer that counts the number of consecutive - * samples that have the given duration. - * o sampleDelta -- an integer that gives the delta of these samples in - * the time-scale of the media. - * - * @return Array - */ - public function getTimeToSampleTable() - { - return $this->_timeToSampleTable; - } - - /** - * Sets an array of values. Each entry must be an array containing the - * following keys. - * o sampleCount -- an integer that counts the number of consecutive - * samples that have the given duration. - * o sampleDelta -- an integer that gives the delta of these samples in - * the time-scale of the media. - * - * @param Array $timeToSampleTable The array of values. - */ - public function setTimeToSampleTable($timeToSampleTable) - { - $this->_timeToSampleTable = $timeToSampleTable; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4 + count($this->_timeToSampleTable) * 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($entryCount = count($this->_timeToSampleTable)); - for ($i = 1; $i <= $entryCount; $i++) { - $writer->writeUInt32BE($this->_timeToSampleTable[$i]['sampleCount']) - ->writeUInt32BE - ($this->_timeToSampleTable[$i]['sampleDelta']); - } - } -} +Decoding Time to Sample Box contains a compact version of a table + * that allows indexing from decoding time to sample number. Other tables give + * sample sizes and pointers, from the sample number. Each entry in the table + * gives the number of consecutive samples with the same time delta, and the + * delta of those samples. By adding the deltas a complete time-to-sample map + * may be built. + * + * The Decoding Time to Sample Box contains decode time delta's: DT(n+1) = DT(n) + * + STTS(n) where STTS(n) is the (uncompressed) table entry for sample n. + * + * The sample entries are ordered by decoding time stamps; therefore the deltas + * are all non-negative. + * + * The DT axis has a zero origin; DT(i) = SUM(for j=0 to i-1 of delta(j)), and + * the sum of all deltas gives the length of the media in the track (not mapped + * to the overall timescale, and not considering any edit list). + * + * The {@link Zend_Media_Iso14496_Box_Elst Edit List Box} provides the initial + * CT value if it is non-empty (non-zero). + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Stts.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Stts extends Zend_Media_Iso14496_FullBox +{ + /** @var Array */ + private $_timeToSampleTable = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 1; $i <= $entryCount; $i++) { + $this->_timeToSampleTable[$i] = array + ('sampleCount' => $this->_reader->readUInt32BE(), + 'sampleDelta' => $this->_reader->readUInt32BE()); + } + } + + /** + * Returns an array of values. Each entry is an array containing the + * following keys. + * o sampleCount -- an integer that counts the number of consecutive + * samples that have the given duration. + * o sampleDelta -- an integer that gives the delta of these samples in + * the time-scale of the media. + * + * @return Array + */ + public function getTimeToSampleTable() + { + return $this->_timeToSampleTable; + } + + /** + * Sets an array of values. Each entry must be an array containing the + * following keys. + * o sampleCount -- an integer that counts the number of consecutive + * samples that have the given duration. + * o sampleDelta -- an integer that gives the delta of these samples in + * the time-scale of the media. + * + * @param Array $timeToSampleTable The array of values. + */ + public function setTimeToSampleTable($timeToSampleTable) + { + $this->_timeToSampleTable = $timeToSampleTable; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4 + count($this->_timeToSampleTable) * 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($entryCount = count($this->_timeToSampleTable)); + for ($i = 1; $i <= $entryCount; $i++) { + $writer->writeUInt32BE($this->_timeToSampleTable[$i]['sampleCount']) + ->writeUInt32BE + ($this->_timeToSampleTable[$i]['sampleDelta']); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Tenc.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Tenc.php index 31a7e528..e519309c 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Tenc.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Tenc.php @@ -1,180 +1,180 @@ -Track Encryption Box contains default values for the IsEncrypted - * flag, IV_size, and KID for the entire track. These values are used as the - * encryption parameters for the samples in this track unless overridden by the - * sample group description associated with a group of samples. For files with - * only one key per track, this box allows the basic encryption parameters to be - * specified once per track instead of being repeated per sample. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tenc.php 274 2012-11-28 19:03:18Z svollbehr@gmail.com $ - */ -final class Zend_Media_Iso14496_Box_Tenc extends Zend_Media_Iso14496_FullBox -{ - private $_defaultEncryption; - private $_defaultIVSize; - private $_defaultKID; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_defaultEncryption = $this->_reader->readUInt24BE(); - $this->_defaultIVSize = $this->_reader->readUInt8(); - $this->_defaultKID = $this->_reader->read(16); - } - - /** - * Returns the encryption flag which indicates the default encryption state - * of the samples in the track. - * - * This flag is the identifier of the encryption state of the samples in the - * track or group of samples. This flag takes the following values: - * - * o 0x0: Not encrypted - * o 0x1: Encrypted using AES 128-bit in CTR mode - * o 0x000002 – 0xFFFFFF: Reserved - * - * @return integer - */ - public function getDefaultEncryption() - { - return $this->_defaultEncryption; - } - - /** - * Sets the encryption flag which indicates the default encryption state - * of the samples in the track. - * - * @param integer $defaultEncryption The default encryption flag. - */ - public function setDefaultEncryption($defaultEncryption) - { - $this->_defaultEncryption = $defaultEncryption; - } - - /** - * Returns the default Initialization Vector size in bytes. - * - * This field is the size in bytes of the InitializationVector field. - * Supported values: - * - * o 0 – If the IsEncrypted flag is 0x0 (Not Encrypted). - * o 8 – Specifies 64-bit initialization vectors. - * o 16 – Specifies 128-bit initialization vectors. - * - * @return integer - */ - public function getDefaultIVSize() - { - return $this->_defaultIVSize; - } - - /** - * Sets the default Initialization Vector size in bytes. - * - * @param integer $defaultIVSize The default vector size in bytes. - */ - public function setDefaultIVSize($defaultIVSize) - { - $this->_defaultIVSize = $defaultIVSize; - } - - /** - * Returns the default key identifier used for samples in this track. - * - * @return string - */ - public function getDefaultKID() - { - return $this->_defaultKID; - } - - /** - * Sets the default key identifier used for samples in this track. - * - * @param string $defaultKID The default key identifier. - */ - public function setDefaultKID($defaultKID) - { - $this->_defaultKID = $defaultKID; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 20; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt24BE($this->_defaultEncryption) - ->writeUInt8($this->_defaultIVSize) - ->write($this->_defaultKID); - } -} +Track Encryption Box contains default values for the IsEncrypted + * flag, IV_size, and KID for the entire track. These values are used as the + * encryption parameters for the samples in this track unless overridden by the + * sample group description associated with a group of samples. For files with + * only one key per track, this box allows the basic encryption parameters to be + * specified once per track instead of being repeated per sample. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tenc.php 274 2012-11-28 19:03:18Z svollbehr@gmail.com $ + */ +final class Zend_Media_Iso14496_Box_Tenc extends Zend_Media_Iso14496_FullBox +{ + private $_defaultEncryption; + private $_defaultIVSize; + private $_defaultKID; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_defaultEncryption = $this->_reader->readUInt24BE(); + $this->_defaultIVSize = $this->_reader->readUInt8(); + $this->_defaultKID = $this->_reader->read(16); + } + + /** + * Returns the encryption flag which indicates the default encryption state + * of the samples in the track. + * + * This flag is the identifier of the encryption state of the samples in the + * track or group of samples. This flag takes the following values: + * + * o 0x0: Not encrypted + * o 0x1: Encrypted using AES 128-bit in CTR mode + * o 0x000002 – 0xFFFFFF: Reserved + * + * @return integer + */ + public function getDefaultEncryption() + { + return $this->_defaultEncryption; + } + + /** + * Sets the encryption flag which indicates the default encryption state + * of the samples in the track. + * + * @param integer $defaultEncryption The default encryption flag. + */ + public function setDefaultEncryption($defaultEncryption) + { + $this->_defaultEncryption = $defaultEncryption; + } + + /** + * Returns the default Initialization Vector size in bytes. + * + * This field is the size in bytes of the InitializationVector field. + * Supported values: + * + * o 0 – If the IsEncrypted flag is 0x0 (Not Encrypted). + * o 8 – Specifies 64-bit initialization vectors. + * o 16 – Specifies 128-bit initialization vectors. + * + * @return integer + */ + public function getDefaultIVSize() + { + return $this->_defaultIVSize; + } + + /** + * Sets the default Initialization Vector size in bytes. + * + * @param integer $defaultIVSize The default vector size in bytes. + */ + public function setDefaultIVSize($defaultIVSize) + { + $this->_defaultIVSize = $defaultIVSize; + } + + /** + * Returns the default key identifier used for samples in this track. + * + * @return string + */ + public function getDefaultKID() + { + return $this->_defaultKID; + } + + /** + * Sets the default key identifier used for samples in this track. + * + * @param string $defaultKID The default key identifier. + */ + public function setDefaultKID($defaultKID) + { + $this->_defaultKID = $defaultKID; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 20; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt24BE($this->_defaultEncryption) + ->writeUInt8($this->_defaultIVSize) + ->write($this->_defaultKID); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Tfra.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Tfra.php index d817f071..cab83145 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Tfra.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Tfra.php @@ -1,334 +1,334 @@ -Track Fragment Random Access Box provides entries that contains the location and the presentation time of - * the random accessible sample. It indicates that the sample in the entry can be random accessed. Note that not every - * random accessible sample in the track needs to be listed in the table. - * - * The absence of this box does not mean that all the samples are sync samples. Random access information in the - * {@link Zend_Media_Iso14496_Box_Trun}, {@link Zend_Media_Iso14496_Box_Traf} and {@link Zend_Media_Iso14496_Box_Trex} - * shall be set appropriately regardless of the presence of this box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Georges-Etienne Legendre - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tfra.php 221 2011-05-04 05:31:08Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Tfra extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_trackId; - - /** @var Array */ - private $_entries = array(); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_trackId = $this->_reader->readUInt32BE(); - - $reserved = (($tmp = $this->_reader->readUInt32BE()) >> 6) & 0x3ffffff; - $lengthSizeOfTrafNum = ($tmp >> 4) & 0x3; - $lengthSizeOfTrunNum = ($tmp >> 2) & 0x3; - $lengthSizeOfSampleNum = $tmp & 0x3; - - $entryCount = $this->_reader->readUInt32BE(); - for ($i = 0; $i < $entryCount; $i++) { - $entry = array(); - if ($this->getVersion() == 1) { - $entry['time'] = $this->_reader->readInt64BE(); - $entry['moofOffset'] = $this->_reader->readInt64BE(); - } else { - $entry['time'] = $this->_reader->readUInt32BE(); - $entry['moofOffset'] = $this->_reader->readUInt32BE(); - } - - switch ($lengthSizeOfTrafNum) { - case 0: - $entry['trafNumber'] = $this->_reader->readUInt8(); - break; - case 1: - $entry['trafNumber'] = $this->_reader->readUInt16BE(); - break; - case 2: - $entry['trafNumber'] = $this->_reader->readUInt32BE(); - break; - case 3: - $entry['trafNumber'] = $this->_reader->readInt64BE(); - break; - } - - switch ($lengthSizeOfTrunNum) { - case 0: - $entry['trunNumber'] = $this->_reader->readUInt8(); - break; - case 1: - $entry['trunNumber'] = $this->_reader->readUInt16BE(); - break; - case 2: - $entry['trunNumber'] = $this->_reader->readUInt32BE(); - break; - case 3: - $entry['trunNumber'] = $this->_reader->readInt64BE(); - break; - } - - switch ($lengthSizeOfSampleNum) { - case 0: - $entry['sampleNumber'] = $this->_reader->readUInt8(); - break; - case 1: - $entry['sampleNumber'] = $this->_reader->readUInt16BE(); - break; - case 2: - $entry['sampleNumber'] = $this->_reader->readUInt32BE(); - break; - case 3: - $entry['sampleNumber'] = $this->_reader->readInt64BE(); - break; - } - $this->_entries[] = $entry; - } - } - - /** - * Returns the integer identifying the track ID. - * - * @return integer - */ - public function getTrackId() - { - return $this->_trackId; - } - - /** - * Sets the integer identifying the track ID. - * - * @param integer $trackId The track ID. - */ - public function setTrackId($trackId) - { - $this->_trackId = $trackId; - } - - /** - * Returns an array of entries. Each entry is an array containing the - * following keys. - * o time: is 32 or 64 bits integer that indicates the presentation time of the random access sample in units - * defined in the {@link Zend_Media_Iso14496_Box_Mdhd} of the associated track. - * o moofOffset: is 32 or 64 bits integer that gives the offset of the {@link Zend_Media_Iso14496_Box_Moof} used - * in this entry. Offset is the byte-offset between the beginning of the file and the beginning of the - * {@link Zend_Media_Iso14496_Box_Moof}. - * o trafNumber: indicates the {@link Zend_Media_Iso14496_Box_Traf} number that contains the random accessible - * sample. The number ranges from 1 (the first traf is numbered 1) in each {@link Zend_Media_Iso14496_Box_Moof}, - * o trunNumber: indicates the {@link Zend_Media_Iso14496_Box_Trun} number that contains the random accessible - * sample. The number ranges from 1 in each {@link Zend_Media_Iso14496_Box_Traf}. - * o sampleNumber: indicates the sample number that contains the random accessible sample. The number ranges from - * 1 in each {@link Zend_Media_Iso14496_Box_Trun}. - * - * @return Array - */ - public function getEntries() - { - return $this->_entries; - } - - /** - * Sets the array of entries. Each entry must be an array containing the - * following keys. - * o time: is 32 or 64 bits integer that indicates the presentation time of the random access sample in units - * defined in the {@link Zend_Media_Iso14496_Box_Mdhd} of the associated track. - * o moofOffset: is 32 or 64 bits integer that gives the offset of the {@link Zend_Media_Iso14496_Box_Moof} used - * in this entry. Offset is the byte-offset between the beginning of the file and the beginning of the - * {@link Zend_Media_Iso14496_Box_Moof}. - * o trafNumber: indicates the {@link Zend_Media_Iso14496_Box_Traf} number that contains the random accessible - * sample. The number ranges from 1 (the first traf is numbered 1) in each {@link Zend_Media_Iso14496_Box_Moof}, - * o trunNumber: indicates the {@link Zend_Media_Iso14496_Box_Trun} number that contains the random accessible - * sample. The number ranges from 1 in each {@link Zend_Media_Iso14496_Box_Traf}. - * o sampleNumber: indicates the sample number that contains the random accessible sample. The number ranges from - * 1 in each {@link Zend_Media_Iso14496_Box_Trun}. - * - * @return Array - */ - public function setEntries($entries) - { - $this->_entries = $entries; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - $lengthSizes = $this->_getLengthSizes(); - return parent::getHeapSize() + 12 + - count($this->_entries) * ($this->getVersion() == 1 ? 16 : 8) + - count($this->_entries) * ($lengthSizes['trafNum'] + 1) + - count($this->_entries) * ($lengthSizes['trunNum'] + 1) + - count($this->_entries) * ($lengthSizes['sampleNum'] + 1); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $lengthSizes = $this->_getLengthSizes(); - $writer->writeUInt32BE($this->_trackId) - ->writeUInt32BE - (($lengthSizes['trafNum'] << 4) | ($lengthSizes['trunNum'] << 2) | ($lengthSizes['sampleNum'])) - ->writeUInt32BE($entryCount = count($this->_entries)); - for ($i = 0; $i < $entryCount; $i++) { - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_entries[$i]['time']) - ->writeInt64BE($this->_entries[$i]['mediaTime']); - } else { - $writer->writeUInt32BE($this->_entries[$i]['time']) - ->writeInt32BE($this->_entries[$i]['moofOffset']); - } - - switch ($lengthSizes['trafNum']) { - case 0: - $writer->writeUInt8($this->_entries[$i]['trafNumber']); - break; - case 1: - $writer->writeUInt16BE($this->_entries[$i]['trafNumber']); - break; - case 2: - $writer->writeUInt32BE($this->_entries[$i]['trafNumber']); - break; - case 3: - $writer->writeInt64BE($this->_entries[$i]['trafNumber']); - break; - } - - switch ($lengthSizes['trunNum']) { - case 0: - $writer->writeUInt8($this->_entries[$i]['trunNumber']); - break; - case 1: - $writer->writeUInt16BE($this->_entries[$i]['trunNumber']); - break; - case 2: - $writer->writeUInt32BE($this->_entries[$i]['trunNumber']); - break; - case 3: - $writer->writeInt64BE($this->_entries[$i]['trunNumber']); - break; - } - - switch ($lengthSizes['sampleNum']) { - case 0: - $writer->writeUInt8($this->_entries[$i]['sampleNumber']); - break; - case 1: - $writer->writeUInt16BE($this->_entries[$i]['sampleNumber']); - break; - case 2: - $writer->writeUInt32BE($this->_entries[$i]['sampleNumber']); - break; - case 3: - $writer->writeInt64BE($this->_entries[$i]['sampleNumber']); - break; - } - } - } - - /** - * Returns the length sizes based on maximum numbers for each type of integer. - * @return integer Returns the length sizes based on maximum numbers for each type of integer. - */ - private function _getLengthSizes() - { - $maxTrafNum = $maxTrunNum = $maxSampleNum = 0; - foreach ($this->entries as $entry) { - if ($maxTrafNum < $entry['trafNumber']) { - $maxTrafNum = $entry['trafNumber']; - } - if ($maxTrunNum < $entry['trunNumber']) { - $maxTrunNum = $entry['trunNumber']; - } - if ($maxSampleNum < $entry['sampleNumber']) { - $maxSampleNum = $entry['sampleNumber']; - } - } - return array( - 'trafNum' => $this->_getLengthSizeFromInteger($maxTrafNum), - 'trunNum' => $this->_getLengthSizeFromInteger($maxTrunNum), - 'sampleNum' => $this->_getLengthSizeFromInteger($maxSampleNum) - ); - } - - /** - * Returns the length size based on the given integer. - * - * @param integer $integer The integer to determine the length size from. - * @return Returns the length size of the given integer. - */ - private function _getLengthSizeFromInteger($integer) - { - if ($integer <= 0xff) { - return 0; - } else if ($integer <= 0xffff) { - return 1; - } else if ($integer <= 0xffffffff) { - return 2; - } else { - return 3; - } - } -} +Track Fragment Random Access Box provides entries that contains the location and the presentation time of + * the random accessible sample. It indicates that the sample in the entry can be random accessed. Note that not every + * random accessible sample in the track needs to be listed in the table. + * + * The absence of this box does not mean that all the samples are sync samples. Random access information in the + * {@link Zend_Media_Iso14496_Box_Trun}, {@link Zend_Media_Iso14496_Box_Traf} and {@link Zend_Media_Iso14496_Box_Trex} + * shall be set appropriately regardless of the presence of this box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Georges-Etienne Legendre + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tfra.php 221 2011-05-04 05:31:08Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Tfra extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_trackId; + + /** @var Array */ + private $_entries = array(); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_trackId = $this->_reader->readUInt32BE(); + + $reserved = (($tmp = $this->_reader->readUInt32BE()) >> 6) & 0x3ffffff; + $lengthSizeOfTrafNum = ($tmp >> 4) & 0x3; + $lengthSizeOfTrunNum = ($tmp >> 2) & 0x3; + $lengthSizeOfSampleNum = $tmp & 0x3; + + $entryCount = $this->_reader->readUInt32BE(); + for ($i = 0; $i < $entryCount; $i++) { + $entry = array(); + if ($this->getVersion() == 1) { + $entry['time'] = $this->_reader->readInt64BE(); + $entry['moofOffset'] = $this->_reader->readInt64BE(); + } else { + $entry['time'] = $this->_reader->readUInt32BE(); + $entry['moofOffset'] = $this->_reader->readUInt32BE(); + } + + switch ($lengthSizeOfTrafNum) { + case 0: + $entry['trafNumber'] = $this->_reader->readUInt8(); + break; + case 1: + $entry['trafNumber'] = $this->_reader->readUInt16BE(); + break; + case 2: + $entry['trafNumber'] = $this->_reader->readUInt32BE(); + break; + case 3: + $entry['trafNumber'] = $this->_reader->readInt64BE(); + break; + } + + switch ($lengthSizeOfTrunNum) { + case 0: + $entry['trunNumber'] = $this->_reader->readUInt8(); + break; + case 1: + $entry['trunNumber'] = $this->_reader->readUInt16BE(); + break; + case 2: + $entry['trunNumber'] = $this->_reader->readUInt32BE(); + break; + case 3: + $entry['trunNumber'] = $this->_reader->readInt64BE(); + break; + } + + switch ($lengthSizeOfSampleNum) { + case 0: + $entry['sampleNumber'] = $this->_reader->readUInt8(); + break; + case 1: + $entry['sampleNumber'] = $this->_reader->readUInt16BE(); + break; + case 2: + $entry['sampleNumber'] = $this->_reader->readUInt32BE(); + break; + case 3: + $entry['sampleNumber'] = $this->_reader->readInt64BE(); + break; + } + $this->_entries[] = $entry; + } + } + + /** + * Returns the integer identifying the track ID. + * + * @return integer + */ + public function getTrackId() + { + return $this->_trackId; + } + + /** + * Sets the integer identifying the track ID. + * + * @param integer $trackId The track ID. + */ + public function setTrackId($trackId) + { + $this->_trackId = $trackId; + } + + /** + * Returns an array of entries. Each entry is an array containing the + * following keys. + * o time: is 32 or 64 bits integer that indicates the presentation time of the random access sample in units + * defined in the {@link Zend_Media_Iso14496_Box_Mdhd} of the associated track. + * o moofOffset: is 32 or 64 bits integer that gives the offset of the {@link Zend_Media_Iso14496_Box_Moof} used + * in this entry. Offset is the byte-offset between the beginning of the file and the beginning of the + * {@link Zend_Media_Iso14496_Box_Moof}. + * o trafNumber: indicates the {@link Zend_Media_Iso14496_Box_Traf} number that contains the random accessible + * sample. The number ranges from 1 (the first traf is numbered 1) in each {@link Zend_Media_Iso14496_Box_Moof}, + * o trunNumber: indicates the {@link Zend_Media_Iso14496_Box_Trun} number that contains the random accessible + * sample. The number ranges from 1 in each {@link Zend_Media_Iso14496_Box_Traf}. + * o sampleNumber: indicates the sample number that contains the random accessible sample. The number ranges from + * 1 in each {@link Zend_Media_Iso14496_Box_Trun}. + * + * @return Array + */ + public function getEntries() + { + return $this->_entries; + } + + /** + * Sets the array of entries. Each entry must be an array containing the + * following keys. + * o time: is 32 or 64 bits integer that indicates the presentation time of the random access sample in units + * defined in the {@link Zend_Media_Iso14496_Box_Mdhd} of the associated track. + * o moofOffset: is 32 or 64 bits integer that gives the offset of the {@link Zend_Media_Iso14496_Box_Moof} used + * in this entry. Offset is the byte-offset between the beginning of the file and the beginning of the + * {@link Zend_Media_Iso14496_Box_Moof}. + * o trafNumber: indicates the {@link Zend_Media_Iso14496_Box_Traf} number that contains the random accessible + * sample. The number ranges from 1 (the first traf is numbered 1) in each {@link Zend_Media_Iso14496_Box_Moof}, + * o trunNumber: indicates the {@link Zend_Media_Iso14496_Box_Trun} number that contains the random accessible + * sample. The number ranges from 1 in each {@link Zend_Media_Iso14496_Box_Traf}. + * o sampleNumber: indicates the sample number that contains the random accessible sample. The number ranges from + * 1 in each {@link Zend_Media_Iso14496_Box_Trun}. + * + * @return Array + */ + public function setEntries($entries) + { + $this->_entries = $entries; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + $lengthSizes = $this->_getLengthSizes(); + return parent::getHeapSize() + 12 + + count($this->_entries) * ($this->getVersion() == 1 ? 16 : 8) + + count($this->_entries) * ($lengthSizes['trafNum'] + 1) + + count($this->_entries) * ($lengthSizes['trunNum'] + 1) + + count($this->_entries) * ($lengthSizes['sampleNum'] + 1); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $lengthSizes = $this->_getLengthSizes(); + $writer->writeUInt32BE($this->_trackId) + ->writeUInt32BE + (($lengthSizes['trafNum'] << 4) | ($lengthSizes['trunNum'] << 2) | ($lengthSizes['sampleNum'])) + ->writeUInt32BE($entryCount = count($this->_entries)); + for ($i = 0; $i < $entryCount; $i++) { + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_entries[$i]['time']) + ->writeInt64BE($this->_entries[$i]['mediaTime']); + } else { + $writer->writeUInt32BE($this->_entries[$i]['time']) + ->writeInt32BE($this->_entries[$i]['moofOffset']); + } + + switch ($lengthSizes['trafNum']) { + case 0: + $writer->writeUInt8($this->_entries[$i]['trafNumber']); + break; + case 1: + $writer->writeUInt16BE($this->_entries[$i]['trafNumber']); + break; + case 2: + $writer->writeUInt32BE($this->_entries[$i]['trafNumber']); + break; + case 3: + $writer->writeInt64BE($this->_entries[$i]['trafNumber']); + break; + } + + switch ($lengthSizes['trunNum']) { + case 0: + $writer->writeUInt8($this->_entries[$i]['trunNumber']); + break; + case 1: + $writer->writeUInt16BE($this->_entries[$i]['trunNumber']); + break; + case 2: + $writer->writeUInt32BE($this->_entries[$i]['trunNumber']); + break; + case 3: + $writer->writeInt64BE($this->_entries[$i]['trunNumber']); + break; + } + + switch ($lengthSizes['sampleNum']) { + case 0: + $writer->writeUInt8($this->_entries[$i]['sampleNumber']); + break; + case 1: + $writer->writeUInt16BE($this->_entries[$i]['sampleNumber']); + break; + case 2: + $writer->writeUInt32BE($this->_entries[$i]['sampleNumber']); + break; + case 3: + $writer->writeInt64BE($this->_entries[$i]['sampleNumber']); + break; + } + } + } + + /** + * Returns the length sizes based on maximum numbers for each type of integer. + * @return integer Returns the length sizes based on maximum numbers for each type of integer. + */ + private function _getLengthSizes() + { + $maxTrafNum = $maxTrunNum = $maxSampleNum = 0; + foreach ($this->entries as $entry) { + if ($maxTrafNum < $entry['trafNumber']) { + $maxTrafNum = $entry['trafNumber']; + } + if ($maxTrunNum < $entry['trunNumber']) { + $maxTrunNum = $entry['trunNumber']; + } + if ($maxSampleNum < $entry['sampleNumber']) { + $maxSampleNum = $entry['sampleNumber']; + } + } + return array( + 'trafNum' => $this->_getLengthSizeFromInteger($maxTrafNum), + 'trunNum' => $this->_getLengthSizeFromInteger($maxTrunNum), + 'sampleNum' => $this->_getLengthSizeFromInteger($maxSampleNum) + ); + } + + /** + * Returns the length size based on the given integer. + * + * @param integer $integer The integer to determine the length size from. + * @return Returns the length size of the given integer. + */ + private function _getLengthSizeFromInteger($integer) + { + if ($integer <= 0xff) { + return 0; + } else if ($integer <= 0xffff) { + return 1; + } else if ($integer <= 0xffffffff) { + return 2; + } else { + return 3; + } + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Tkhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Tkhd.php index ef56426e..ab355129 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Tkhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Tkhd.php @@ -1,432 +1,432 @@ -Track Header Box specifies the characteristics of a single track. - * Exactly one Track Header Box is contained in a track. - * - * In the absence of an edit list, the presentation of a track starts at the - * beginning of the overall presentation. An empty edit is used to offset the - * start time of a track. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tkhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Tkhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_creationTime; - - /** @var integer */ - private $_modificationTime; - - /** @var integer */ - private $_trackId; - - /** @var integer */ - private $_duration; - - /** @var integer */ - private $_layer = 0; - - /** @var integer */ - private $_alternateGroup = 0; - - /** @var integer */ - private $_volume = 0; - - /** @var Array */ - private $_matrix = array - (0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000); - - /** @var integer */ - private $_width; - - /** @var integer */ - private $_height; - - /** - * Indicates that the track is enabled. A disabled track is treated as if it - * were not present. - */ - const TRACK_ENABLED = 1; - - /** Indicates that the track is used in the presentation. */ - const TRACK_IN_MOVIE = 2; - - /** Indicates that the track is used when previewing the presentation. */ - const TRACK_IN_PREVIEW = 4; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - if ($this->getVersion() == 1) { - $this->_creationTime = $this->_reader->readInt64BE(); - $this->_modificationTime = $this->_reader->readInt64BE(); - $this->_trackId = $this->_reader->readUInt32BE(); - $this->_reader->skip(4); - $this->_duration = $this->_reader->readInt64BE(); - } else { - $this->_creationTime = $this->_reader->readUInt32BE(); - $this->_modificationTime = $this->_reader->readUInt32BE(); - $this->_trackId = $this->_reader->readUInt32BE(); - $this->_reader->skip(4); - $this->_duration = $this->_reader->readUInt32BE(); - } - $this->_reader->skip(8); - $this->_layer = $this->_reader->readInt16BE(); - $this->_alternateGroup = $this->_reader->readInt16BE(); - $this->_volume = - ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + - (float)("0." . ((string)($tmp & 0xff))); - $this->_reader->skip(2); - for ($i = 0; $i < 9; $i++) { - $this->_matrix[$i] = $this->_reader->readUInt32BE(); - } - $this->_width = - ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + - (float)("0." . ((string)($tmp & 0xffff))); - $this->_height = - ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + - (float)("0." . ((string)($tmp & 0xffff))); - } - - /** - * Returns the creation time of this track in seconds since midnight, Jan. 1, - * 1904, in UTC time. - * - * @return integer - */ - public function getCreationTime() - { - return $this->_creationTime; - } - - /** - * Sets the creation time of this track in seconds since midnight, Jan. 1, - * 1904, in UTC time. - * - * @param integer $creationTime The creation time. - */ - public function setCreationTime() - { - $this->_creationTime = $creationTime; - } - - /** - * Returns the most recent time the track was modified in seconds since - * midnight, Jan. 1, 1904, in UTC time. - * - * @return integer - */ - public function getModificationTime() - { - return $this->_modificationTime; - } - - /** - * Sets the most recent time the track was modified in seconds since - * midnight, Jan. 1, 1904, in UTC time. - * - * @param integer $modificationTime The modification time. - */ - public function setModificationTime($modificationTime) - { - $this->_modificationTime = $modificationTime; - } - - /** - * Returns a number that uniquely identifies this track over the entire - * life-time of this presentation. Track IDs are never re-used and cannot be - * zero. - * - * @return integer - */ - public function getTrackId() - { - return $this->_trackId; - } - - /** - * Returns a number that uniquely identifies this track over the entire - * life-time of this presentation. Track IDs are never re-used and cannot be - * zero. - * - * @param integer $trackId The track identification. - */ - public function setTrackId($trackId) - { - $this->_trackId = $trackId; - } - - /** - * Returns the duration of this track (in the timescale indicated in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of this - * field is equal to the sum of the durations of all of the track's edits. - * If there is no edit list, then the duration is the sum of the sample - * durations, converted into the timescale in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. If the duration - * of this track cannot be determined then duration is set to all 32-bit - * maxint. - * - * @return integer - */ - public function getDuration() - { - return $this->_duration; - } - - /** - * Sets the duration of this track (in the timescale indicated in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of this - * field must be equal to the sum of the durations of all of the track's - * edits. If there is no edit list, then the duration must be the sum of the - * sample durations, converted into the timescale in the - * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. If the duration - * of this track cannot be determined then duration is set to all 32-bit - * maxint. - * - * @param integer $duration The duration of this track. - */ - public function setDuration($duration) - { - $this->_duration = $duration; - } - - /** - * Returns the front-to-back ordering of video tracks; tracks with lower - * numbers are closer to the viewer. 0 is the normal value, and -1 would be - * in front of track 0, and so on. - * - * @return integer - */ - public function getLayer() - { - return $this->_layer; - } - - /** - * Sets the front-to-back ordering of video tracks; tracks with lower - * numbers are closer to the viewer. 0 is the normal value, and -1 would be - * in front of track 0, and so on. - * - * @param integer $layer The layer. - */ - public function setLayer($layer) - { - $this->_layer = $layer; - } - - /** - * Returns an integer that specifies a group or collection of tracks. If - * this field is 0 there is no information on possible relations to other - * tracks. If this field is not 0, it should be the same for tracks that - * contain alternate data for one another and different for tracks belonging - * to different such groups. Only one track within an alternate group - * should be played or streamed at any one time, and must be distinguishable - * from other tracks in the group via attributes such as bitrate, codec, - * language, packet size etc. A group may have only one member. - * - * @return integer - */ - public function getAlternateGroup() - { - return $this->_alternateGroup; - } - - /** - * Returns an integer that specifies a group or collection of tracks. If - * this field is 0 there is no information on possible relations to other - * tracks. If this field is not 0, it should be the same for tracks that - * contain alternate data for one another and different for tracks belonging - * to different such groups. Only one track within an alternate group - * should be played or streamed at any one time, and must be distinguishable - * from other tracks in the group via attributes such as bitrate, codec, - * language, packet size etc. A group may have only one member. - * - * @param integer $alternateGroup The alternate group. - */ - public function setAlternateGroup($alternateGroup) - { - $this->_alternateGroup = $alternateGroup; - } - - /** - * Returns track's relative audio volume. Full volume is 1.0 (0x0100) and - * is the normal value. Its value is irrelevant for a purely visual track. - * Tracks may be composed by combining them according to their volume, and - * then using the overall Movie Header Box volume setting; or more complex - * audio composition (e.g. MPEG-4 BIFS) may be used. - * - * @return integer - */ - public function getVolume() - { - return $this->_volume; - } - - /** - * Sets track's relative audio volume. Full volume is 1.0 (0x0100) and - * is the normal value. Its value is irrelevant for a purely visual track. - * Tracks may be composed by combining them according to their volume, and - * then using the overall Movie Header Box volume setting; or more complex - * audio composition (e.g. MPEG-4 BIFS) may be used. - * - * @param integer $volume The volume. - */ - public function setVolume($volume) - { - $this->_volume = $volume; - } - - /** - * Returns the track's visual presentation width. This needs not be the same - * as the pixel width of the images; all images in the sequence are scaled - * to this width, before any overall transformation of the track represented - * by the matrix. The pixel width of the images is the default value. - * - * @return integer - */ - public function getWidth() - { - return $this->_width; - } - - /** - * Set the track's visual presentation width. This needs not be the same - * as the pixel width of the images; all images in the sequence are scaled - * to this width, before any overall transformation of the track represented - * by the matrix. The pixel width of the images should be the default value. - * - * @param integer $width The width. - */ - public function setWidth($width) - { - $this->_width = $width; - } - - /** - * Returns the track's visual presentation height. This needs not be the - * same as the pixel height of the images; all images in the sequence are - * scaled to this height, before any overall transformation of the track - * represented by the matrix. The pixel height of the images is the default - * value. - * - * @return integer - */ - public function getHeight() - { - return $this->_height; - } - - /** - * Sets the track's visual presentation height. This needs not be the - * same as the pixel height of the images; all images in the sequence are - * scaled to this height, before any overall transformation of the track - * represented by the matrix. The pixel height of the images should be the - * default value. - * - * @param integer $height The height. - */ - public function setHeight($height) - { - $this->_height = $height; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + - ($this->getVersion() == 1 ? 32 : 20) + 60; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - if ($this->getVersion() == 1) { - $writer->writeInt64BE($this->_creationTime) - ->writeInt64BE($this->_modificationTime) - ->writeUInt32BE($this->_trackId) - ->writeUInt32BE(0) - ->writeInt64BE($this->_duration); - } else { - $writer->writeUInt32BE($this->_creationTime) - ->writeUInt32BE($this->_modificationTime) - ->writeUInt32BE($this->_trackId) - ->writeUInt32BE(0) - ->writeUInt32BE($this->_duration); - } - - @list(, $volumeDecimals) = explode('.', (float)$this->_volume); - $writer->write(str_pad('', 8, "\0")) - ->writeInt16BE($this->_layer) - ->writeInt16BE($this->_alternateGroup) - ->writeUInt16BE(floor($this->_volume) << 8 | $volumeDecimals) - ->write(str_pad('', 2, "\0")); - for ($i = 0; $i < 9; $i++) { - $writer->writeUInt32BE($this->_matrix[$i]); - } - @list(, $widthDecimals) = explode('.', (float)$this->_width); - @list(, $heightDecimals) = explode('.', (float)$this->_height); - $writer->writeUInt32BE(floor($this->_width) << 16 | $widthDecimals) - ->writeUInt32BE(floor($this->_height) << 16 | $heightDecimals); - } -} +Track Header Box specifies the characteristics of a single track. + * Exactly one Track Header Box is contained in a track. + * + * In the absence of an edit list, the presentation of a track starts at the + * beginning of the overall presentation. An empty edit is used to offset the + * start time of a track. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tkhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Tkhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_creationTime; + + /** @var integer */ + private $_modificationTime; + + /** @var integer */ + private $_trackId; + + /** @var integer */ + private $_duration; + + /** @var integer */ + private $_layer = 0; + + /** @var integer */ + private $_alternateGroup = 0; + + /** @var integer */ + private $_volume = 0; + + /** @var Array */ + private $_matrix = array + (0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000); + + /** @var integer */ + private $_width; + + /** @var integer */ + private $_height; + + /** + * Indicates that the track is enabled. A disabled track is treated as if it + * were not present. + */ + const TRACK_ENABLED = 1; + + /** Indicates that the track is used in the presentation. */ + const TRACK_IN_MOVIE = 2; + + /** Indicates that the track is used when previewing the presentation. */ + const TRACK_IN_PREVIEW = 4; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + if ($this->getVersion() == 1) { + $this->_creationTime = $this->_reader->readInt64BE(); + $this->_modificationTime = $this->_reader->readInt64BE(); + $this->_trackId = $this->_reader->readUInt32BE(); + $this->_reader->skip(4); + $this->_duration = $this->_reader->readInt64BE(); + } else { + $this->_creationTime = $this->_reader->readUInt32BE(); + $this->_modificationTime = $this->_reader->readUInt32BE(); + $this->_trackId = $this->_reader->readUInt32BE(); + $this->_reader->skip(4); + $this->_duration = $this->_reader->readUInt32BE(); + } + $this->_reader->skip(8); + $this->_layer = $this->_reader->readInt16BE(); + $this->_alternateGroup = $this->_reader->readInt16BE(); + $this->_volume = + ((($tmp = $this->_reader->readUInt16BE()) >> 8) & 0xff) + + (float)("0." . ((string)($tmp & 0xff))); + $this->_reader->skip(2); + for ($i = 0; $i < 9; $i++) { + $this->_matrix[$i] = $this->_reader->readUInt32BE(); + } + $this->_width = + ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + + (float)("0." . ((string)($tmp & 0xffff))); + $this->_height = + ((($tmp = $this->_reader->readUInt32BE()) >> 16) & 0xffff) + + (float)("0." . ((string)($tmp & 0xffff))); + } + + /** + * Returns the creation time of this track in seconds since midnight, Jan. 1, + * 1904, in UTC time. + * + * @return integer + */ + public function getCreationTime() + { + return $this->_creationTime; + } + + /** + * Sets the creation time of this track in seconds since midnight, Jan. 1, + * 1904, in UTC time. + * + * @param integer $creationTime The creation time. + */ + public function setCreationTime() + { + $this->_creationTime = $creationTime; + } + + /** + * Returns the most recent time the track was modified in seconds since + * midnight, Jan. 1, 1904, in UTC time. + * + * @return integer + */ + public function getModificationTime() + { + return $this->_modificationTime; + } + + /** + * Sets the most recent time the track was modified in seconds since + * midnight, Jan. 1, 1904, in UTC time. + * + * @param integer $modificationTime The modification time. + */ + public function setModificationTime($modificationTime) + { + $this->_modificationTime = $modificationTime; + } + + /** + * Returns a number that uniquely identifies this track over the entire + * life-time of this presentation. Track IDs are never re-used and cannot be + * zero. + * + * @return integer + */ + public function getTrackId() + { + return $this->_trackId; + } + + /** + * Returns a number that uniquely identifies this track over the entire + * life-time of this presentation. Track IDs are never re-used and cannot be + * zero. + * + * @param integer $trackId The track identification. + */ + public function setTrackId($trackId) + { + $this->_trackId = $trackId; + } + + /** + * Returns the duration of this track (in the timescale indicated in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of this + * field is equal to the sum of the durations of all of the track's edits. + * If there is no edit list, then the duration is the sum of the sample + * durations, converted into the timescale in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. If the duration + * of this track cannot be determined then duration is set to all 32-bit + * maxint. + * + * @return integer + */ + public function getDuration() + { + return $this->_duration; + } + + /** + * Sets the duration of this track (in the timescale indicated in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}). The value of this + * field must be equal to the sum of the durations of all of the track's + * edits. If there is no edit list, then the duration must be the sum of the + * sample durations, converted into the timescale in the + * {@link Zend_Media_Iso14496_Box_Mvhd Movie Header Box}. If the duration + * of this track cannot be determined then duration is set to all 32-bit + * maxint. + * + * @param integer $duration The duration of this track. + */ + public function setDuration($duration) + { + $this->_duration = $duration; + } + + /** + * Returns the front-to-back ordering of video tracks; tracks with lower + * numbers are closer to the viewer. 0 is the normal value, and -1 would be + * in front of track 0, and so on. + * + * @return integer + */ + public function getLayer() + { + return $this->_layer; + } + + /** + * Sets the front-to-back ordering of video tracks; tracks with lower + * numbers are closer to the viewer. 0 is the normal value, and -1 would be + * in front of track 0, and so on. + * + * @param integer $layer The layer. + */ + public function setLayer($layer) + { + $this->_layer = $layer; + } + + /** + * Returns an integer that specifies a group or collection of tracks. If + * this field is 0 there is no information on possible relations to other + * tracks. If this field is not 0, it should be the same for tracks that + * contain alternate data for one another and different for tracks belonging + * to different such groups. Only one track within an alternate group + * should be played or streamed at any one time, and must be distinguishable + * from other tracks in the group via attributes such as bitrate, codec, + * language, packet size etc. A group may have only one member. + * + * @return integer + */ + public function getAlternateGroup() + { + return $this->_alternateGroup; + } + + /** + * Returns an integer that specifies a group or collection of tracks. If + * this field is 0 there is no information on possible relations to other + * tracks. If this field is not 0, it should be the same for tracks that + * contain alternate data for one another and different for tracks belonging + * to different such groups. Only one track within an alternate group + * should be played or streamed at any one time, and must be distinguishable + * from other tracks in the group via attributes such as bitrate, codec, + * language, packet size etc. A group may have only one member. + * + * @param integer $alternateGroup The alternate group. + */ + public function setAlternateGroup($alternateGroup) + { + $this->_alternateGroup = $alternateGroup; + } + + /** + * Returns track's relative audio volume. Full volume is 1.0 (0x0100) and + * is the normal value. Its value is irrelevant for a purely visual track. + * Tracks may be composed by combining them according to their volume, and + * then using the overall Movie Header Box volume setting; or more complex + * audio composition (e.g. MPEG-4 BIFS) may be used. + * + * @return integer + */ + public function getVolume() + { + return $this->_volume; + } + + /** + * Sets track's relative audio volume. Full volume is 1.0 (0x0100) and + * is the normal value. Its value is irrelevant for a purely visual track. + * Tracks may be composed by combining them according to their volume, and + * then using the overall Movie Header Box volume setting; or more complex + * audio composition (e.g. MPEG-4 BIFS) may be used. + * + * @param integer $volume The volume. + */ + public function setVolume($volume) + { + $this->_volume = $volume; + } + + /** + * Returns the track's visual presentation width. This needs not be the same + * as the pixel width of the images; all images in the sequence are scaled + * to this width, before any overall transformation of the track represented + * by the matrix. The pixel width of the images is the default value. + * + * @return integer + */ + public function getWidth() + { + return $this->_width; + } + + /** + * Set the track's visual presentation width. This needs not be the same + * as the pixel width of the images; all images in the sequence are scaled + * to this width, before any overall transformation of the track represented + * by the matrix. The pixel width of the images should be the default value. + * + * @param integer $width The width. + */ + public function setWidth($width) + { + $this->_width = $width; + } + + /** + * Returns the track's visual presentation height. This needs not be the + * same as the pixel height of the images; all images in the sequence are + * scaled to this height, before any overall transformation of the track + * represented by the matrix. The pixel height of the images is the default + * value. + * + * @return integer + */ + public function getHeight() + { + return $this->_height; + } + + /** + * Sets the track's visual presentation height. This needs not be the + * same as the pixel height of the images; all images in the sequence are + * scaled to this height, before any overall transformation of the track + * represented by the matrix. The pixel height of the images should be the + * default value. + * + * @param integer $height The height. + */ + public function setHeight($height) + { + $this->_height = $height; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + + ($this->getVersion() == 1 ? 32 : 20) + 60; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + if ($this->getVersion() == 1) { + $writer->writeInt64BE($this->_creationTime) + ->writeInt64BE($this->_modificationTime) + ->writeUInt32BE($this->_trackId) + ->writeUInt32BE(0) + ->writeInt64BE($this->_duration); + } else { + $writer->writeUInt32BE($this->_creationTime) + ->writeUInt32BE($this->_modificationTime) + ->writeUInt32BE($this->_trackId) + ->writeUInt32BE(0) + ->writeUInt32BE($this->_duration); + } + + @list(, $volumeDecimals) = explode('.', (float)$this->_volume); + $writer->write(str_pad('', 8, "\0")) + ->writeInt16BE($this->_layer) + ->writeInt16BE($this->_alternateGroup) + ->writeUInt16BE(floor($this->_volume) << 8 | $volumeDecimals) + ->write(str_pad('', 2, "\0")); + for ($i = 0; $i < 9; $i++) { + $writer->writeUInt32BE($this->_matrix[$i]); + } + @list(, $widthDecimals) = explode('.', (float)$this->_width); + @list(, $heightDecimals) = explode('.', (float)$this->_height); + $writer->writeUInt32BE(floor($this->_width) << 16 | $widthDecimals) + ->writeUInt32BE(floor($this->_height) << 16 | $heightDecimals); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Traf.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Traf.php index 1f21e4f1..7047f432 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Traf.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Traf.php @@ -1,77 +1,77 @@ -Track Fragment Box there is a set of track fragments, zero - * or more per track. The track fragments in turn contain zero or more track - * runs, each of which document a contiguous run of samples for that track. - * - * Within these structures, many fields are optional and can be defaulted. It is - * possible to add empty time to a track using these structures, as well as - * adding samples. Empty inserts can be used in audio tracks doing silence - * suppression, for example. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Traf.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Traf extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Track Fragment Box there is a set of track fragments, zero + * or more per track. The track fragments in turn contain zero or more track + * runs, each of which document a contiguous run of samples for that track. + * + * Within these structures, many fields are optional and can be defaulted. It is + * possible to add empty time to a track using these structures, as well as + * adding samples. Empty inserts can be used in audio tracks doing silence + * suppression, for example. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Traf.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Traf extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Trak.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Trak.php index fbac9d52..20a36848 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Trak.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Trak.php @@ -1,83 +1,83 @@ -Track Box is a container box for a single track of a presentation. - * A presentation consists of one or more tracks. Each track is independent of - * the other tracks in the presentation and carries its own temporal and spatial - * information. Each track will contain its associated - * {@link Zend_Media_Iso14496_Box_Mdia Media Box}. - * - * Tracks are used for two purposes: - * (a) to contain media data (media tracks) and - * (b) to contain packetization information for streaming protocols - * (hint tracks). - * There shall be at least one media track within an ISO file, and all the media - * tracks that contributed to the hint tracks shall remain in the file, even if - * the media data within them is not referenced by the hint tracks; after - * deleting all hint tracks, the entire un-hinted presentation shall remain. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trak.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Trak extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Track Box is a container box for a single track of a presentation. + * A presentation consists of one or more tracks. Each track is independent of + * the other tracks in the presentation and carries its own temporal and spatial + * information. Each track will contain its associated + * {@link Zend_Media_Iso14496_Box_Mdia Media Box}. + * + * Tracks are used for two purposes: + * (a) to contain media data (media tracks) and + * (b) to contain packetization information for streaming protocols + * (hint tracks). + * There shall be at least one media track within an ISO file, and all the media + * tracks that contributed to the hint tracks shall remain in the file, even if + * the media data within them is not referenced by the hint tracks; after + * deleting all hint tracks, the entire un-hinted presentation shall remain. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trak.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Trak extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Tref.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Tref.php index 83555548..885d2129 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Tref.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Tref.php @@ -1,81 +1,81 @@ -Track Reference Box provides a reference from the containing track - * to another track in the presentation. These references are typed. A - * {@link Zend_Media_Iso14496_Box_Hint hint} reference links from the containing - * hint track to the media data that it hints. A content description reference - * {@link Zend_Media_Iso14496_Box_Cdsc cdsc} links a descriptive or metadata - * track to the content which it describes. - * - * Exactly one Track Reference Box can be contained within the - * {@link Zend_Media_Iso14496_Box_Trak Track Box}. - * - * If this box is not present, the track is not referencing any other track in - * any way. The reference array is sized to fill the reference type box. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Tref.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Tref extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +Track Reference Box provides a reference from the containing track + * to another track in the presentation. These references are typed. A + * {@link Zend_Media_Iso14496_Box_Hint hint} reference links from the containing + * hint track to the media data that it hints. A content description reference + * {@link Zend_Media_Iso14496_Box_Cdsc cdsc} links a descriptive or metadata + * track to the content which it describes. + * + * Exactly one Track Reference Box can be contained within the + * {@link Zend_Media_Iso14496_Box_Trak Track Box}. + * + * If this box is not present, the track is not referencing any other track in + * any way. The reference array is sized to fill the reference type box. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Tref.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Tref extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Trex.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Trex.php index 3f3e1cc4..1e8bcb07 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Trex.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Trex.php @@ -1,214 +1,214 @@ -Track Extends Box sets up default values used by the movie - * fragments. By setting defaults in this way, space and complexity can be saved - * in each {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box}. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Trex.php 212 2011-04-30 06:14:16Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Trex extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_trackId; - - /** @var integer */ - private $_defaultSampleDescriptionIndex; - - /** @var integer */ - private $_defaultSampleDuration; - - /** @var integer */ - private $_defaultSampleSize; - - /** @var integer */ - private $_defaultSampleFlags; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - * @todo The sample flags could be parsed further - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_trackId = $this->_reader->readUInt32BE(); - $this->_defaultSampleDescriptionIndex = $this->_reader->readUInt32BE(); - $this->_defaultSampleDuration = $this->_reader->readUInt32BE(); - $this->_defaultSampleSize = $this->_reader->readUInt32BE(); - $this->_defaultSampleFlags = $this->_reader->readUInt32BE(); - } - - /** - * Returns the default track identifier. - * - * @return integer - */ - public function getTrackId() - { - return $this->_trackId; - } - - /** - * Sets the default track identifier. - * - * @param integer $trackId The track identifier. - */ - public function setTrackId($trackId) - { - $this->_trackId = $trackId; - } - - /** - * Returns the default sample description index. - * - * @return integer - */ - public function getDefaultSampleDescriptionIndex() - { - return $this->_defaultSampleDescriptionIndex; - } - - /** - * Sets the default sample description index. - * - * @param integer $defaultSampleDescriptionIndex The description index. - */ - public function setDefaultSampleDescriptionIndex - ($defaultSampleDescriptionIndex) - { - $this->_defaultSampleDescriptionIndex = $defaultSampleDescriptionIndex; - } - - /** - * Returns the default sample duration. - * - * @return integer - */ - public function getDefaultSampleDuration() - { - return $this->_defaultSampleDuration; - } - - /** - * Sets the default sample duration. - * - * @param integer $defaultSampleDuration The sample duration. - */ - public function setDefaultSampleDuration($defaultSampleDuration) - { - $this->_defaultSampleDuration = $defaultSampleDuration; - } - - /** - * Returns the default sample size. - * - * @return integer - */ - public function getDefaultSampleSize() - { - return $this->_defaultSampleSize; - } - - /** - * Sets the default sample size. - * - * @param integer $defaultSampleSize The sample size. - */ - public function setDefaultSampleSize($defaultSampleSize) - { - $this->_defaultSampleSize = $defaultSampleSize; - } - - /** - * Returns the default sample flags. - * - * @return integer - */ - public function getDefaultSampleFlags() - { - return $this->_defaultSampleFlags; - } - - /** - * Sets the default sample flags. - * - * @param integer $defaultSampleFlags The sample flags. - */ - public function setDefaultSampleFlags() - { - $this->_defaultSampleFlags = $defaultSampleFlags; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 20; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_trackId) - ->writeUInt32BE($this->_defaultSampleDescriptionIndex) - ->writeUInt32BE($this->_defaultSampleDuration) - ->writeUInt32BE($this->_defaultSampleSize) - ->writeUInt32BE($this->_defaultSampleFlags); - } -} +Track Extends Box sets up default values used by the movie + * fragments. By setting defaults in this way, space and complexity can be saved + * in each {@link Zend_Media_Iso14496_Box_Traf Track Fragment Box}. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Trex.php 212 2011-04-30 06:14:16Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Trex extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_trackId; + + /** @var integer */ + private $_defaultSampleDescriptionIndex; + + /** @var integer */ + private $_defaultSampleDuration; + + /** @var integer */ + private $_defaultSampleSize; + + /** @var integer */ + private $_defaultSampleFlags; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + * @todo The sample flags could be parsed further + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_trackId = $this->_reader->readUInt32BE(); + $this->_defaultSampleDescriptionIndex = $this->_reader->readUInt32BE(); + $this->_defaultSampleDuration = $this->_reader->readUInt32BE(); + $this->_defaultSampleSize = $this->_reader->readUInt32BE(); + $this->_defaultSampleFlags = $this->_reader->readUInt32BE(); + } + + /** + * Returns the default track identifier. + * + * @return integer + */ + public function getTrackId() + { + return $this->_trackId; + } + + /** + * Sets the default track identifier. + * + * @param integer $trackId The track identifier. + */ + public function setTrackId($trackId) + { + $this->_trackId = $trackId; + } + + /** + * Returns the default sample description index. + * + * @return integer + */ + public function getDefaultSampleDescriptionIndex() + { + return $this->_defaultSampleDescriptionIndex; + } + + /** + * Sets the default sample description index. + * + * @param integer $defaultSampleDescriptionIndex The description index. + */ + public function setDefaultSampleDescriptionIndex + ($defaultSampleDescriptionIndex) + { + $this->_defaultSampleDescriptionIndex = $defaultSampleDescriptionIndex; + } + + /** + * Returns the default sample duration. + * + * @return integer + */ + public function getDefaultSampleDuration() + { + return $this->_defaultSampleDuration; + } + + /** + * Sets the default sample duration. + * + * @param integer $defaultSampleDuration The sample duration. + */ + public function setDefaultSampleDuration($defaultSampleDuration) + { + $this->_defaultSampleDuration = $defaultSampleDuration; + } + + /** + * Returns the default sample size. + * + * @return integer + */ + public function getDefaultSampleSize() + { + return $this->_defaultSampleSize; + } + + /** + * Sets the default sample size. + * + * @param integer $defaultSampleSize The sample size. + */ + public function setDefaultSampleSize($defaultSampleSize) + { + $this->_defaultSampleSize = $defaultSampleSize; + } + + /** + * Returns the default sample flags. + * + * @return integer + */ + public function getDefaultSampleFlags() + { + return $this->_defaultSampleFlags; + } + + /** + * Sets the default sample flags. + * + * @param integer $defaultSampleFlags The sample flags. + */ + public function setDefaultSampleFlags() + { + $this->_defaultSampleFlags = $defaultSampleFlags; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 20; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_trackId) + ->writeUInt32BE($this->_defaultSampleDescriptionIndex) + ->writeUInt32BE($this->_defaultSampleDuration) + ->writeUInt32BE($this->_defaultSampleSize) + ->writeUInt32BE($this->_defaultSampleFlags); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Udta.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Udta.php index 9664d35d..4b996a66 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Udta.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Udta.php @@ -1,75 +1,75 @@ -User Data Box contains objects that declare user information about - * the containing box and its data (presentation or track). - * - * The User Data Box is a container box for informative user-data. This user - * data is formatted as a set of boxes with more specific box types, which - * declare more precisely their content. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Udta.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Udta extends Zend_Media_Iso14496_Box -{ - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - $this->setContainer(true); - - if ($reader === null) { - return; - } - - $this->constructBoxes(); - } -} +User Data Box contains objects that declare user information about + * the containing box and its data (presentation or track). + * + * The User Data Box is a container box for informative user-data. This user + * data is formatted as a set of boxes with more specific box types, which + * declare more precisely their content. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Udta.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Udta extends Zend_Media_Iso14496_Box +{ + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + $this->setContainer(true); + + if ($reader === null) { + return; + } + + $this->constructBoxes(); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Url.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Url.php index a15bfe35..ec0cb869 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Url.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Url.php @@ -1,122 +1,122 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Url.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Url extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_location; - - /** - * Indicates that the media data is in the same file as the Movie Box - * containing this data reference. - */ - const SELF_CONTAINED = 1; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_location = $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - } - - /** - * Returns the location. - * - * @return string - */ - public function getLocation() - { - return $this->_location; - } - - /** - * Sets the location. - * - * @param string $location The location string. - */ - public function setLocation($location) - { - $this->_location = $location; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + strlen($this->_location); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_location); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Url.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Url extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_location; + + /** + * Indicates that the media data is in the same file as the Movie Box + * containing this data reference. + */ + const SELF_CONTAINED = 1; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_location = $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + } + + /** + * Returns the location. + * + * @return string + */ + public function getLocation() + { + return $this->_location; + } + + /** + * Sets the location. + * + * @param string $location The location string. + */ + public function setLocation($location) + { + $this->_location = $location; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + strlen($this->_location); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_location); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Urn.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Urn.php index 26d72bd1..df57e2f0 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Urn.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Urn.php @@ -1,148 +1,148 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Urn.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Urn extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_name; - - /** @var string */ - private $_location; - - /** - * Indicates that the media data is in the same file as the Movie Box - * containing this data reference. - */ - const SELF_CONTAINED = 1; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - list ($this->_name, $this->_location) = preg_split - ("/\\x00/", $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset())); - } - - /** - * Returns the name. - * - * @return string - */ - public function getName() - { - return $this->_name; - } - - /** - * Sets the name. - * - * @param string $name The name. - */ - public function setName($name) - { - $this->_name = $name; - } - - /** - * Returns the location. - * - * @return string - */ - public function getLocation() - { - return $this->_location; - } - - /** - * Sets the location. - * - * @param string $location The location. - */ - public function setLocation($location) - { - $this->_location = $location; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + - strlen($this->_name) + 1 + strlen($this->_location); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeString8($this->_name, 1) - ->write($this->_location); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Urn.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Urn extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_name; + + /** @var string */ + private $_location; + + /** + * Indicates that the media data is in the same file as the Movie Box + * containing this data reference. + */ + const SELF_CONTAINED = 1; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + list ($this->_name, $this->_location) = preg_split + ("/\\x00/", $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset())); + } + + /** + * Returns the name. + * + * @return string + */ + public function getName() + { + return $this->_name; + } + + /** + * Sets the name. + * + * @param string $name The name. + */ + public function setName($name) + { + $this->_name = $name; + } + + /** + * Returns the location. + * + * @return string + */ + public function getLocation() + { + return $this->_location; + } + + /** + * Sets the location. + * + * @param string $location The location. + */ + public function setLocation($location) + { + $this->_location = $location; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + + strlen($this->_name) + 1 + strlen($this->_location); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeString8($this->_name, 1) + ->write($this->_location); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Vmhd.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Vmhd.php index cef56969..6e1b0c12 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Vmhd.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Vmhd.php @@ -1,153 +1,153 @@ -Video Media Header Box contains general presentation information, - * independent of the coding, for video media. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Vmhd.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Vmhd extends Zend_Media_Iso14496_FullBox -{ - /** @var integer */ - private $_graphicsMode = 0; - - /** @var Array */ - private $_opcolor = array(0, 0, 0); - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - $this->setFlags(1); - return; - } - - $this->_graphicsMode = $this->_reader->readUInt16BE(); - $this->_opcolor = array - ($this->_reader->readUInt16BE(), - $this->_reader->readUInt16BE(), - $this->_reader->readUInt16BE()); - } - - /** - * Returns the composition mode for this video track, from the following - * enumerated set, which may be extended by derived specifications: - * - *
      - *
    • copy = 0 copy over the existing image
    • - *
    - * - * @return integer - */ - public function getGraphicsMode() - { - return $this->_graphicsMode; - } - - /** - * Sets the composition mode for this video track. - * - * @param integer $graphicsMode The composition mode. - */ - public function setGraphicsMode($graphicsMode) - { - $this->_graphicsMode = $graphicsMode; - } - - /** - * Returns an array of 3 colour values (red, green, blue) available for use - * by graphics modes. - * - * @return Array - */ - public function getOpcolor() - { - return $this->_opcolor; - } - - /** - * Sets the array of 3 colour values (red, green, blue) available for use - * by graphics modes. - * - * @param Array $opcolor An array of 3 colour values - */ - public function setOpcolor($opcolor) - { - $this->_opcolor = $opcolor; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 8; - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt16BE($this->_graphicsMode) - ->writeUInt16BE($this->_opcolor[0]) - ->writeUInt16BE($this->_opcolor[1]) - ->writeUInt16BE($this->_opcolor[2]); - } -} +Video Media Header Box contains general presentation information, + * independent of the coding, for video media. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Vmhd.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Vmhd extends Zend_Media_Iso14496_FullBox +{ + /** @var integer */ + private $_graphicsMode = 0; + + /** @var Array */ + private $_opcolor = array(0, 0, 0); + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + $this->setFlags(1); + return; + } + + $this->_graphicsMode = $this->_reader->readUInt16BE(); + $this->_opcolor = array + ($this->_reader->readUInt16BE(), + $this->_reader->readUInt16BE(), + $this->_reader->readUInt16BE()); + } + + /** + * Returns the composition mode for this video track, from the following + * enumerated set, which may be extended by derived specifications: + * + *
      + *
    • copy = 0 copy over the existing image
    • + *
    + * + * @return integer + */ + public function getGraphicsMode() + { + return $this->_graphicsMode; + } + + /** + * Sets the composition mode for this video track. + * + * @param integer $graphicsMode The composition mode. + */ + public function setGraphicsMode($graphicsMode) + { + $this->_graphicsMode = $graphicsMode; + } + + /** + * Returns an array of 3 colour values (red, green, blue) available for use + * by graphics modes. + * + * @return Array + */ + public function getOpcolor() + { + return $this->_opcolor; + } + + /** + * Sets the array of 3 colour values (red, green, blue) available for use + * by graphics modes. + * + * @param Array $opcolor An array of 3 colour values + */ + public function setOpcolor($opcolor) + { + $this->_opcolor = $opcolor; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 8; + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt16BE($this->_graphicsMode) + ->writeUInt16BE($this->_opcolor[0]) + ->writeUInt16BE($this->_opcolor[1]) + ->writeUInt16BE($this->_opcolor[2]); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Box/Xml.php b/app/libs/vendor/Zend/Media/Iso14496/Box/Xml.php index 9f8e13f7..1f531862 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Box/Xml.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Box/Xml.php @@ -1,123 +1,123 @@ -XML Box forms may be used. - * The {@link Zend_Media_Iso14496_Box_Bxml Binary XML Box} may only be used when - * there is a single well-defined binarization of the XML for that defined - * format as identified by the handler. - * - * Within an XML box the data is in UTF-8 format unless the data starts with a - * byte-order-mark (BOM), which indicates that the data is in UTF-16 format. - * - * @category Zend - * @package Zend_Media - * @subpackage ISO14496 - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Xml.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -final class Zend_Media_Iso14496_Box_Xml extends Zend_Media_Iso14496_FullBox -{ - /** @var string */ - private $_xml; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_xml = $this->_reader->read - ($this->getOffset() + $this->getSize() - - $this->_reader->getOffset()); - } - - /** - * Returns the XML data. - * - * @return string - */ - public function getXml() - { - return $this->_xml; - } - - /** - * Sets the XML data. - * - * @param string $xml The XML data. - */ - public function setXml($xml) - { - $this->_xml = $xml; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + strlen($this->_xml); - } - - /** - * Writes the box data. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->write($this->_xml); - } -} +XML Box forms may be used. + * The {@link Zend_Media_Iso14496_Box_Bxml Binary XML Box} may only be used when + * there is a single well-defined binarization of the XML for that defined + * format as identified by the handler. + * + * Within an XML box the data is in UTF-8 format unless the data starts with a + * byte-order-mark (BOM), which indicates that the data is in UTF-16 format. + * + * @category Zend + * @package Zend_Media + * @subpackage ISO14496 + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Xml.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +final class Zend_Media_Iso14496_Box_Xml extends Zend_Media_Iso14496_FullBox +{ + /** @var string */ + private $_xml; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_xml = $this->_reader->read + ($this->getOffset() + $this->getSize() - + $this->_reader->getOffset()); + } + + /** + * Returns the XML data. + * + * @return string + */ + public function getXml() + { + return $this->_xml; + } + + /** + * Sets the XML data. + * + * @param string $xml The XML data. + */ + public function setXml($xml) + { + $this->_xml = $xml; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + strlen($this->_xml); + } + + /** + * Writes the box data. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->write($this->_xml); + } +} diff --git a/app/libs/vendor/Zend/Media/Iso14496/Exception.php b/app/libs/vendor/Zend/Media/Iso14496/Exception.php index 7fbcbcd0..51a92514 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/Exception.php +++ b/app/libs/vendor/Zend/Media/Iso14496/Exception.php @@ -1,52 +1,52 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Iso14496_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Iso14496_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Iso14496/FullBox.php b/app/libs/vendor/Zend/Media/Iso14496/FullBox.php index 92d1f206..28df74c0 100644 --- a/app/libs/vendor/Zend/Media/Iso14496/FullBox.php +++ b/app/libs/vendor/Zend/Media/Iso14496/FullBox.php @@ -1,150 +1,150 @@ - - * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: FullBox.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Iso14496_FullBox extends Zend_Media_Iso14496_Box -{ - /** @var integer */ - protected $_version = 0; - - /** @var integer */ - protected $_flags = 0; - - /** - * Constructs the class with given parameters and reads box related data - * from the ISO Base Media file. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader = null, &$options = array()) - { - parent::__construct($reader, $options); - - if ($reader === null) { - return; - } - - $this->_version = - (($field = $this->_reader->readUInt32BE()) >> 24) & 0xff; - $this->_flags = $field & 0xffffff; - } - - /** - * Returns the version of this format of the box. - * - * @return integer - */ - public function getVersion() - { - return $this->_version; - } - - /** - * Sets the version of this format of the box. - * - * @param integer $version The version. - */ - public function setVersion($version) - { - $this->_version = $version; - } - - /** - * Checks whether or not the flag is set. Returns true if the - * flag is set, false otherwise. - * - * @param integer $flag The flag to query. - * @return boolean - */ - public function hasFlag($flag) - { - return ($this->_flags & $flag) == $flag; - } - - /** - * Returns the map of flags. - * - * @return integer - */ - public function getFlags() - { - return $this->_flags; - } - - /** - * Sets the map of flags. - * - * @param string $flags The map of flags. - */ - public function setFlags($flags) - { - $this->_flags = $flags; - } - - /** - * Returns the box heap size in bytes. - * - * @return integer - */ - public function getHeapSize() - { - return parent::getHeapSize() + 4; - } - - /** - * Writes the box data without the header. - * - * @param Zend_Io_Writer $writer The writer object. - * @return void - */ - protected function _writeData($writer) - { - parent::_writeData($writer); - $writer->writeUInt32BE($this->_version << 24 | $this->_flags); - } -} + + * @copyright Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: FullBox.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Iso14496_FullBox extends Zend_Media_Iso14496_Box +{ + /** @var integer */ + protected $_version = 0; + + /** @var integer */ + protected $_flags = 0; + + /** + * Constructs the class with given parameters and reads box related data + * from the ISO Base Media file. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader = null, &$options = array()) + { + parent::__construct($reader, $options); + + if ($reader === null) { + return; + } + + $this->_version = + (($field = $this->_reader->readUInt32BE()) >> 24) & 0xff; + $this->_flags = $field & 0xffffff; + } + + /** + * Returns the version of this format of the box. + * + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Sets the version of this format of the box. + * + * @param integer $version The version. + */ + public function setVersion($version) + { + $this->_version = $version; + } + + /** + * Checks whether or not the flag is set. Returns true if the + * flag is set, false otherwise. + * + * @param integer $flag The flag to query. + * @return boolean + */ + public function hasFlag($flag) + { + return ($this->_flags & $flag) == $flag; + } + + /** + * Returns the map of flags. + * + * @return integer + */ + public function getFlags() + { + return $this->_flags; + } + + /** + * Sets the map of flags. + * + * @param string $flags The map of flags. + */ + public function setFlags($flags) + { + $this->_flags = $flags; + } + + /** + * Returns the box heap size in bytes. + * + * @return integer + */ + public function getHeapSize() + { + return parent::getHeapSize() + 4; + } + + /** + * Writes the box data without the header. + * + * @param Zend_Io_Writer $writer The writer object. + * @return void + */ + protected function _writeData($writer) + { + parent::_writeData($writer); + $writer->writeUInt32BE($this->_version << 24 | $this->_flags); + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs.php b/app/libs/vendor/Zend/Media/Mpeg/Abs.php index 0455c235..f1931d4d 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs.php @@ -1,456 +1,456 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Abs.php 261 2012-03-05 20:43:15Z svollbehr $ - * @todo Implement validation routines - */ -final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object -{ - /** @var integer */ - private $_bytes; - - /** @var Array */ - private $_frames = array(); - - /** @var Zend_Media_Mpeg_Abs_XingHeader */ - private $_xingHeader = null; - - /** @var Zend_Media_Mpeg_Abs_LameHeader */ - private $_lameHeader = null; - - /** @var Zend_Media_Mpeg_Abs_VbriHeader */ - private $_vbriHeader = null; - - /** @var integer */ - private $_cumulativeBitrate = 0; - - /** @var integer */ - private $_cumulativePlayDuration = 0; - - /** @var integer */ - private $_estimatedBitrate = 0; - - /** @var integer */ - private $_estimatedPlayDuration = 0; - - /** @var integer */ - private $_lastFrameOffset = false; - - /** - * Constructs the Zend_Media_Mpeg_ABS class with given file and options. - * - * The following options are currently recognized: - * o readmode -- Can be one of full or lazy and determines when the read - * of frames and their data happens. When in full mode the data is read - * automatically during the instantiation of the frame and all the - * frames are read during the instantiation of this class. While this - * allows faster validation and data fetching, it is unnecessary in - * terms of determining just the play duration of the file. Defaults to - * lazy. - * - * o estimatePrecision -- Only applicaple with lazy read mode to determine - * the precision of play duration estimate. This precision is equal to - * how many frames are read before fixing the average bitrate that is - * used to calculate the play duration estimate of the whole file. Each - * frame adds about 0.1-0.2ms to the processing of the file. Defaults to - * 1000. - * - * When in lazy data reading mode it is first checked whether a VBR header - * is found in a file. If so, the play duration is calculated based no its - * data and no further frames are read from the file. If no VBR header is - * found, frames up to estimatePrecision are read to calculate an average - * bitrate. - * - * Hence, only zero or estimatePrecision number of frames are - * read in lazy data reading mode. The rest of the frames are read - * automatically when directly referenced, ie the data is read when it is - * needed. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception($e->getMessage()); - } - } - $this->setOptions($options); - - $offset = $this->_reader->getOffset(); - $this->_bytes = $this->_reader->getSize(); - - /* Skip ID3v1 tag */ - $this->_reader->setOffset(-128); - if ($this->_reader->read(3) == 'TAG') { - $this->_bytes -= 128; - } - $this->_reader->setOffset($offset); - - /* Skip ID3v2 tags (some files errorneusly contain multiple tags) */ - while ($this->_reader->readString8(3) == 'ID3') { - require_once 'Zend/Media/Id3/Header.php'; - $header = new Zend_Media_Id3_Header($this->_reader); - $this->_reader->skip - ($header->getSize() + - ($header->hasFlag(Zend_Media_Id3_Header::FOOTER) ? 10 : 0)); - $offset = $this->_reader->getOffset(); - } - $this->_reader->setOffset($offset); - - /* Check whether the ABS is contained within a RIFF chunk */ - $offset = $this->_reader->getOffset(); - - if ($this->_reader->readString8(4) == 'RIFF') { - $riffSize = $this->_reader->readUInt32LE(); - $riffType = $this->_reader->read(4); // WAVE - - while ($this->_reader->getOffset() < $offset + 8 + $riffSize - 1) { - $chunkId = $this->_reader->read(4); - $chunkSize = $this->_reader->readUInt32LE(); - - if ($chunkId == 'fmt ') { - if ($this->_reader->readInt16LE() != 85) { // 85: MPEG-1 Layer 3 Codec - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception - ('File does not contain a valid MPEG Audio Bit Stream (Contains RIFF with no MPEG ABS)'); - } else { - $this->_reader->skip($chunkSize - 2); - } - } else if ($chunkId == 'data') { - $offset = $this->_reader->getOffset(); - break; - } else { - $this->_reader->skip($chunkSize); - } - } - } else { - $this->_reader->setOffset($offset); - } - - /* Check for VBR headers */ - $this->_frames[] = $firstFrame = - new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); - - $offset = $this->_reader->getOffset(); - - $this->_reader->setOffset - ($firstFrame->getOffset() + 4 + self::$sidesizes - [$firstFrame->getFrequencyType()][$firstFrame->getMode()]); - if (($xing = $this->_reader->readString8(4)) == 'Xing' || - $xing == 'Info') { - require_once 'Zend/Media/Mpeg/Abs/XingHeader.php'; - $this->_xingHeader = - new Zend_Media_Mpeg_Abs_XingHeader($this->_reader, $options); - if ($this->_reader->readString8(4) == 'LAME') { - require_once 'Zend/Media/Mpeg/Abs/LameHeader.php'; - $this->_lameHeader = - new Zend_Media_Mpeg_Abs_LameHeader - ($this->_reader, $options); - } - - // A header frame is not counted as an audio frame - array_pop($this->_frames); - } - - $this->_reader->setOffset($firstFrame->getOffset() + 4 + 32); - if ($this->_reader->readString8(4) == 'VBRI') { - require_once 'Zend/Media/Mpeg/Abs/VbriHeader.php'; - $this->_vbriHeader = - new Zend_Media_Mpeg_Abs_VbriHeader($this->_reader, $options); - - // A header frame is not counted as an audio frame - array_pop($this->_frames); - } - - $this->_reader->setOffset($offset); - - // Ensure we always have read at least one frame - if (empty($this->_frames)) { - $this->_readFrames(1); - } - - /* Read necessary frames */ - if ($this->getOption('readmode', 'lazy') == 'lazy') { - if ((($header = $this->_xingHeader) !== null || - ($header = $this->_vbriHeader) !== null) && - $header->getFrames() != 0) { - $this->_estimatedPlayDuration = $header->getFrames() * - $firstFrame->getSamples() / - $firstFrame->getSamplingFrequency(); - if ($this->_lameHeader !== null) { - $this->_estimatedBitrate = $this->_lameHeader->getBitrate(); - if ($this->_estimatedBitrate == 255) { - $this->_estimatedBitrate = round - (($this->_lameHeader->getMusicLength()) / - (($header->getFrames() * - $firstFrame->getSamples()) / - $firstFrame->getSamplingFrequency()) / 1000 * 8); - } - } else { - $this->_estimatedBitrate = ($this->_bytes - $firstFrame->getOffset()) / - $this->_estimatedPlayDuration / 1000 * 8; - } - } else { - $this->_readFrames($this->getOption('estimatePrecision', 1000)); - - $this->_estimatedBitrate = - $this->_cumulativeBitrate / count($this->_frames); - $this->_estimatedPlayDuration = - ($this->_bytes - $firstFrame->getOffset()) / - ($this->_estimatedBitrate * 1000 / 8); - } - } else { - $this->_readFrames(); - - $this->_estimatedBitrate = - $this->_cumulativeBitrate / count($this->_frames); - $this->_estimatedPlayDuration = $this->_cumulativePlayDuration; - } - } - - /** - * Returns true if the audio bitstream contains the Xing VBR - * header, or false otherwise. - * - * @return boolean - */ - public function hasXingHeader() - { - return $this->_xingHeader !== null; - } - - /** - * Returns the Xing VBR header, or null if not found in the audio - * bitstream. - * - * @return Zend_Media_Mpeg_Abs_XingHeader - */ - public function getXingHeader() - { - return $this->_xingHeader; - } - - /** - * Returns true if the audio bitstream contains the LAME VBR - * header, or false otherwise. - * - * @return boolean - */ - public function hasLameHeader() - { - return $this->_lameHeader !== null; - } - - /** - * Returns the LAME VBR header, or null if not found in the audio - * bitstream. - * - * @return Zend_Media_Mpeg_Abs_LameHeader - */ - public function getLameHeader() - { - return $this->_lameHeader; - } - - /** - * Returns true if the audio bitstream contains the Fraunhofer - * IIS VBR header, or false otherwise. - * - * @return boolean - */ - public function hasVbriHeader() - { - return $this->_vbriHeader !== null; - } - - /** - * Returns the Fraunhofer IIS VBR header, or null if not found in - * the audio bitstream. - * - * @return Zend_Media_Mpeg_Abs_VbriHeader - */ - public function getVbriHeader() - { - return $this->_vbriHeader; - } - - /** - * Returns the bitrate estimate. This value is either fetched from one of - * the headers or calculated based on the read frames. - * - * @return integer - */ - public function getBitrateEstimate() - { - return $this->_estimatedBitrate; - } - - /** - * For variable bitrate files this method returns the exact average bitrate - * of the whole file. - * - * @return integer - */ - public function getBitrate() - { - if ($this->getOption('readmode', 'lazy') == 'lazy') { - $this->_readFrames(); - } - return $this->_cumulativeBitrate / count($this->_frames); - } - - /** - * Returns the playtime estimate, in seconds. - * - * @return integer - */ - public function getLengthEstimate() - { - return $this->_estimatedPlayDuration; - } - - /** - * Returns the exact playtime in seconds. In lazy reading mode the frames - * are read from the file the first time you call this method to get the - * exact playtime of the file. - * - * @return integer - */ - public function getLength() - { - if ($this->getOption('readmode', 'lazy') == 'lazy') { - $this->_readFrames(); - } - return $this->_cumulativePlayDuration; - } - - /** - * Returns the playtime estimate as a string in the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLengthEstimate() - { - return $this->formatTime($this->getLengthEstimate()); - } - - /** - * Returns the exact playtime given in seconds as a string in the form of - * [hours:]minutes:seconds.milliseconds. In lazy reading mode the frames are - * read from the file the first time you call this method to get the exact - * playtime of the file. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLength() - { - return $this->formatTime($this->getLength()); - } - - /** - * Returns all the frames of the audio bitstream as an array. In lazy - * reading mode the frames are read from the file the first time you call - * this method. - * - * @return Array - */ - public function getFrames() - { - if ($this->getOption('readmode', 'lazy') == 'lazy') { - $this->_readFrames(); - } - return $this->_frames; - } - - /** - * Reads frames up to given limit. If called subsequently the method - * continues after the last frame read in the last call, again to read up - * to the limit or just the rest of the frames. - * - * @param integer $limit The maximum number of frames read from the - * bitstream - */ - private function _readFrames($limit = null) - { - if ($this->_lastFrameOffset !== false) { - $this->_reader->setOffset($this->_lastFrameOffset); - } - - for ($i = 0; ($j = $this->_reader->getOffset()) < $this->_bytes; $i++) { - $options = $this->getOptions(); - $frame = new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); - - $this->_cumulativePlayDuration += - (double)($frame->getLength() / - ($frame->getBitrate() * 1000 / 8)); - $this->_cumulativeBitrate += $frame->getBitrate(); - $this->_frames[] = $frame; - - if ($limit === null) { - $this->_lastFrameOffset = $this->_reader->getOffset(); - } - if (($limit !== null && (($i + 1) == $limit)) || - ($limit !== null && - ($j + $frame->getLength() >= $this->_bytes))) { - $this->_lastFrameOffset = $this->_reader->getOffset(); - break; - } - } - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Abs.php 261 2012-03-05 20:43:15Z svollbehr $ + * @todo Implement validation routines + */ +final class Zend_Media_Mpeg_Abs extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_bytes; + + /** @var Array */ + private $_frames = array(); + + /** @var Zend_Media_Mpeg_Abs_XingHeader */ + private $_xingHeader = null; + + /** @var Zend_Media_Mpeg_Abs_LameHeader */ + private $_lameHeader = null; + + /** @var Zend_Media_Mpeg_Abs_VbriHeader */ + private $_vbriHeader = null; + + /** @var integer */ + private $_cumulativeBitrate = 0; + + /** @var integer */ + private $_cumulativePlayDuration = 0; + + /** @var integer */ + private $_estimatedBitrate = 0; + + /** @var integer */ + private $_estimatedPlayDuration = 0; + + /** @var integer */ + private $_lastFrameOffset = false; + + /** + * Constructs the Zend_Media_Mpeg_ABS class with given file and options. + * + * The following options are currently recognized: + * o readmode -- Can be one of full or lazy and determines when the read + * of frames and their data happens. When in full mode the data is read + * automatically during the instantiation of the frame and all the + * frames are read during the instantiation of this class. While this + * allows faster validation and data fetching, it is unnecessary in + * terms of determining just the play duration of the file. Defaults to + * lazy. + * + * o estimatePrecision -- Only applicaple with lazy read mode to determine + * the precision of play duration estimate. This precision is equal to + * how many frames are read before fixing the average bitrate that is + * used to calculate the play duration estimate of the whole file. Each + * frame adds about 0.1-0.2ms to the processing of the file. Defaults to + * 1000. + * + * When in lazy data reading mode it is first checked whether a VBR header + * is found in a file. If so, the play duration is calculated based no its + * data and no further frames are read from the file. If no VBR header is + * found, frames up to estimatePrecision are read to calculate an average + * bitrate. + * + * Hence, only zero or estimatePrecision number of frames are + * read in lazy data reading mode. The rest of the frames are read + * automatically when directly referenced, ie the data is read when it is + * needed. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception($e->getMessage()); + } + } + $this->setOptions($options); + + $offset = $this->_reader->getOffset(); + $this->_bytes = $this->_reader->getSize(); + + /* Skip ID3v1 tag */ + $this->_reader->setOffset(-128); + if ($this->_reader->read(3) == 'TAG') { + $this->_bytes -= 128; + } + $this->_reader->setOffset($offset); + + /* Skip ID3v2 tags (some files errorneusly contain multiple tags) */ + while ($this->_reader->readString8(3) == 'ID3') { + require_once 'Zend/Media/Id3/Header.php'; + $header = new Zend_Media_Id3_Header($this->_reader); + $this->_reader->skip + ($header->getSize() + + ($header->hasFlag(Zend_Media_Id3_Header::FOOTER) ? 10 : 0)); + $offset = $this->_reader->getOffset(); + } + $this->_reader->setOffset($offset); + + /* Check whether the ABS is contained within a RIFF chunk */ + $offset = $this->_reader->getOffset(); + + if ($this->_reader->readString8(4) == 'RIFF') { + $riffSize = $this->_reader->readUInt32LE(); + $riffType = $this->_reader->read(4); // WAVE + + while ($this->_reader->getOffset() < $offset + 8 + $riffSize - 1) { + $chunkId = $this->_reader->read(4); + $chunkSize = $this->_reader->readUInt32LE(); + + if ($chunkId == 'fmt ') { + if ($this->_reader->readInt16LE() != 85) { // 85: MPEG-1 Layer 3 Codec + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception + ('File does not contain a valid MPEG Audio Bit Stream (Contains RIFF with no MPEG ABS)'); + } else { + $this->_reader->skip($chunkSize - 2); + } + } else if ($chunkId == 'data') { + $offset = $this->_reader->getOffset(); + break; + } else { + $this->_reader->skip($chunkSize); + } + } + } else { + $this->_reader->setOffset($offset); + } + + /* Check for VBR headers */ + $this->_frames[] = $firstFrame = + new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); + + $offset = $this->_reader->getOffset(); + + $this->_reader->setOffset + ($firstFrame->getOffset() + 4 + self::$sidesizes + [$firstFrame->getFrequencyType()][$firstFrame->getMode()]); + if (($xing = $this->_reader->readString8(4)) == 'Xing' || + $xing == 'Info') { + require_once 'Zend/Media/Mpeg/Abs/XingHeader.php'; + $this->_xingHeader = + new Zend_Media_Mpeg_Abs_XingHeader($this->_reader, $options); + if ($this->_reader->readString8(4) == 'LAME') { + require_once 'Zend/Media/Mpeg/Abs/LameHeader.php'; + $this->_lameHeader = + new Zend_Media_Mpeg_Abs_LameHeader + ($this->_reader, $options); + } + + // A header frame is not counted as an audio frame + array_pop($this->_frames); + } + + $this->_reader->setOffset($firstFrame->getOffset() + 4 + 32); + if ($this->_reader->readString8(4) == 'VBRI') { + require_once 'Zend/Media/Mpeg/Abs/VbriHeader.php'; + $this->_vbriHeader = + new Zend_Media_Mpeg_Abs_VbriHeader($this->_reader, $options); + + // A header frame is not counted as an audio frame + array_pop($this->_frames); + } + + $this->_reader->setOffset($offset); + + // Ensure we always have read at least one frame + if (empty($this->_frames)) { + $this->_readFrames(1); + } + + /* Read necessary frames */ + if ($this->getOption('readmode', 'lazy') == 'lazy') { + if ((($header = $this->_xingHeader) !== null || + ($header = $this->_vbriHeader) !== null) && + $header->getFrames() != 0) { + $this->_estimatedPlayDuration = $header->getFrames() * + $firstFrame->getSamples() / + $firstFrame->getSamplingFrequency(); + if ($this->_lameHeader !== null) { + $this->_estimatedBitrate = $this->_lameHeader->getBitrate(); + if ($this->_estimatedBitrate == 255) { + $this->_estimatedBitrate = round + (($this->_lameHeader->getMusicLength()) / + (($header->getFrames() * + $firstFrame->getSamples()) / + $firstFrame->getSamplingFrequency()) / 1000 * 8); + } + } else { + $this->_estimatedBitrate = ($this->_bytes - $firstFrame->getOffset()) / + $this->_estimatedPlayDuration / 1000 * 8; + } + } else { + $this->_readFrames($this->getOption('estimatePrecision', 1000)); + + $this->_estimatedBitrate = + $this->_cumulativeBitrate / count($this->_frames); + $this->_estimatedPlayDuration = + ($this->_bytes - $firstFrame->getOffset()) / + ($this->_estimatedBitrate * 1000 / 8); + } + } else { + $this->_readFrames(); + + $this->_estimatedBitrate = + $this->_cumulativeBitrate / count($this->_frames); + $this->_estimatedPlayDuration = $this->_cumulativePlayDuration; + } + } + + /** + * Returns true if the audio bitstream contains the Xing VBR + * header, or false otherwise. + * + * @return boolean + */ + public function hasXingHeader() + { + return $this->_xingHeader !== null; + } + + /** + * Returns the Xing VBR header, or null if not found in the audio + * bitstream. + * + * @return Zend_Media_Mpeg_Abs_XingHeader + */ + public function getXingHeader() + { + return $this->_xingHeader; + } + + /** + * Returns true if the audio bitstream contains the LAME VBR + * header, or false otherwise. + * + * @return boolean + */ + public function hasLameHeader() + { + return $this->_lameHeader !== null; + } + + /** + * Returns the LAME VBR header, or null if not found in the audio + * bitstream. + * + * @return Zend_Media_Mpeg_Abs_LameHeader + */ + public function getLameHeader() + { + return $this->_lameHeader; + } + + /** + * Returns true if the audio bitstream contains the Fraunhofer + * IIS VBR header, or false otherwise. + * + * @return boolean + */ + public function hasVbriHeader() + { + return $this->_vbriHeader !== null; + } + + /** + * Returns the Fraunhofer IIS VBR header, or null if not found in + * the audio bitstream. + * + * @return Zend_Media_Mpeg_Abs_VbriHeader + */ + public function getVbriHeader() + { + return $this->_vbriHeader; + } + + /** + * Returns the bitrate estimate. This value is either fetched from one of + * the headers or calculated based on the read frames. + * + * @return integer + */ + public function getBitrateEstimate() + { + return $this->_estimatedBitrate; + } + + /** + * For variable bitrate files this method returns the exact average bitrate + * of the whole file. + * + * @return integer + */ + public function getBitrate() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_cumulativeBitrate / count($this->_frames); + } + + /** + * Returns the playtime estimate, in seconds. + * + * @return integer + */ + public function getLengthEstimate() + { + return $this->_estimatedPlayDuration; + } + + /** + * Returns the exact playtime in seconds. In lazy reading mode the frames + * are read from the file the first time you call this method to get the + * exact playtime of the file. + * + * @return integer + */ + public function getLength() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_cumulativePlayDuration; + } + + /** + * Returns the playtime estimate as a string in the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLengthEstimate() + { + return $this->formatTime($this->getLengthEstimate()); + } + + /** + * Returns the exact playtime given in seconds as a string in the form of + * [hours:]minutes:seconds.milliseconds. In lazy reading mode the frames are + * read from the file the first time you call this method to get the exact + * playtime of the file. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLength() + { + return $this->formatTime($this->getLength()); + } + + /** + * Returns all the frames of the audio bitstream as an array. In lazy + * reading mode the frames are read from the file the first time you call + * this method. + * + * @return Array + */ + public function getFrames() + { + if ($this->getOption('readmode', 'lazy') == 'lazy') { + $this->_readFrames(); + } + return $this->_frames; + } + + /** + * Reads frames up to given limit. If called subsequently the method + * continues after the last frame read in the last call, again to read up + * to the limit or just the rest of the frames. + * + * @param integer $limit The maximum number of frames read from the + * bitstream + */ + private function _readFrames($limit = null) + { + if ($this->_lastFrameOffset !== false) { + $this->_reader->setOffset($this->_lastFrameOffset); + } + + for ($i = 0; ($j = $this->_reader->getOffset()) < $this->_bytes; $i++) { + $options = $this->getOptions(); + $frame = new Zend_Media_Mpeg_Abs_Frame($this->_reader, $options); + + $this->_cumulativePlayDuration += + (double)($frame->getLength() / + ($frame->getBitrate() * 1000 / 8)); + $this->_cumulativeBitrate += $frame->getBitrate(); + $this->_frames[] = $frame; + + if ($limit === null) { + $this->_lastFrameOffset = $this->_reader->getOffset(); + } + if (($limit !== null && (($i + 1) == $limit)) || + ($limit !== null && + ($j + $frame->getLength() >= $this->_bytes))) { + $this->_lastFrameOffset = $this->_reader->getOffset(); + break; + } + } + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs/Frame.php b/app/libs/vendor/Zend/Media/Mpeg/Abs/Frame.php index 656ab86b..f2bb2664 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs/Frame.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs/Frame.php @@ -1,574 +1,574 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Frame.php 261 2012-03-05 20:43:15Z svollbehr $ - */ -final class Zend_Media_Mpeg_Abs_Frame extends Zend_Media_Mpeg_Abs_Object -{ - /** - * The bitrate lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * ) - * - * - * @var Array - */ - private static $bitrates = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => array ( - 1 => 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, - 416, 448 - ), - self::LAYER_TWO => array ( - 1 => 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, - 384 - ), - self::LAYER_THREE => array ( - 1 => 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, - 320 - ) - ), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => array ( - 1 => 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, - 256 - ), - self::LAYER_TWO => array ( - 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 - ), - self::LAYER_THREE => array ( - 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 - ) - ) - ); - - /** - * Sample rate lookup table. The table has the following format. - * - * - * array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * - * - * @var Array - */ - private static $samplingFrequencies = array ( - self::VERSION_ONE => array (44100, 48000, 32000), - self::VERSION_TWO => array (22050, 24000, 16000), - self::VERSION_TWO_FIVE => array (11025, 12000, 8000) - ); - - /** - * Samples per frame lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => - * ) - * ) - * - * - * @var Array - */ - private static $samples = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => 384, - self::LAYER_TWO => 1152, - self::LAYER_THREE => 1152), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => 384, - self::LAYER_TWO => 1152, - self::LAYER_THREE => 576)); - - /** - * Coefficient lookup table. The table has the following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) - * ) - * ) - * - * - * @var Array - */ - private static $coefficients = array ( - self::SAMPLING_FREQUENCY_HIGH => array ( - self::LAYER_ONE => 12, self::LAYER_TWO => 144, - self::LAYER_THREE => 144 - ), - self::SAMPLING_FREQUENCY_LOW => array ( - self::LAYER_ONE => 12, self::LAYER_TWO => 144, - self::LAYER_THREE => 72 - ) - ); - - /** - * Slot size per layer lookup table. The table has the following format. - * - * - * array ( - * LAYER_ONE | LAYER_TWO | LAYER_TREE => - * ) - * - * - * @var Array - */ - private static $slotsizes = array ( - self::LAYER_ONE => 4, self::LAYER_TWO => 1, self::LAYER_THREE => 1 - ); - - /** @var integer */ - private $_offset; - - /** @var integer */ - private $_version; - - /** @var integer */ - private $_frequencyType; - - /** @var integer */ - private $_layer; - - /** @var integer */ - private $_redundancy; - - /** @var integer */ - private $_bitrate; - - /** @var integer */ - private $_samplingFrequency; - - /** @var integer */ - private $_padding; - - /** @var integer */ - private $_mode; - - /** @var integer */ - private $_modeExtension; - - /** @var integer */ - private $_copyright; - - /** @var integer */ - private $_original; - - /** @var integer */ - private $_emphasis; - - /** @var integer */ - private $_length; - - /** @var integer */ - private $_samples; - - /** @var integer */ - private $_crc = false; - - /** @var string */ - private $_data = false; - - /** - * Constructs the class with given parameters and reads object related data - * from the frame. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_offset = $this->_reader->getOffset(); - - $header = null; - for ($i = 0; $i < 5775 /* max attempts: max frame size x2 */; $i++) { - $header = $this->_reader->readUInt32BE(); - if (Zend_Bit_Twiddling::testAllBits(Zend_Bit_Twiddling::getValue($header, 21, 32), 0xffe)) { - break; - } - $this->_reader->setOffset(++$this->_offset + 1); - if ($this->_offset == $this->_reader->getSize() || $i == (5775 - 1)) { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception - ('File does not contain a valid MPEG Audio Bit Stream (Invalid frame sync and resynchronization failed)'); - } - } - - $this->_version = Zend_Bit_Twiddling::getValue($header, 19, 20); - $this->_frequencyType = Zend_Bit_Twiddling::testBit($header, 19); - $this->_layer = Zend_Bit_Twiddling::getValue($header, 17, 18); - $this->_redundancy = !Zend_Bit_Twiddling::testBit($header, 16); - $this->_bitrate = isset - (self::$bitrates[$this->_frequencyType][$this->_layer] - [$index = Zend_Bit_Twiddling::getValue($header, 12, 15)]) ? - self::$bitrates[$this->_frequencyType][$this->_layer][$index] : - false; - $this->_samplingFrequency = isset - (self::$samplingFrequencies[$this->_version] - [$index = Zend_Bit_Twiddling::getValue($header, 10, 11)]) ? - self::$samplingFrequencies[$this->_version][$index] : false; - $this->_padding = Zend_Bit_Twiddling::testBit($header, 9); - $this->_mode = Zend_Bit_Twiddling::getValue($header, 6, 7); - $this->_modeExtension = Zend_Bit_Twiddling::getValue($header, 4, 5); - $this->_copyright = Zend_Bit_Twiddling::testBit($header, 3); - $this->_original = Zend_Bit_Twiddling::testBit($header, 2); - $this->_emphasis = Zend_Bit_Twiddling::getValue($header, 0, 1); - - $this->_length = (int) - ((self::$coefficients[$this->_frequencyType][$this->_layer] * - ($this->_bitrate * 1000) / $this->_samplingFrequency) + - ($this->_padding ? 1 : 0)) * self::$slotsizes[$this->_layer]; - $this->_samples = self::$samples[$this->_frequencyType][$this->_layer]; - - if ($this->getOption('readmode', 'lazy') == 'full') { - $this->_readCrc(); - $this->_readData(); - } - $this->_reader->skip($this->_length - 4); - } - - /** - * Returns the offset where the frame actually begins (stream error may - * cause resynchronization). - * - * @return integer - */ - public function getOffset() - { - return $this->_offset; - } - - /** - * Returns the version identifier of the algorithm. - * - * @see VERSION_ONE, VERSION_TWO, VERSION_TWO_FIVE - * @return integer - */ - public function getVersion() - { - return $this->_version; - } - - /** - * Returns the sampling frequency type. This can be one of the following - * values. - * - * o {@link SAMPLING_FREQUENCY_HIGH} -- Higher Sampling Frequency - * (Version 1) - * o {@link SAMPLING_FREQUENCY_LOW} -- Lower Sampling Frequency - * (Version 2 and 2.5) - * - * @see SAMPLING_FREQUENCY_LOW, SAMPLING_FREQUENCY_HIGH - * @return integer - */ - public function getFrequencyType() - { - return $this->_frequencyType; - } - - /** - * Returns the type of layer used. - * - * @see LAYER_ONE, LAYER_TWO, LAYER_THREE - * @return integer - */ - public function getLayer() - { - return $this->_layer; - } - - /** - * An alias to getRedundancy(). - * - * @see getRedundancy - * @return boolean - */ - public function hasRedundancy() - { - return $this->getRedundancy(); - } - - /** - * Returns boolean corresponding to whether redundancy has been added in the - * audio bitstream to facilitate error detection and concealment. Equals - * false if no redundancy has been added, true if - * redundancy has been added. - * - * @return boolean - */ - public function getRedundancy() - { - return $this->_redundancy; - } - - /** - * Returns the bitrate in kbps. The returned value indicates the total bitrate - * irrespective of the mode (stereo, joint_stereo, dual_channel, - * single_channel). - * - * @return integer - */ - public function getBitrate() - { - return $this->_bitrate; - } - - /** - * Returns the sampling frequency in Hz. - * - * @return integer - */ - public function getSamplingFrequency() - { - return $this->_samplingFrequency; - } - - /** - * An alias to getPadding(). - * - * @see getPadding - * @return boolean - */ - public function hasPadding() - { - return $this->getPadding(); - } - - /** - * Returns boolean corresponding the frame contains an additional slot to - * adjust the mean bitrate to the sampling frequency. Equals to - * true if padding has been added, false otherwise. - * - * Padding is only necessary with a sampling frequency of 44.1kHz. - * - * @return boolean - */ - public function getPadding() - { - return $this->_padding; - } - - /** - * Returns the mode. In Layer I and II the CHANNEL_JOINT_STEREO mode is - * intensity_stereo, in Layer III it is intensity_stereo and/or ms_stereo. - * - * @see CHANNEL_STEREO, CHANNEL_JOINT_STEREO, CHANNEL_DUAL_CHANNEL, - * CHANNEL_SINGLE_CHANNEL - * @return integer - */ - public function getMode() - { - return $this->_mode; - } - - /** - * Returns the mode extension used in CHANNEL_JOINT_STEREO mode. - * - * In Layer I and II the return type indicates which subbands are in - * intensity_stereo. All other subbands are coded in stereo. - * - * o {@link MODE_SUBBAND_4_TO_31} -- subbands 4-31 in - * intensity_stereo, bound==4 - * o {@link MODE_SUBBAND_8_TO_31} -- subbands 8-31 in - * intensity_stereo, bound==8 - * o {@link MODE_SUBBAND_12_TO_31} -- subbands 12-31 in - * intensity_stereo, bound==12 - * o {@link MODE_SUBBAND_16_TO_31} -- subbands 16-31 in - * intensity_stereo, bound==16 - * - * In Layer III they indicate which type of joint stereo coding method is - * applied. The frequency ranges over which the intensity_stereo and - * ms_stereo modes are applied are implicit in the algorithm. Please see - * {@link MODE_ISOFF_MSSOFF}, {@link MODE_ISON_MSSOFF}, - * {@link MODE_ISOFF_MSSON}, and {@link MODE_ISON_MSSON}. - * - * @return integer - */ - public function getModeExtension() - { - return $this->_modeExtension; - } - - /** - * An alias to getCopyright(). - * - * @see getCopyright - * @return boolean - */ - public function hasCopyright() - { - return $this->getCopyright(); - } - - /** - * Returns true if the coded bitstream is copyright protected, - * false otherwise. - * - * @return boolean - */ - public function getCopyright() - { - return $this->_copyright; - } - - /** - * An alias to getOriginal(). - * - * @see getOriginal - * @return boolean - */ - public function isOriginal() - { - return $this->getOriginal(); - } - - /** - * Returns whether the bitstream is original or home made. - * - * @return boolean - */ - public function getOriginal() - { - return $this->_original; - } - - /** - * Returns the type of de-emphasis that shall be used. The value is one of - * the following. - * - * o {@link EMPHASIS_NONE} -- No emphasis - * o {@link EMPHASIS_50_15} -- 50/15 microsec. emphasis - * o {@link EMPHASIS_CCIT_J17} -- CCITT J.17 - * - * @see EMPHASIS_NONE, EMPHASIS_50_15, EMPHASIS_CCIT_J17 - * @return integer - */ - public function getEmphasis() - { - return $this->_emphasis; - } - - /** - * Returns the length of the frame based on the current layer, bit rate, - * sampling frequency and padding, in bytes. - * - * @return integer - */ - public function getLength() - { - return $this->_length; - } - - /** - * Returns the number of samples contained in the frame. - * - * @return integer - */ - public function getSamples() - { - return $this->_samples; - } - - /** - * Returns the 16-bit CRC of the frame or false if not present. - * - * @return integer - */ - public function getCrc() - { - if ($this->getOption('readmode', 'lazy') == 'lazy' && - $this->hasRedundancy() && $this->_crc === false) { - $this->_readCrc(); - } - return $this->_crc; - } - - /** - * Reads the CRC data. - */ - private function _readCrc() - { - if ($this->hasRedundancy()) { - $offset = $this->_reader->getOffset(); - $this->_reader->setOffset($this->_offset + 4); - $this->_crc = $this->_reader->readUInt16BE(); - $this->_reader->setOffset($offset); - } - } - - /** - * Returns the audio data. - * - * @return string - */ - public function getData() - { - if ($this->getOption('readmode', 'lazy') == 'lazy' && - $this->_data === false) { - $this->_readData(); - } - return $this->_data; - } - - /** - * Reads the frame data. - */ - private function _readData() - { - $offset = $this->_reader->getOffset(); - $this->_reader->setOffset - ($this->_offset + 4 + ($this->hasRedundancy() ? 2 : 0)); - $this->_data = $this->_reader->read - ($this->getLength() - 4 - ($this->hasRedundancy() ? 2 : 0)); - $this->_reader->setOffset($offset); - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Frame.php 261 2012-03-05 20:43:15Z svollbehr $ + */ +final class Zend_Media_Mpeg_Abs_Frame extends Zend_Media_Mpeg_Abs_Object +{ + /** + * The bitrate lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * ) + * + * + * @var Array + */ + private static $bitrates = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => array ( + 1 => 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, + 416, 448 + ), + self::LAYER_TWO => array ( + 1 => 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, + 384 + ), + self::LAYER_THREE => array ( + 1 => 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, + 320 + ) + ), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => array ( + 1 => 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, + 256 + ), + self::LAYER_TWO => array ( + 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 + ), + self::LAYER_THREE => array ( + 1 => 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160 + ) + ) + ); + + /** + * Sample rate lookup table. The table has the following format. + * + * + * array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * + * + * @var Array + */ + private static $samplingFrequencies = array ( + self::VERSION_ONE => array (44100, 48000, 32000), + self::VERSION_TWO => array (22050, 24000, 16000), + self::VERSION_TWO_FIVE => array (11025, 12000, 8000) + ); + + /** + * Samples per frame lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => + * ) + * ) + * + * + * @var Array + */ + private static $samples = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => 384, + self::LAYER_TWO => 1152, + self::LAYER_THREE => 1152), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => 384, + self::LAYER_TWO => 1152, + self::LAYER_THREE => 576)); + + /** + * Coefficient lookup table. The table has the following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => array ( ) + * ) + * ) + * + * + * @var Array + */ + private static $coefficients = array ( + self::SAMPLING_FREQUENCY_HIGH => array ( + self::LAYER_ONE => 12, self::LAYER_TWO => 144, + self::LAYER_THREE => 144 + ), + self::SAMPLING_FREQUENCY_LOW => array ( + self::LAYER_ONE => 12, self::LAYER_TWO => 144, + self::LAYER_THREE => 72 + ) + ); + + /** + * Slot size per layer lookup table. The table has the following format. + * + * + * array ( + * LAYER_ONE | LAYER_TWO | LAYER_TREE => + * ) + * + * + * @var Array + */ + private static $slotsizes = array ( + self::LAYER_ONE => 4, self::LAYER_TWO => 1, self::LAYER_THREE => 1 + ); + + /** @var integer */ + private $_offset; + + /** @var integer */ + private $_version; + + /** @var integer */ + private $_frequencyType; + + /** @var integer */ + private $_layer; + + /** @var integer */ + private $_redundancy; + + /** @var integer */ + private $_bitrate; + + /** @var integer */ + private $_samplingFrequency; + + /** @var integer */ + private $_padding; + + /** @var integer */ + private $_mode; + + /** @var integer */ + private $_modeExtension; + + /** @var integer */ + private $_copyright; + + /** @var integer */ + private $_original; + + /** @var integer */ + private $_emphasis; + + /** @var integer */ + private $_length; + + /** @var integer */ + private $_samples; + + /** @var integer */ + private $_crc = false; + + /** @var string */ + private $_data = false; + + /** + * Constructs the class with given parameters and reads object related data + * from the frame. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_offset = $this->_reader->getOffset(); + + $header = null; + for ($i = 0; $i < 5775 /* max attempts: max frame size x2 */; $i++) { + $header = $this->_reader->readUInt32BE(); + if (Zend_Bit_Twiddling::testAllBits(Zend_Bit_Twiddling::getValue($header, 21, 32), 0xffe)) { + break; + } + $this->_reader->setOffset(++$this->_offset + 1); + if ($this->_offset == $this->_reader->getSize() || $i == (5775 - 1)) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception + ('File does not contain a valid MPEG Audio Bit Stream (Invalid frame sync and resynchronization failed)'); + } + } + + $this->_version = Zend_Bit_Twiddling::getValue($header, 19, 20); + $this->_frequencyType = Zend_Bit_Twiddling::testBit($header, 19); + $this->_layer = Zend_Bit_Twiddling::getValue($header, 17, 18); + $this->_redundancy = !Zend_Bit_Twiddling::testBit($header, 16); + $this->_bitrate = isset + (self::$bitrates[$this->_frequencyType][$this->_layer] + [$index = Zend_Bit_Twiddling::getValue($header, 12, 15)]) ? + self::$bitrates[$this->_frequencyType][$this->_layer][$index] : + false; + $this->_samplingFrequency = isset + (self::$samplingFrequencies[$this->_version] + [$index = Zend_Bit_Twiddling::getValue($header, 10, 11)]) ? + self::$samplingFrequencies[$this->_version][$index] : false; + $this->_padding = Zend_Bit_Twiddling::testBit($header, 9); + $this->_mode = Zend_Bit_Twiddling::getValue($header, 6, 7); + $this->_modeExtension = Zend_Bit_Twiddling::getValue($header, 4, 5); + $this->_copyright = Zend_Bit_Twiddling::testBit($header, 3); + $this->_original = Zend_Bit_Twiddling::testBit($header, 2); + $this->_emphasis = Zend_Bit_Twiddling::getValue($header, 0, 1); + + $this->_length = (int) + ((self::$coefficients[$this->_frequencyType][$this->_layer] * + ($this->_bitrate * 1000) / $this->_samplingFrequency) + + ($this->_padding ? 1 : 0)) * self::$slotsizes[$this->_layer]; + $this->_samples = self::$samples[$this->_frequencyType][$this->_layer]; + + if ($this->getOption('readmode', 'lazy') == 'full') { + $this->_readCrc(); + $this->_readData(); + } + $this->_reader->skip($this->_length - 4); + } + + /** + * Returns the offset where the frame actually begins (stream error may + * cause resynchronization). + * + * @return integer + */ + public function getOffset() + { + return $this->_offset; + } + + /** + * Returns the version identifier of the algorithm. + * + * @see VERSION_ONE, VERSION_TWO, VERSION_TWO_FIVE + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the sampling frequency type. This can be one of the following + * values. + * + * o {@link SAMPLING_FREQUENCY_HIGH} -- Higher Sampling Frequency + * (Version 1) + * o {@link SAMPLING_FREQUENCY_LOW} -- Lower Sampling Frequency + * (Version 2 and 2.5) + * + * @see SAMPLING_FREQUENCY_LOW, SAMPLING_FREQUENCY_HIGH + * @return integer + */ + public function getFrequencyType() + { + return $this->_frequencyType; + } + + /** + * Returns the type of layer used. + * + * @see LAYER_ONE, LAYER_TWO, LAYER_THREE + * @return integer + */ + public function getLayer() + { + return $this->_layer; + } + + /** + * An alias to getRedundancy(). + * + * @see getRedundancy + * @return boolean + */ + public function hasRedundancy() + { + return $this->getRedundancy(); + } + + /** + * Returns boolean corresponding to whether redundancy has been added in the + * audio bitstream to facilitate error detection and concealment. Equals + * false if no redundancy has been added, true if + * redundancy has been added. + * + * @return boolean + */ + public function getRedundancy() + { + return $this->_redundancy; + } + + /** + * Returns the bitrate in kbps. The returned value indicates the total bitrate + * irrespective of the mode (stereo, joint_stereo, dual_channel, + * single_channel). + * + * @return integer + */ + public function getBitrate() + { + return $this->_bitrate; + } + + /** + * Returns the sampling frequency in Hz. + * + * @return integer + */ + public function getSamplingFrequency() + { + return $this->_samplingFrequency; + } + + /** + * An alias to getPadding(). + * + * @see getPadding + * @return boolean + */ + public function hasPadding() + { + return $this->getPadding(); + } + + /** + * Returns boolean corresponding the frame contains an additional slot to + * adjust the mean bitrate to the sampling frequency. Equals to + * true if padding has been added, false otherwise. + * + * Padding is only necessary with a sampling frequency of 44.1kHz. + * + * @return boolean + */ + public function getPadding() + { + return $this->_padding; + } + + /** + * Returns the mode. In Layer I and II the CHANNEL_JOINT_STEREO mode is + * intensity_stereo, in Layer III it is intensity_stereo and/or ms_stereo. + * + * @see CHANNEL_STEREO, CHANNEL_JOINT_STEREO, CHANNEL_DUAL_CHANNEL, + * CHANNEL_SINGLE_CHANNEL + * @return integer + */ + public function getMode() + { + return $this->_mode; + } + + /** + * Returns the mode extension used in CHANNEL_JOINT_STEREO mode. + * + * In Layer I and II the return type indicates which subbands are in + * intensity_stereo. All other subbands are coded in stereo. + * + * o {@link MODE_SUBBAND_4_TO_31} -- subbands 4-31 in + * intensity_stereo, bound==4 + * o {@link MODE_SUBBAND_8_TO_31} -- subbands 8-31 in + * intensity_stereo, bound==8 + * o {@link MODE_SUBBAND_12_TO_31} -- subbands 12-31 in + * intensity_stereo, bound==12 + * o {@link MODE_SUBBAND_16_TO_31} -- subbands 16-31 in + * intensity_stereo, bound==16 + * + * In Layer III they indicate which type of joint stereo coding method is + * applied. The frequency ranges over which the intensity_stereo and + * ms_stereo modes are applied are implicit in the algorithm. Please see + * {@link MODE_ISOFF_MSSOFF}, {@link MODE_ISON_MSSOFF}, + * {@link MODE_ISOFF_MSSON}, and {@link MODE_ISON_MSSON}. + * + * @return integer + */ + public function getModeExtension() + { + return $this->_modeExtension; + } + + /** + * An alias to getCopyright(). + * + * @see getCopyright + * @return boolean + */ + public function hasCopyright() + { + return $this->getCopyright(); + } + + /** + * Returns true if the coded bitstream is copyright protected, + * false otherwise. + * + * @return boolean + */ + public function getCopyright() + { + return $this->_copyright; + } + + /** + * An alias to getOriginal(). + * + * @see getOriginal + * @return boolean + */ + public function isOriginal() + { + return $this->getOriginal(); + } + + /** + * Returns whether the bitstream is original or home made. + * + * @return boolean + */ + public function getOriginal() + { + return $this->_original; + } + + /** + * Returns the type of de-emphasis that shall be used. The value is one of + * the following. + * + * o {@link EMPHASIS_NONE} -- No emphasis + * o {@link EMPHASIS_50_15} -- 50/15 microsec. emphasis + * o {@link EMPHASIS_CCIT_J17} -- CCITT J.17 + * + * @see EMPHASIS_NONE, EMPHASIS_50_15, EMPHASIS_CCIT_J17 + * @return integer + */ + public function getEmphasis() + { + return $this->_emphasis; + } + + /** + * Returns the length of the frame based on the current layer, bit rate, + * sampling frequency and padding, in bytes. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } + + /** + * Returns the number of samples contained in the frame. + * + * @return integer + */ + public function getSamples() + { + return $this->_samples; + } + + /** + * Returns the 16-bit CRC of the frame or false if not present. + * + * @return integer + */ + public function getCrc() + { + if ($this->getOption('readmode', 'lazy') == 'lazy' && + $this->hasRedundancy() && $this->_crc === false) { + $this->_readCrc(); + } + return $this->_crc; + } + + /** + * Reads the CRC data. + */ + private function _readCrc() + { + if ($this->hasRedundancy()) { + $offset = $this->_reader->getOffset(); + $this->_reader->setOffset($this->_offset + 4); + $this->_crc = $this->_reader->readUInt16BE(); + $this->_reader->setOffset($offset); + } + } + + /** + * Returns the audio data. + * + * @return string + */ + public function getData() + { + if ($this->getOption('readmode', 'lazy') == 'lazy' && + $this->_data === false) { + $this->_readData(); + } + return $this->_data; + } + + /** + * Reads the frame data. + */ + private function _readData() + { + $offset = $this->_reader->getOffset(); + $this->_reader->setOffset + ($this->_offset + 4 + ($this->hasRedundancy() ? 2 : 0)); + $this->_data = $this->_reader->read + ($this->getLength() - 4 - ($this->hasRedundancy() ? 2 : 0)); + $this->_reader->setOffset($offset); + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs/LameHeader.php b/app/libs/vendor/Zend/Media/Mpeg/Abs/LameHeader.php index aea45455..803268df 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs/LameHeader.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs/LameHeader.php @@ -1,527 +1,527 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: LameHeader.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Mpeg_Abs_LameHeader extends Zend_Media_Mpeg_Abs_Object -{ - /** @var integer */ - const VBR_METHOD_CONSTANT = 1; - - /** @var integer */ - const VBR_METHOD_ABR = 2; - - /** @var integer */ - const VBR_METHOD_RH = 3; - - /** @var integer */ - const VBR_METHOD_MTRH = 4; - - /** @var integer */ - const VBR_METHOD_MT = 5; - - /** @var integer */ - const ENCODING_FLAG_NSPSYTUNE = 1; - - /** @var integer */ - const ENCODING_FLAG_NSSAFEJOINT = 2; - - /** @var integer */ - const ENCODING_FLAG_NOGAP_CONTINUED = 4; - - /** @var integer */ - const ENCODING_FLAG_NOGAP_CONTINUATION = 8; - - /** @var integer */ - const MODE_MONO = 0; - - /** @var integer */ - const MODE_STEREO = 1; - - /** @var integer */ - const MODE_DUAL = 2; - - /** @var integer */ - const MODE_JOINT = 3; - - /** @var integer */ - const MODE_FORCE = 4; - - /** @var integer */ - const MODE_AUTO = 5; - - /** @var integer */ - const MODE_INTENSITY = 6; - - /** @var integer */ - const MODE_UNDEFINED = 7; - - /** @var integer */ - const SOURCE_FREQUENCY_32000_OR_LOWER = 0; - - /** @var integer */ - const SOURCE_FREQUENCY_44100 = 1; - - /** @var integer */ - const SOURCE_FREQUENCY_48000 = 2; - - /** @var integer */ - const SOURCE_FREQUENCY_HIGHER = 3; - - /** @var integer */ - const SURROUND_NONE = 0; - - /** @var integer */ - const SURROUND_DPL = 1; - - /** @var integer */ - const SURROUND_DPL2 = 2; - - /** @var integer */ - const SURROUND_AMBISONIC = 3; - - /** @var string */ - private $_version; - - /** @var integer */ - private $_revision; - - /** @var integer */ - private $_vbrMethod; - - /** @var integer */ - private $_lowpass; - - /** @var integer */ - private $_peakSignalAmplitude; - - /** @var integer */ - private $_radioReplayGain; - - /** @var integer */ - private $_audiophileReplayGain; - - /** @var integer */ - private $_encodingFlags; - - /** @var integer */ - private $_athType; - - /** @var integer */ - private $_bitrate; - - /** @var integer */ - private $_encoderDelaySamples; - - /** @var integer */ - private $_paddedSamples; - - /** @var integer */ - private $_sourceSampleFrequency; - - /** @var boolean */ - private $_unwiseSettingsUsed; - - /** @var integer */ - private $_mode; - - /** @var integer */ - private $_noiseShaping; - - /** @var integer */ - private $_mp3Gain; - - /** @var integer */ - private $_surroundInfo; - - /** @var integer */ - private $_presetUsed; - - /** @var integer */ - private $_musicLength; - - /** @var integer */ - private $_musicCrc; - - /** @var integer */ - private $_crc; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $this->_version = $this->_reader->readString8(5); - - $tmp = $this->_reader->readUInt8(); - $this->_revision = Zend_Bit_Twiddling::getValue($tmp, 4, 8); - $this->_vbrMethod = Zend_Bit_Twiddling::getValue($tmp, 0, 3); - - $this->_lowpass = $this->_reader->readUInt8() * 100; - - $this->_peakSignalAmplitude = $this->_reader->readUInt32BE(); - - $tmp = $this->_reader->readUInt16BE(); - $this->_radioReplayGain = array( - 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), - 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), - 'absoluteGainAdjustment' => - Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 - ); - - $tmp = $this->_reader->readUInt16BE(); - $this->_audiophileReplayGain = array( - 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), - 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), - 'absoluteGainAdjustment' => - Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 - ); - - $tmp = $this->_reader->readUInt8(); - $this->_encodingFlags = Zend_Bit_Twiddling::getValue($tmp, 4, 8); - $this->_athType = Zend_Bit_Twiddling::getValue($tmp, 0, 3); - - $this->_bitrate = $this->_reader->readUInt8(); - - $tmp = $this->_reader->readUInt32BE(); - // Encoder delay fields - $this->_encoderDelaySamples = - Zend_Bit_Twiddling::getValue($tmp, 20, 31); - $this->_paddedSamples = Zend_Bit_Twiddling::getValue($tmp, 8, 19); - // Misc field - $this->_sourceSampleFrequency = - Zend_Bit_Twiddling::getValue($tmp, 6, 7); - $this->_unwiseSettingsUsed = Zend_Bit_Twiddling::testBit($tmp, 5); - $this->_mode = Zend_Bit_Twiddling::getValue($tmp, 2, 4); - $this->_noiseShaping = Zend_Bit_Twiddling::getValue($tmp, 0, 1); - - $this->_mp3Gain = pow(2, $this->_reader->readInt8() / 4); - - $tmp = $this->_reader->readUInt16BE(); - $this->_surroundInfo = Zend_Bit_Twiddling::getValue($tmp, 11, 14); - $this->_presetUsed = Zend_Bit_Twiddling::getValue($tmp, 0, 10); - - $this->_musicLength = $this->_reader->readUInt32BE(); - - $this->_musicCrc = $this->_reader->readUInt16BE(); - $this->_crc = $this->_reader->readUInt16BE(); - } - - /** - * Returns the version string of the header. - * - * @return string - */ - public function getVersion() - { - return $this->_version; - } - - /** - * Returns the info tag revision. - * - * @return integer - */ - public function getRevision() - { - return $this->_revision; - } - - /** - * Returns the VBR method used for encoding. See the corresponding constants - * for possible return values. - * - * @return integer - */ - public function getVbrMethod() - { - return $this->_vbrMethod; - } - - /** - * Returns the lowpass filter value. - * - * @return integer - */ - public function getLowpass() - { - return $this->_lowpass; - } - - /** - * Returns the peak signal amplitude field of replay gain. The value of 1.0 - * (ie 100%) represents maximal signal amplitude storeable in decoding - * format. - * - * @return integer - */ - public function getPeakSignalAmplitude() - { - return $this->_peakSignalAmplitude; - } - - /** - * Returns the radio replay gain field of replay gain, required to make all - * tracks equal loudness, as an array that consists of the following keys. - * - * o name -- Specifies the name of the gain adjustment. Can be one of the - * following values: 0 = not set, 1 = radio, or 2 = audiophile. - * - * o originator -- Specifies the originator of the gain adjustment. Can be - * one of the following values: 0 = not set, 1 = set by artist, 2 = set - * by user, 3 = set by my model, 4 = set by simple RMS average. - * - * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. - * - * @return Array - */ - public function getRadioReplayGain() - { - return $this->_radioReplayGain; - } - - /** - * Returns the audiophile replay gain field of replay gain, required to give - * ideal listening loudness, as an array that consists of the following - * keys. - * - * o name -- Specifies the name of the gain adjustment. Can be one of the - * following values: 0 = not set, 1 = radio, or 2 = audiophile. - * - * o originator -- Specifies the originator of the gain adjustment. Can be - * one of the following values: 0 = not set, 1 = set by artist, 2 = set - * by user, 3 = set by my model, 4 = set by simple RMS average. - * - * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. - * - * @return Array - */ - public function getAudiophileReplayGain() - { - return $this->_audiophileReplayGain; - } - - /** - * Returns the encoding flags. See the corresponding flag constants for - * possible values. - * - * @return integer - */ - public function getEncodingFlags() - { - return $this->_encodingFlags; - } - - /** - * Returns the ATH type. - * - * @return integer - */ - public function getAthType() - { - return $this->_athType; - } - - /** - * Returns the bitrate for CBR encoded files and the minimal birate for - * VBR encoded file. The maximum value of this field is 255 even with higher - * actual bitrates. - * - * @return integer - */ - public function getBitrate() - { - return $this->_bitrate; - } - - /** - * Returns the encoder delay or number of samples added at start. - * - * @return integer - */ - public function getEncoderDelaySamples() - { - return $this->_encoderDelaySamples; - } - - /** - * Returns the number of padded samples to complete the last frame. - * - * @return integer - */ - public function getPaddedSamples() - { - return $this->_paddedSamples; - } - - /** - * Returns the source sample frequency. See corresponding constants for - * possible values. - * - * @return integer - */ - public function getSourceSampleFrequency() - { - return $this->_sourceSampleFrequency; - } - - /** - * An alias to getUnwiseSettingsUsed(). - * - * @see getUnwiseSettingsUsed - * @return boolean - */ - public function areUnwiseSettingsUsed() - { - return $this->getUnwiseSettingsUsed(); - } - - /** - * Returns whether unwise settings were used to encode the file. - * - * @return boolean - */ - public function getUnwiseSettingsUsed() - { - return $this->_unwiseSettingsUsed; - } - - /** - * Returns the stereo mode. See corresponding constants for possible values. - * - * @return integer - */ - public function getMode() - { - return $this->_mode; - } - - /** - * Returns the noise shaping. - * - * @return integer - */ - public function getNoiseShaping() - { - return $this->_noiseShaping; - } - - /** - * Returns the MP3 gain change. Any MP3 can be amplified in a lossless - * manner. If done so, this field can be used to log such transformation - * happened so that any given time it can be undone. - * - * @return integer - */ - public function getMp3Gain() - { - return $this->_mp3Gain; - } - - /** - * Returns the surround info. See corresponding contants for possible - * values. - * - * @return integer - */ - public function getSurroundInfo() - { - return $this->_surroundInfo; - } - - /** - * Returns the preset used in encoding. - * - * @return integer - */ - public function getPresetUsed() - { - return $this->_presetUsed; - } - - /** - * Returns the exact length in bytes of the MP3 file originally made by LAME - * excluded ID3 tag info at the end. - * - * The first byte it counts is the first byte of this LAME header and the - * last byte it counts is the last byte of the last MP3 frame containing - * music. The value should be equal to file length at the time of LAME - * encoding, except when using ID3 tags. - * - * @return integer - */ - public function getMusicLength() - { - return $this->_musicLength; - } - - /** - * Returns the CRC-16 of the complete MP3 music data as made originally by - * LAME. - * - * @return integer - */ - public function getMusicCrc() - { - return $this->_musicCrc; - } - - /** - * Returns the CRC-16 of the first 190 bytes of the header frame. - * - * @return integer - */ - public function getCrc() - { - return $this->_crc; - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: LameHeader.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Mpeg_Abs_LameHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + const VBR_METHOD_CONSTANT = 1; + + /** @var integer */ + const VBR_METHOD_ABR = 2; + + /** @var integer */ + const VBR_METHOD_RH = 3; + + /** @var integer */ + const VBR_METHOD_MTRH = 4; + + /** @var integer */ + const VBR_METHOD_MT = 5; + + /** @var integer */ + const ENCODING_FLAG_NSPSYTUNE = 1; + + /** @var integer */ + const ENCODING_FLAG_NSSAFEJOINT = 2; + + /** @var integer */ + const ENCODING_FLAG_NOGAP_CONTINUED = 4; + + /** @var integer */ + const ENCODING_FLAG_NOGAP_CONTINUATION = 8; + + /** @var integer */ + const MODE_MONO = 0; + + /** @var integer */ + const MODE_STEREO = 1; + + /** @var integer */ + const MODE_DUAL = 2; + + /** @var integer */ + const MODE_JOINT = 3; + + /** @var integer */ + const MODE_FORCE = 4; + + /** @var integer */ + const MODE_AUTO = 5; + + /** @var integer */ + const MODE_INTENSITY = 6; + + /** @var integer */ + const MODE_UNDEFINED = 7; + + /** @var integer */ + const SOURCE_FREQUENCY_32000_OR_LOWER = 0; + + /** @var integer */ + const SOURCE_FREQUENCY_44100 = 1; + + /** @var integer */ + const SOURCE_FREQUENCY_48000 = 2; + + /** @var integer */ + const SOURCE_FREQUENCY_HIGHER = 3; + + /** @var integer */ + const SURROUND_NONE = 0; + + /** @var integer */ + const SURROUND_DPL = 1; + + /** @var integer */ + const SURROUND_DPL2 = 2; + + /** @var integer */ + const SURROUND_AMBISONIC = 3; + + /** @var string */ + private $_version; + + /** @var integer */ + private $_revision; + + /** @var integer */ + private $_vbrMethod; + + /** @var integer */ + private $_lowpass; + + /** @var integer */ + private $_peakSignalAmplitude; + + /** @var integer */ + private $_radioReplayGain; + + /** @var integer */ + private $_audiophileReplayGain; + + /** @var integer */ + private $_encodingFlags; + + /** @var integer */ + private $_athType; + + /** @var integer */ + private $_bitrate; + + /** @var integer */ + private $_encoderDelaySamples; + + /** @var integer */ + private $_paddedSamples; + + /** @var integer */ + private $_sourceSampleFrequency; + + /** @var boolean */ + private $_unwiseSettingsUsed; + + /** @var integer */ + private $_mode; + + /** @var integer */ + private $_noiseShaping; + + /** @var integer */ + private $_mp3Gain; + + /** @var integer */ + private $_surroundInfo; + + /** @var integer */ + private $_presetUsed; + + /** @var integer */ + private $_musicLength; + + /** @var integer */ + private $_musicCrc; + + /** @var integer */ + private $_crc; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $this->_version = $this->_reader->readString8(5); + + $tmp = $this->_reader->readUInt8(); + $this->_revision = Zend_Bit_Twiddling::getValue($tmp, 4, 8); + $this->_vbrMethod = Zend_Bit_Twiddling::getValue($tmp, 0, 3); + + $this->_lowpass = $this->_reader->readUInt8() * 100; + + $this->_peakSignalAmplitude = $this->_reader->readUInt32BE(); + + $tmp = $this->_reader->readUInt16BE(); + $this->_radioReplayGain = array( + 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), + 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), + 'absoluteGainAdjustment' => + Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 + ); + + $tmp = $this->_reader->readUInt16BE(); + $this->_audiophileReplayGain = array( + 'name' => Zend_Bit_Twiddling::getValue($tmp, 0, 2), + 'originator' => Zend_Bit_Twiddling::getValue($tmp, 3, 5), + 'absoluteGainAdjustment' => + Zend_Bit_Twiddling::getValue($tmp, 7, 15) / 10 + ); + + $tmp = $this->_reader->readUInt8(); + $this->_encodingFlags = Zend_Bit_Twiddling::getValue($tmp, 4, 8); + $this->_athType = Zend_Bit_Twiddling::getValue($tmp, 0, 3); + + $this->_bitrate = $this->_reader->readUInt8(); + + $tmp = $this->_reader->readUInt32BE(); + // Encoder delay fields + $this->_encoderDelaySamples = + Zend_Bit_Twiddling::getValue($tmp, 20, 31); + $this->_paddedSamples = Zend_Bit_Twiddling::getValue($tmp, 8, 19); + // Misc field + $this->_sourceSampleFrequency = + Zend_Bit_Twiddling::getValue($tmp, 6, 7); + $this->_unwiseSettingsUsed = Zend_Bit_Twiddling::testBit($tmp, 5); + $this->_mode = Zend_Bit_Twiddling::getValue($tmp, 2, 4); + $this->_noiseShaping = Zend_Bit_Twiddling::getValue($tmp, 0, 1); + + $this->_mp3Gain = pow(2, $this->_reader->readInt8() / 4); + + $tmp = $this->_reader->readUInt16BE(); + $this->_surroundInfo = Zend_Bit_Twiddling::getValue($tmp, 11, 14); + $this->_presetUsed = Zend_Bit_Twiddling::getValue($tmp, 0, 10); + + $this->_musicLength = $this->_reader->readUInt32BE(); + + $this->_musicCrc = $this->_reader->readUInt16BE(); + $this->_crc = $this->_reader->readUInt16BE(); + } + + /** + * Returns the version string of the header. + * + * @return string + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the info tag revision. + * + * @return integer + */ + public function getRevision() + { + return $this->_revision; + } + + /** + * Returns the VBR method used for encoding. See the corresponding constants + * for possible return values. + * + * @return integer + */ + public function getVbrMethod() + { + return $this->_vbrMethod; + } + + /** + * Returns the lowpass filter value. + * + * @return integer + */ + public function getLowpass() + { + return $this->_lowpass; + } + + /** + * Returns the peak signal amplitude field of replay gain. The value of 1.0 + * (ie 100%) represents maximal signal amplitude storeable in decoding + * format. + * + * @return integer + */ + public function getPeakSignalAmplitude() + { + return $this->_peakSignalAmplitude; + } + + /** + * Returns the radio replay gain field of replay gain, required to make all + * tracks equal loudness, as an array that consists of the following keys. + * + * o name -- Specifies the name of the gain adjustment. Can be one of the + * following values: 0 = not set, 1 = radio, or 2 = audiophile. + * + * o originator -- Specifies the originator of the gain adjustment. Can be + * one of the following values: 0 = not set, 1 = set by artist, 2 = set + * by user, 3 = set by my model, 4 = set by simple RMS average. + * + * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. + * + * @return Array + */ + public function getRadioReplayGain() + { + return $this->_radioReplayGain; + } + + /** + * Returns the audiophile replay gain field of replay gain, required to give + * ideal listening loudness, as an array that consists of the following + * keys. + * + * o name -- Specifies the name of the gain adjustment. Can be one of the + * following values: 0 = not set, 1 = radio, or 2 = audiophile. + * + * o originator -- Specifies the originator of the gain adjustment. Can be + * one of the following values: 0 = not set, 1 = set by artist, 2 = set + * by user, 3 = set by my model, 4 = set by simple RMS average. + * + * o absoluteGainAdjustment -- Speficies the absolute gain adjustment. + * + * @return Array + */ + public function getAudiophileReplayGain() + { + return $this->_audiophileReplayGain; + } + + /** + * Returns the encoding flags. See the corresponding flag constants for + * possible values. + * + * @return integer + */ + public function getEncodingFlags() + { + return $this->_encodingFlags; + } + + /** + * Returns the ATH type. + * + * @return integer + */ + public function getAthType() + { + return $this->_athType; + } + + /** + * Returns the bitrate for CBR encoded files and the minimal birate for + * VBR encoded file. The maximum value of this field is 255 even with higher + * actual bitrates. + * + * @return integer + */ + public function getBitrate() + { + return $this->_bitrate; + } + + /** + * Returns the encoder delay or number of samples added at start. + * + * @return integer + */ + public function getEncoderDelaySamples() + { + return $this->_encoderDelaySamples; + } + + /** + * Returns the number of padded samples to complete the last frame. + * + * @return integer + */ + public function getPaddedSamples() + { + return $this->_paddedSamples; + } + + /** + * Returns the source sample frequency. See corresponding constants for + * possible values. + * + * @return integer + */ + public function getSourceSampleFrequency() + { + return $this->_sourceSampleFrequency; + } + + /** + * An alias to getUnwiseSettingsUsed(). + * + * @see getUnwiseSettingsUsed + * @return boolean + */ + public function areUnwiseSettingsUsed() + { + return $this->getUnwiseSettingsUsed(); + } + + /** + * Returns whether unwise settings were used to encode the file. + * + * @return boolean + */ + public function getUnwiseSettingsUsed() + { + return $this->_unwiseSettingsUsed; + } + + /** + * Returns the stereo mode. See corresponding constants for possible values. + * + * @return integer + */ + public function getMode() + { + return $this->_mode; + } + + /** + * Returns the noise shaping. + * + * @return integer + */ + public function getNoiseShaping() + { + return $this->_noiseShaping; + } + + /** + * Returns the MP3 gain change. Any MP3 can be amplified in a lossless + * manner. If done so, this field can be used to log such transformation + * happened so that any given time it can be undone. + * + * @return integer + */ + public function getMp3Gain() + { + return $this->_mp3Gain; + } + + /** + * Returns the surround info. See corresponding contants for possible + * values. + * + * @return integer + */ + public function getSurroundInfo() + { + return $this->_surroundInfo; + } + + /** + * Returns the preset used in encoding. + * + * @return integer + */ + public function getPresetUsed() + { + return $this->_presetUsed; + } + + /** + * Returns the exact length in bytes of the MP3 file originally made by LAME + * excluded ID3 tag info at the end. + * + * The first byte it counts is the first byte of this LAME header and the + * last byte it counts is the last byte of the last MP3 frame containing + * music. The value should be equal to file length at the time of LAME + * encoding, except when using ID3 tags. + * + * @return integer + */ + public function getMusicLength() + { + return $this->_musicLength; + } + + /** + * Returns the CRC-16 of the complete MP3 music data as made originally by + * LAME. + * + * @return integer + */ + public function getMusicCrc() + { + return $this->_musicCrc; + } + + /** + * Returns the CRC-16 of the first 190 bytes of the header frame. + * + * @return integer + */ + public function getCrc() + { + return $this->_crc; + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs/Object.php b/app/libs/vendor/Zend/Media/Mpeg/Abs/Object.php index 0cd5c937..d98a544b 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs/Object.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs/Object.php @@ -1,150 +1,150 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Mpeg_Abs_Object extends Zend_Media_Mpeg_Object -{ - /** @var integer */ - const VERSION_ONE = 3; - - /** @var integer */ - const VERSION_TWO = 2; - - /** @var integer */ - const VERSION_TWO_FIVE = 0; - - /** @var integer */ - const SAMPLING_FREQUENCY_LOW = 0; - - /** @var integer */ - const SAMPLING_FREQUENCY_HIGH = 1; - - /** @var integer */ - const LAYER_ONE = 3; - - /** @var integer */ - const LAYER_TWO = 2; - - /** @var integer */ - const LAYER_THREE = 1; - - /** @var integer */ - const CHANNEL_STEREO = 0; - - /** @var integer */ - const CHANNEL_JOINT_STEREO = 1; - - /** @var integer */ - const CHANNEL_DUAL_CHANNEL = 2; - - /** @var integer */ - const CHANNEL_SINGLE_CHANNEL = 3; - - /** @var integer */ - const MODE_SUBBAND_4_TO_31 = 0; - - /** @var integer */ - const MODE_SUBBAND_8_TO_31 = 1; - - /** @var integer */ - const MODE_SUBBAND_12_TO_31 = 2; - - /** @var integer */ - const MODE_SUBBAND_16_TO_31 = 3; - - /** @var integer */ - const MODE_ISOFF_MSSOFF = 0; - - /** @var integer */ - const MODE_ISON_MSSOFF = 1; - - /** @var integer */ - const MODE_ISOFF_MSSON = 2; - - /** @var integer */ - const MODE_ISON_MSSON = 3; - - /** @var integer */ - const EMPHASIS_NONE = 0; - - /** @var integer */ - const EMPHASIS_50_15 = 1; - - /** @var integer */ - const EMPHASIS_CCIT_J17 = 3; - - /** - * Layer III side information size lookup table. The table has the - * following format. - * - * - * array ( - * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( - * CHANNEL_STEREO | CHANNEL_JOINT_STEREO | CHANNEL_DUAL_CHANNEL | - * CHANNEL_SINGLE_CHANNEL => - * ) - * ) - * - * - * @var Array - */ - protected static $sidesizes = array( - self::SAMPLING_FREQUENCY_HIGH => array( - self::CHANNEL_STEREO => 32, - self::CHANNEL_JOINT_STEREO => 32, - self::CHANNEL_DUAL_CHANNEL => 32, - self::CHANNEL_SINGLE_CHANNEL => 17 - ), - self::SAMPLING_FREQUENCY_LOW => array( - self::CHANNEL_STEREO => 17, - self::CHANNEL_JOINT_STEREO => 17, - self::CHANNEL_DUAL_CHANNEL => 17, - self::CHANNEL_SINGLE_CHANNEL => 9 - ) - ); - - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Mpeg_Abs_Object extends Zend_Media_Mpeg_Object +{ + /** @var integer */ + const VERSION_ONE = 3; + + /** @var integer */ + const VERSION_TWO = 2; + + /** @var integer */ + const VERSION_TWO_FIVE = 0; + + /** @var integer */ + const SAMPLING_FREQUENCY_LOW = 0; + + /** @var integer */ + const SAMPLING_FREQUENCY_HIGH = 1; + + /** @var integer */ + const LAYER_ONE = 3; + + /** @var integer */ + const LAYER_TWO = 2; + + /** @var integer */ + const LAYER_THREE = 1; + + /** @var integer */ + const CHANNEL_STEREO = 0; + + /** @var integer */ + const CHANNEL_JOINT_STEREO = 1; + + /** @var integer */ + const CHANNEL_DUAL_CHANNEL = 2; + + /** @var integer */ + const CHANNEL_SINGLE_CHANNEL = 3; + + /** @var integer */ + const MODE_SUBBAND_4_TO_31 = 0; + + /** @var integer */ + const MODE_SUBBAND_8_TO_31 = 1; + + /** @var integer */ + const MODE_SUBBAND_12_TO_31 = 2; + + /** @var integer */ + const MODE_SUBBAND_16_TO_31 = 3; + + /** @var integer */ + const MODE_ISOFF_MSSOFF = 0; + + /** @var integer */ + const MODE_ISON_MSSOFF = 1; + + /** @var integer */ + const MODE_ISOFF_MSSON = 2; + + /** @var integer */ + const MODE_ISON_MSSON = 3; + + /** @var integer */ + const EMPHASIS_NONE = 0; + + /** @var integer */ + const EMPHASIS_50_15 = 1; + + /** @var integer */ + const EMPHASIS_CCIT_J17 = 3; + + /** + * Layer III side information size lookup table. The table has the + * following format. + * + * + * array ( + * SAMPLING_FREQUENCY_HIGH | SAMPLING_FREQUENCY_LOW => array ( + * CHANNEL_STEREO | CHANNEL_JOINT_STEREO | CHANNEL_DUAL_CHANNEL | + * CHANNEL_SINGLE_CHANNEL => + * ) + * ) + * + * + * @var Array + */ + protected static $sidesizes = array( + self::SAMPLING_FREQUENCY_HIGH => array( + self::CHANNEL_STEREO => 32, + self::CHANNEL_JOINT_STEREO => 32, + self::CHANNEL_DUAL_CHANNEL => 32, + self::CHANNEL_SINGLE_CHANNEL => 17 + ), + self::SAMPLING_FREQUENCY_LOW => array( + self::CHANNEL_STEREO => 17, + self::CHANNEL_JOINT_STEREO => 17, + self::CHANNEL_DUAL_CHANNEL => 17, + self::CHANNEL_SINGLE_CHANNEL => 9 + ) + ); + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs/VbriHeader.php b/app/libs/vendor/Zend/Media/Mpeg/Abs/VbriHeader.php index 3a30a48f..1c6a1252 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs/VbriHeader.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs/VbriHeader.php @@ -1,177 +1,177 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: VbriHeader.php 234 2011-05-25 14:49:36Z svollbehr $ - */ -class Zend_Media_Mpeg_Abs_VbriHeader extends Zend_Media_Mpeg_Abs_Object -{ - /** @var integer */ - private $_version; - - /** @var integer */ - private $_delay; - - /** @var integer */ - private $_qualityIndicator; - - /** @var integer */ - private $_bytes; - - /** @var integer */ - private $_frames; - - /** @var Array */ - private $_toc = array(); - - /** @var integer */ - private $_tocFramesPerEntry; - - /** @var integer */ - private $_length; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $offset = $this->_reader->getOffset(); - $this->_version = $this->_reader->readUInt16BE(); - $this->_delay = $this->_reader->readUInt16BE(); - $this->_qualityIndicator = $this->_reader->readUInt16BE(); - $this->_bytes = $this->_reader->readUInt32BE(); - $this->_frames = $this->_reader->readUInt32BE(); - $tocEntries = $this->_reader->readUInt16BE(); - $tocEntryScale = $this->_reader->readUInt16BE(); - $tocEntrySize = $this->_reader->readUInt16BE(); - $this->_tocFramesPerEntry = $this->_reader->readUInt16BE(); - $this->_toc = array_merge(unpack(($tocEntrySize == 1) ? 'C*' : - ($tocEntrySize == 2) ? 'n*' : 'N*', - $this->_reader->read($tocCount * $tocEntrySize))); - foreach ($this->_toc as $key => $value) { - $this->_toc[$key] = $tocEntryScale * $value; - } - $this->_length = $this->_reader->getOffset() - $offset; - } - - /** - * Returns the header version. - * - * @return integer - */ - public function getVersion() - { - return $this->_version; - } - - /** - * Returns the delay. - * - * @return integer - */ - public function getDelay() - { - return $this->_delay; - } - - /** - * Returns the quality indicator. Return value varies from 0 (best quality) - * to 100 (worst quality). - * - * @return integer - */ - public function getQualityIndicator() - { - return $this->_qualityIndicator; - } - - /** - * Returns the number of bytes in the file. - * - * @return integer - */ - public function getBytes() - { - return $this->_bytes; - } - - /** - * Returns the number of frames in the file. - * - * @return integer - */ - public function getFrames() - { - return $this->_frames; - } - - /** - * Returns the table of contents array. - * - * @return Array - */ - public function getToc() - { - return $this->_toc; - } - - /** - * Returns the number of frames per TOC entry. - * - * @return integer - */ - public function getTocFramesPerEntry() - { - return $this->_tocFramesPerEntry; - } - - /** - * Returns the length of the header in bytes. - * - * @return integer - */ - public function getLength() - { - return $this->_length; - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: VbriHeader.php 234 2011-05-25 14:49:36Z svollbehr $ + */ +class Zend_Media_Mpeg_Abs_VbriHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_version; + + /** @var integer */ + private $_delay; + + /** @var integer */ + private $_qualityIndicator; + + /** @var integer */ + private $_bytes; + + /** @var integer */ + private $_frames; + + /** @var Array */ + private $_toc = array(); + + /** @var integer */ + private $_tocFramesPerEntry; + + /** @var integer */ + private $_length; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $offset = $this->_reader->getOffset(); + $this->_version = $this->_reader->readUInt16BE(); + $this->_delay = $this->_reader->readUInt16BE(); + $this->_qualityIndicator = $this->_reader->readUInt16BE(); + $this->_bytes = $this->_reader->readUInt32BE(); + $this->_frames = $this->_reader->readUInt32BE(); + $tocEntries = $this->_reader->readUInt16BE(); + $tocEntryScale = $this->_reader->readUInt16BE(); + $tocEntrySize = $this->_reader->readUInt16BE(); + $this->_tocFramesPerEntry = $this->_reader->readUInt16BE(); + $this->_toc = array_merge(unpack(($tocEntrySize == 1) ? 'C*' : + ($tocEntrySize == 2) ? 'n*' : 'N*', + $this->_reader->read($tocCount * $tocEntrySize))); + foreach ($this->_toc as $key => $value) { + $this->_toc[$key] = $tocEntryScale * $value; + } + $this->_length = $this->_reader->getOffset() - $offset; + } + + /** + * Returns the header version. + * + * @return integer + */ + public function getVersion() + { + return $this->_version; + } + + /** + * Returns the delay. + * + * @return integer + */ + public function getDelay() + { + return $this->_delay; + } + + /** + * Returns the quality indicator. Return value varies from 0 (best quality) + * to 100 (worst quality). + * + * @return integer + */ + public function getQualityIndicator() + { + return $this->_qualityIndicator; + } + + /** + * Returns the number of bytes in the file. + * + * @return integer + */ + public function getBytes() + { + return $this->_bytes; + } + + /** + * Returns the number of frames in the file. + * + * @return integer + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Returns the table of contents array. + * + * @return Array + */ + public function getToc() + { + return $this->_toc; + } + + /** + * Returns the number of frames per TOC entry. + * + * @return integer + */ + public function getTocFramesPerEntry() + { + return $this->_tocFramesPerEntry; + } + + /** + * Returns the length of the header in bytes. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Abs/XingHeader.php b/app/libs/vendor/Zend/Media/Mpeg/Abs/XingHeader.php index 3e58aecd..47b0a77a 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Abs/XingHeader.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Abs/XingHeader.php @@ -1,137 +1,137 @@ - - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: XingHeader.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Mpeg_Abs_XingHeader extends Zend_Media_Mpeg_Abs_Object -{ - /** @var integer */ - private $_frames = false; - - /** @var integer */ - private $_bytes = false; - - /** @var Array */ - private $_toc = array(); - - /** @var integer */ - private $_qualityIndicator = false; - - /** - * Constructs the class with given parameters and reads object related data - * from the bitstream. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, &$options = array()) - { - parent::__construct($reader, $options); - - $flags = $reader->readUInt32BE(); - - if (Zend_Bit_Twiddling::testAnyBits($flags, 0x1)) { - $this->_frames = $this->_reader->readUInt32BE(); - } - if (Zend_Bit_Twiddling::testAnyBits($flags, 0x2)) { - $this->_bytes = $this->_reader->readUInt32BE(); - } - if (Zend_Bit_Twiddling::testAnyBits($flags, 0x4)) { - $this->_toc = array_merge(unpack('C*', $this->_reader->read(100))); - } - if (Zend_Bit_Twiddling::testAnyBits($flags, 0x8)) { - $this->_qualityIndicator = $this->_reader->readUInt32BE(); - } - } - - /** - * Returns the number of frames in the file. - * - * @return integer - */ - public function getFrames() - { - return $this->_frames; - } - - /** - * Returns the number of bytes in the file. - * - * @return integer - */ - public function getBytes() - { - return $this->_bytes; - } - - /** - * Returns the table of contents array. The returned array has a fixed - * amount of 100 seek points to the file. - * - * @return Array - */ - public function getToc() - { - return $this->_toc; - } - - /** - * Returns the quality indicator. The indicator is from 0 (best quality) to - * 100 (worst quality). - * - * @return integer - */ - public function getQualityIndicator() - { - return $this->_qualityIndicator; - } - - /** - * Returns the length of the header in bytes. - * - * @return integer - */ - public function getLength() - { - return 4 + - ($this->_frames !== false ? 4 : 0) + - ($this->_bytes !== false ? 4 : 0) + - (empty($this->_toc) ? 0 : 100) + - ($this->_qualityIndicator !== false ? 4 : 0); - } -} + + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: XingHeader.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Mpeg_Abs_XingHeader extends Zend_Media_Mpeg_Abs_Object +{ + /** @var integer */ + private $_frames = false; + + /** @var integer */ + private $_bytes = false; + + /** @var Array */ + private $_toc = array(); + + /** @var integer */ + private $_qualityIndicator = false; + + /** + * Constructs the class with given parameters and reads object related data + * from the bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, &$options = array()) + { + parent::__construct($reader, $options); + + $flags = $reader->readUInt32BE(); + + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x1)) { + $this->_frames = $this->_reader->readUInt32BE(); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x2)) { + $this->_bytes = $this->_reader->readUInt32BE(); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x4)) { + $this->_toc = array_merge(unpack('C*', $this->_reader->read(100))); + } + if (Zend_Bit_Twiddling::testAnyBits($flags, 0x8)) { + $this->_qualityIndicator = $this->_reader->readUInt32BE(); + } + } + + /** + * Returns the number of frames in the file. + * + * @return integer + */ + public function getFrames() + { + return $this->_frames; + } + + /** + * Returns the number of bytes in the file. + * + * @return integer + */ + public function getBytes() + { + return $this->_bytes; + } + + /** + * Returns the table of contents array. The returned array has a fixed + * amount of 100 seek points to the file. + * + * @return Array + */ + public function getToc() + { + return $this->_toc; + } + + /** + * Returns the quality indicator. The indicator is from 0 (best quality) to + * 100 (worst quality). + * + * @return integer + */ + public function getQualityIndicator() + { + return $this->_qualityIndicator; + } + + /** + * Returns the length of the header in bytes. + * + * @return integer + */ + public function getLength() + { + return 4 + + ($this->_frames !== false ? 4 : 0) + + ($this->_bytes !== false ? 4 : 0) + + (empty($this->_toc) ? 0 : 100) + + ($this->_qualityIndicator !== false ? 4 : 0); + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Exception.php b/app/libs/vendor/Zend/Media/Mpeg/Exception.php index 966fe895..1a0e9d8a 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Exception.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Exception.php @@ -1,40 +1,40 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -class Zend_Media_Mpeg_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +class Zend_Media_Mpeg_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Object.php b/app/libs/vendor/Zend/Media/Mpeg/Object.php index 74ded535..27f6bbaf 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Object.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Object.php @@ -1,267 +1,267 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ - */ -abstract class Zend_Media_Mpeg_Object -{ - /** - * The reader object. - * - * @var Reader - */ - protected $_reader; - - /** - * The options array. - * - * @var Array - */ - private $_options; - - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader, &$options = array()) - { - $this->_reader = $reader; - $this->_options = &$options; - } - - /** - * Returns the options array. - * - * @return Array - */ - public final function &getOptions() - { - return $this->_options; - } - - /** - * Returns the given option value, or the default value if the option is not - * defined. - * - * @param string $option The name of the option. - * @param mixed $defaultValue The default value to be returned. - */ - public final function getOption($option, $defaultValue = null) - { - if (isset($this->_options[$option])) { - return $this->_options[$option]; - } - return $defaultValue; - } - - /** - * Sets the options array. See main class for available options. - * - * @param Array $options The options array. - */ - public final function setOptions(&$options) - { - $this->_options = &$options; - } - - /** - * Sets the given option the given value. - * - * @param string $option The name of the option. - * @param mixed $value The value to set for the option. - */ - public final function setOption($option, $value) - { - $this->_options[$option] = $value; - } - - /** - * Clears the given option value. - * - * @param string $option The name of the option. - */ - public final function clearOption($option) - { - unset($this->_options[$option]); - } - - /** - * Finds and returns the next start code. Start codes are reserved bit - * patterns in the video file that do not otherwise occur in the video stream. - * - * All start codes are byte aligned and start with the following byte - * sequence: 0x00 0x00 0x01. - * - * @return integer - */ - protected final function nextStartCode() - { - $buffer = ' '; - for ($i = 0; $i < 4; $i++) { - $start = $this->_reader->getOffset(); - if (($buffer = substr($buffer, -4) . - $this->_reader->read(512)) === false) { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception('Invalid data'); - } - $limit = strlen($buffer); - $pos = 0; - while ($pos < $limit - 3) { - if (ord($buffer{$pos++}) == 0) { - list(, $int) = unpack('n*', substr($buffer, $pos, 2)); - if ($int == 1) { - if (($pos += 2) < $limit - 2) { - list(, $int) = - unpack('n*', substr($buffer, $pos, 2)); - if ($int == 0 && ord($buffer{$pos + 2}) == 1) { - continue; - } - } - $this->_reader->setOffset($start + $pos - 3); - return ord($buffer{$pos++}) & 0xff | 0x100; - } - } - } - $this->_reader->setOffset($start + $limit); - } - - /* No start code found within 2048 bytes, the maximum size of a pack */ - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception('Invalid data'); - } - - /** - * Finds and returns the previous start code. Start codes are reserved bit - * patterns in the video file that do not otherwise occur in the video - * stream. - * - * All start codes are byte aligned and start with the following byte - * sequence: 0x00 0x00 0x01. - * - * @return integer - */ - protected final function prevStartCode() - { - $buffer = ' '; - $start; - $position = $this->_reader->getOffset(); - while ($position > 0) { - $start = 0; - $position = $position - 512; - if ($position < 0) { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception('Invalid data'); - } - $this->_reader->setOffset($position); - $buffer = $this->_reader->read(512) . substr($buffer, 0, 4); - $pos = 512 - 8; - while ($pos > 3) { - list(, $int) = unpack('n*', substr($buffer, $pos + 1, 2)); - if (ord($buffer{$pos}) == 0 && $int == 1) { - list(, $int) = unpack('n*', substr($buffer, $pos + 3, 2)); - if ($pos + 2 < 512 && $int == 0 && - ord($buffer{$pos + 5}) == 1) { - $pos--; - continue; - } - $this->_reader->setOffset($position + $pos); - return ord($buffer{$pos + 3}) & 0xff | 0x100; - } - $pos--; - } - $this->_reader->setOffset($position = $position + 3); - } - return 0; - } - - /** - * Formats given time in seconds into the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The time to format, in seconds - * @return string - */ - protected final function formatTime($seconds) - { - $milliseconds = round(($seconds - floor($seconds)) * 1000); - $seconds = floor($seconds); - $minutes = floor($seconds / 60); - $hours = floor($minutes / 60); - return - ($minutes > 0 ? - ($hours > 0 ? $hours . ':' . - str_pad($minutes % 60, 2, '0', STR_PAD_LEFT) : $minutes % 60) . - ':' . - str_pad($seconds % 60, 2, '0', STR_PAD_LEFT) : $seconds % 60) . - '.' . - str_pad($milliseconds, 3, '0', STR_PAD_LEFT); - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } else { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst($name))) { - call_user_func - (array($this, 'set' . ucfirst($name)), $value); - } else { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Object.php 177 2010-03-09 13:13:34Z svollbehr $ + */ +abstract class Zend_Media_Mpeg_Object +{ + /** + * The reader object. + * + * @var Reader + */ + protected $_reader; + + /** + * The options array. + * + * @var Array + */ + private $_options; + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader, &$options = array()) + { + $this->_reader = $reader; + $this->_options = &$options; + } + + /** + * Returns the options array. + * + * @return Array + */ + public final function &getOptions() + { + return $this->_options; + } + + /** + * Returns the given option value, or the default value if the option is not + * defined. + * + * @param string $option The name of the option. + * @param mixed $defaultValue The default value to be returned. + */ + public final function getOption($option, $defaultValue = null) + { + if (isset($this->_options[$option])) { + return $this->_options[$option]; + } + return $defaultValue; + } + + /** + * Sets the options array. See main class for available options. + * + * @param Array $options The options array. + */ + public final function setOptions(&$options) + { + $this->_options = &$options; + } + + /** + * Sets the given option the given value. + * + * @param string $option The name of the option. + * @param mixed $value The value to set for the option. + */ + public final function setOption($option, $value) + { + $this->_options[$option] = $value; + } + + /** + * Clears the given option value. + * + * @param string $option The name of the option. + */ + public final function clearOption($option) + { + unset($this->_options[$option]); + } + + /** + * Finds and returns the next start code. Start codes are reserved bit + * patterns in the video file that do not otherwise occur in the video stream. + * + * All start codes are byte aligned and start with the following byte + * sequence: 0x00 0x00 0x01. + * + * @return integer + */ + protected final function nextStartCode() + { + $buffer = ' '; + for ($i = 0; $i < 4; $i++) { + $start = $this->_reader->getOffset(); + if (($buffer = substr($buffer, -4) . + $this->_reader->read(512)) === false) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + $limit = strlen($buffer); + $pos = 0; + while ($pos < $limit - 3) { + if (ord($buffer{$pos++}) == 0) { + list(, $int) = unpack('n*', substr($buffer, $pos, 2)); + if ($int == 1) { + if (($pos += 2) < $limit - 2) { + list(, $int) = + unpack('n*', substr($buffer, $pos, 2)); + if ($int == 0 && ord($buffer{$pos + 2}) == 1) { + continue; + } + } + $this->_reader->setOffset($start + $pos - 3); + return ord($buffer{$pos++}) & 0xff | 0x100; + } + } + } + $this->_reader->setOffset($start + $limit); + } + + /* No start code found within 2048 bytes, the maximum size of a pack */ + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + + /** + * Finds and returns the previous start code. Start codes are reserved bit + * patterns in the video file that do not otherwise occur in the video + * stream. + * + * All start codes are byte aligned and start with the following byte + * sequence: 0x00 0x00 0x01. + * + * @return integer + */ + protected final function prevStartCode() + { + $buffer = ' '; + $start; + $position = $this->_reader->getOffset(); + while ($position > 0) { + $start = 0; + $position = $position - 512; + if ($position < 0) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Invalid data'); + } + $this->_reader->setOffset($position); + $buffer = $this->_reader->read(512) . substr($buffer, 0, 4); + $pos = 512 - 8; + while ($pos > 3) { + list(, $int) = unpack('n*', substr($buffer, $pos + 1, 2)); + if (ord($buffer{$pos}) == 0 && $int == 1) { + list(, $int) = unpack('n*', substr($buffer, $pos + 3, 2)); + if ($pos + 2 < 512 && $int == 0 && + ord($buffer{$pos + 5}) == 1) { + $pos--; + continue; + } + $this->_reader->setOffset($position + $pos); + return ord($buffer{$pos + 3}) & 0xff | 0x100; + } + $pos--; + } + $this->_reader->setOffset($position = $position + 3); + } + return 0; + } + + /** + * Formats given time in seconds into the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The time to format, in seconds + * @return string + */ + protected final function formatTime($seconds) + { + $milliseconds = round(($seconds - floor($seconds)) * 1000); + $seconds = floor($seconds); + $minutes = floor($seconds / 60); + $hours = floor($minutes / 60); + return + ($minutes > 0 ? + ($hours > 0 ? $hours . ':' . + str_pad($minutes % 60, 2, '0', STR_PAD_LEFT) : $minutes % 60) . + ':' . + str_pad($seconds % 60, 2, '0', STR_PAD_LEFT) : $seconds % 60) . + '.' . + str_pad($milliseconds, 3, '0', STR_PAD_LEFT); + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } else { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst($name))) { + call_user_func + (array($this, 'set' . ucfirst($name)), $value); + } else { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Mpeg/Ps.php b/app/libs/vendor/Zend/Media/Mpeg/Ps.php index ed38d7a2..15816d14 100644 --- a/app/libs/vendor/Zend/Media/Mpeg/Ps.php +++ b/app/libs/vendor/Zend/Media/Mpeg/Ps.php @@ -1,153 +1,153 @@ - - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ps.php 208 2010-12-28 13:48:09Z svollbehr $ - * @todo Full implementation - */ -final class Zend_Media_Mpeg_Ps extends Zend_Media_Mpeg_Object -{ - /** @var integer */ - private $_length; - - /** - * Constructs the class with given file and options. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @param Array $options The options array. - */ - public function __construct($filename, $options = array()) - { - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - require_once 'Zend/Io/FileReader.php'; - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception($e->getMessage()); - } - } - $this->setOptions($options); - - $startCode = 0; - $startTime = 0; - $pictureCount = 0; - $pictureRate = 0; - $rates = array ( 0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 ); - $foundSeqHdr = false; - $foundGOP = false; - - do { - do { - $startCode = $this->nextStartCode(); - } while ($startCode != 0x1b3 && $startCode != 0x1b8); - - if ($startCode == 0x1b3 /* sequence_header_code */ && - $pictureRate == 0) { - $i1 = $this->_reader->readUInt32BE(); - $i2 = $this->_reader->readUInt32BE(); - if (!Zend_Bit_Twiddling::testAllBits($i2, 0x2000)) { - require_once 'Zend/Media/Mpeg/Exception.php'; - throw new Zend_Media_Mpeg_Exception - ('File does not contain a valid MPEG Program Stream (Invalid mark)'); - } - $pictureRate = $rates[Zend_Bit_Twiddling::getValue($i1, 4, 8)]; - $foundSeqHdr = true; - } - if ($startCode == 0x1b8 /* group_start_code */) { - $tmp = $this->_reader->readUInt32BE(); - $startTime = - (($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + - (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + - (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + - (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000); - $foundGOP = true; - } - } while (!$foundSeqHdr || !$foundGOP); - - $this->_reader->setOffset($this->_reader->getSize()); - - do { - if (($startCode = $this->prevStartCode()) == 0x100) { - $pictureCount++; - } - } while ($startCode != 0x1b8); - - $this->_reader->skip(4); - $tmp = $this->_reader->readUInt32BE(); - $this->_length = - (((($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + - (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + - (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + - (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000)) - - $startTime + - (int)(1 / $pictureRate * $pictureCount * 1000)) / 1000; - } - - /** - * Returns the exact playtime in seconds. - * - * @return integer - */ - public function getLength() - { - return $this->_length; - } - - /** - * Returns the exact playtime given in seconds as a string in the form of - * [hours:]minutes:seconds.milliseconds. - * - * @param integer $seconds The playtime in seconds. - * @return string - */ - public function getFormattedLength() - { - return $this->formatTime($this->getLength()); - } -} + + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ps.php 208 2010-12-28 13:48:09Z svollbehr $ + * @todo Full implementation + */ +final class Zend_Media_Mpeg_Ps extends Zend_Media_Mpeg_Object +{ + /** @var integer */ + private $_length; + + /** + * Constructs the class with given file and options. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @param Array $options The options array. + */ + public function __construct($filename, $options = array()) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + require_once 'Zend/Io/FileReader.php'; + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception($e->getMessage()); + } + } + $this->setOptions($options); + + $startCode = 0; + $startTime = 0; + $pictureCount = 0; + $pictureRate = 0; + $rates = array ( 0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60 ); + $foundSeqHdr = false; + $foundGOP = false; + + do { + do { + $startCode = $this->nextStartCode(); + } while ($startCode != 0x1b3 && $startCode != 0x1b8); + + if ($startCode == 0x1b3 /* sequence_header_code */ && + $pictureRate == 0) { + $i1 = $this->_reader->readUInt32BE(); + $i2 = $this->_reader->readUInt32BE(); + if (!Zend_Bit_Twiddling::testAllBits($i2, 0x2000)) { + require_once 'Zend/Media/Mpeg/Exception.php'; + throw new Zend_Media_Mpeg_Exception + ('File does not contain a valid MPEG Program Stream (Invalid mark)'); + } + $pictureRate = $rates[Zend_Bit_Twiddling::getValue($i1, 4, 8)]; + $foundSeqHdr = true; + } + if ($startCode == 0x1b8 /* group_start_code */) { + $tmp = $this->_reader->readUInt32BE(); + $startTime = + (($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + + (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + + (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + + (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000); + $foundGOP = true; + } + } while (!$foundSeqHdr || !$foundGOP); + + $this->_reader->setOffset($this->_reader->getSize()); + + do { + if (($startCode = $this->prevStartCode()) == 0x100) { + $pictureCount++; + } + } while ($startCode != 0x1b8); + + $this->_reader->skip(4); + $tmp = $this->_reader->readUInt32BE(); + $this->_length = + (((($tmp >> 26) & 0x1f) * 60 * 60 * 1000 /* hours */ + + (($tmp >> 20) & 0x3f) * 60 * 1000 /* minutes */ + + (($tmp >> 13) & 0x3f) * 1000 /* seconds */ + + (int)(1 / $pictureRate * (($tmp >> 7) & 0x3f) * 1000)) - + $startTime + + (int)(1 / $pictureRate * $pictureCount * 1000)) / 1000; + } + + /** + * Returns the exact playtime in seconds. + * + * @return integer + */ + public function getLength() + { + return $this->_length; + } + + /** + * Returns the exact playtime given in seconds as a string in the form of + * [hours:]minutes:seconds.milliseconds. + * + * @param integer $seconds The playtime in seconds. + * @return string + */ + public function getFormattedLength() + { + return $this->formatTime($this->getLength()); + } +} diff --git a/app/libs/vendor/Zend/Media/Ogg/Exception.php b/app/libs/vendor/Zend/Media/Ogg/Exception.php index 4e2f0027..8cadb897 100644 --- a/app/libs/vendor/Zend/Media/Ogg/Exception.php +++ b/app/libs/vendor/Zend/Media/Ogg/Exception.php @@ -1,39 +1,39 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 231 2011-05-14 13:05:48Z svollbehr $ - */ -class Zend_Media_Ogg_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 231 2011-05-14 13:05:48Z svollbehr $ + */ +class Zend_Media_Ogg_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Ogg/Page.php b/app/libs/vendor/Zend/Media/Ogg/Page.php index 3dc8713f..093e1aa2 100644 --- a/app/libs/vendor/Zend/Media/Ogg/Page.php +++ b/app/libs/vendor/Zend/Media/Ogg/Page.php @@ -1,235 +1,235 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Page.php 231 2011-05-14 13:05:48Z svollbehr $ - */ -final class Zend_Media_Ogg_Page -{ - /** - * The reader object. - * - * @var Zend_Io_Reader - */ - private $_reader; - - /** @var string */ - private $_capturePattern; - - /** @var integer */ - private $_streamStructureVersion; - - /** @var integer */ - private $_headerTypeFlag; - - /** @var integer */ - private $_granulePosition; - - /** @var integer */ - private $_bitstreamSerialNumber; - - /** @var integer */ - private $_pageSequenceNumber; - - /** @var integer */ - private $_crcChecksum; - - /** @var integer */ - private $_numberPageSegments; - - /** @var Array */ - private $_segmentTable = array(); - - /** @var integer */ - private $_size; - - /** @var integer */ - private $_headerSize; - - /** @var integer */ - private $_pageSize; - - /** - * Constructs the class with given parameters and reads object related data - * from the Ogg bitstream. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - $this->_reader = $reader; - - $this->_capturePattern = $this->_reader->read(4); - if ($this->_capturePattern != 'OggS') { - require_once 'Zend/Media/Ogg/Exception.php'; - throw new Zend_Media_Ogg_Exception('Not a valid Ogg bitstream'); - } - $this->_streamStructureVersion = $this->_reader->readUInt8(); - if ($this->_streamStructureVersion != 0) { - require_once 'Zend/Media/Ogg/Exception.php'; - throw new Zend_Media_Ogg_Exception('Unsupported Ogg stream structure version'); - } - $this->_headerTypeFlag = $this->_reader->readUInt8(); - $this->_granulePosition = $this->_reader->readInt64LE(); - $this->_bitstreamSerialNumber = $this->_reader->readUInt32LE(); - $this->_pageSequenceNumber = $this->_reader->readUInt32LE(); - $this->_crcChecksum = $this->_reader->readUInt32LE(); - $this->_numberPageSegments = $this->_reader->readUInt8(); - $this->_segmentTable = array(); - for ($i = 0; $i < $this->_numberPageSegments; $i++) { - $this->_segmentTable[] = $this->_reader->readUInt8(); - } - $this->_headerSize = $this->_numberPageSegments + 27; - $this->_pageSize = array_sum($this->_segmentTable); - $this->_size = $this->_headerSize + $this->_pageSize; - } - - /** - * Returns this page's context identifier in the bitstream. - * - * @return integer - */ - public final function getHeaderTypeFlag() - { - return $this->_headerTypeFlag; - } - - /** - * Returns total samples encoded after including all packets finished on this page (packets begun on this page but - * continuing on to the next page do not count). - * - * The rationale here is that the position specified in the frame header of the last page tells how long the data - * coded by the bitstream is. A truncated stream will still return the proper number of samples that can be decoded - * fully. - * - * A special value of '-1' (in two's complement) indicates that no packets finish on this page. - * - * @return integer - */ - public final function getGranulePosition() - { - return $this->_granulePosition; - } - - /** - * Returns the logical bitstream serial number. - * - * Ogg allows for separate logical bitstreams to be mixed at page granularity in a physical bitstream. The most - * common case would be sequential arrangement, but it is possible to interleave pages for two separate bitstreams - * to be decoded concurrently. The serial number is the means by which pages physical pages are associated with a - * particular logical stream. Each logical stream must have a unique serial number within a physical stream. - * - * @return integer - */ - public final function getBitstreamSerialNumber() - { - return $this->_bitstreamSerialNumber; - } - - /** - * Returns the page counter; lets us know if a page is lost (useful where packets span page boundaries). - * - * @return integer - */ - public final function getPageSequenceNumber() - { - return $this->_pageSequenceNumber; - } - - /** - * Returns the 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7). - * The value is computed over the entire header (with the CRC field in the header set to zero) and then continued - * over the page. The CRC field is then filled with the computed value. - * - * @return integer - */ - public final function getCrcChecksum() - { - return $this->_crcChecksum; - } - - /** - * Returns the number of segment entries to appear in the segment table. The maximum number of 255 segments (255 - * bytes each) sets the maximum possible physical page size at 65307 bytes or just under 64kB (thus we know that a - * header corrupted so as destroy sizing/alignment information will not cause a runaway bitstream. We'll read in the - * page according to the corrupted size information that's guaranteed to be a reasonable size regardless, notice the - * checksum mismatch, drop sync and then look for recapture). - * - * @return integer - */ - public final function getNumberPageSegments() - { - return $this->_numberPageSegments; - } - - /** - * Returns the lacing values for each packet segment physically appearing in this page are listed in contiguous - * order. - * - * @return integer - */ - public final function getSegmentTable() - { - return $this->_segmentTable; - } - - /** - * Returns the total page size with the header in bytes. - * - * @return integer - */ - public final function getSize() - { - return $this->_size; - } - - /** - * Returns the total header size in bytes. - * - * @return integer - */ - public final function getHeaderSize() - { - return $this->_headerSize; - } - - /** - * Returns the total page size without the header in bytes. The page size is calculated directly from the known - * lacing values in the segment table. - * - * @return integer - */ - public final function getPageSize() - { - return $this->_pageSize; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Page.php 231 2011-05-14 13:05:48Z svollbehr $ + */ +final class Zend_Media_Ogg_Page +{ + /** + * The reader object. + * + * @var Zend_Io_Reader + */ + private $_reader; + + /** @var string */ + private $_capturePattern; + + /** @var integer */ + private $_streamStructureVersion; + + /** @var integer */ + private $_headerTypeFlag; + + /** @var integer */ + private $_granulePosition; + + /** @var integer */ + private $_bitstreamSerialNumber; + + /** @var integer */ + private $_pageSequenceNumber; + + /** @var integer */ + private $_crcChecksum; + + /** @var integer */ + private $_numberPageSegments; + + /** @var Array */ + private $_segmentTable = array(); + + /** @var integer */ + private $_size; + + /** @var integer */ + private $_headerSize; + + /** @var integer */ + private $_pageSize; + + /** + * Constructs the class with given parameters and reads object related data + * from the Ogg bitstream. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + $this->_reader = $reader; + + $this->_capturePattern = $this->_reader->read(4); + if ($this->_capturePattern != 'OggS') { + require_once 'Zend/Media/Ogg/Exception.php'; + throw new Zend_Media_Ogg_Exception('Not a valid Ogg bitstream'); + } + $this->_streamStructureVersion = $this->_reader->readUInt8(); + if ($this->_streamStructureVersion != 0) { + require_once 'Zend/Media/Ogg/Exception.php'; + throw new Zend_Media_Ogg_Exception('Unsupported Ogg stream structure version'); + } + $this->_headerTypeFlag = $this->_reader->readUInt8(); + $this->_granulePosition = $this->_reader->readInt64LE(); + $this->_bitstreamSerialNumber = $this->_reader->readUInt32LE(); + $this->_pageSequenceNumber = $this->_reader->readUInt32LE(); + $this->_crcChecksum = $this->_reader->readUInt32LE(); + $this->_numberPageSegments = $this->_reader->readUInt8(); + $this->_segmentTable = array(); + for ($i = 0; $i < $this->_numberPageSegments; $i++) { + $this->_segmentTable[] = $this->_reader->readUInt8(); + } + $this->_headerSize = $this->_numberPageSegments + 27; + $this->_pageSize = array_sum($this->_segmentTable); + $this->_size = $this->_headerSize + $this->_pageSize; + } + + /** + * Returns this page's context identifier in the bitstream. + * + * @return integer + */ + public final function getHeaderTypeFlag() + { + return $this->_headerTypeFlag; + } + + /** + * Returns total samples encoded after including all packets finished on this page (packets begun on this page but + * continuing on to the next page do not count). + * + * The rationale here is that the position specified in the frame header of the last page tells how long the data + * coded by the bitstream is. A truncated stream will still return the proper number of samples that can be decoded + * fully. + * + * A special value of '-1' (in two's complement) indicates that no packets finish on this page. + * + * @return integer + */ + public final function getGranulePosition() + { + return $this->_granulePosition; + } + + /** + * Returns the logical bitstream serial number. + * + * Ogg allows for separate logical bitstreams to be mixed at page granularity in a physical bitstream. The most + * common case would be sequential arrangement, but it is possible to interleave pages for two separate bitstreams + * to be decoded concurrently. The serial number is the means by which pages physical pages are associated with a + * particular logical stream. Each logical stream must have a unique serial number within a physical stream. + * + * @return integer + */ + public final function getBitstreamSerialNumber() + { + return $this->_bitstreamSerialNumber; + } + + /** + * Returns the page counter; lets us know if a page is lost (useful where packets span page boundaries). + * + * @return integer + */ + public final function getPageSequenceNumber() + { + return $this->_pageSequenceNumber; + } + + /** + * Returns the 32 bit CRC value (direct algorithm, initial val and final XOR = 0, generator polynomial=0x04c11db7). + * The value is computed over the entire header (with the CRC field in the header set to zero) and then continued + * over the page. The CRC field is then filled with the computed value. + * + * @return integer + */ + public final function getCrcChecksum() + { + return $this->_crcChecksum; + } + + /** + * Returns the number of segment entries to appear in the segment table. The maximum number of 255 segments (255 + * bytes each) sets the maximum possible physical page size at 65307 bytes or just under 64kB (thus we know that a + * header corrupted so as destroy sizing/alignment information will not cause a runaway bitstream. We'll read in the + * page according to the corrupted size information that's guaranteed to be a reasonable size regardless, notice the + * checksum mismatch, drop sync and then look for recapture). + * + * @return integer + */ + public final function getNumberPageSegments() + { + return $this->_numberPageSegments; + } + + /** + * Returns the lacing values for each packet segment physically appearing in this page are listed in contiguous + * order. + * + * @return integer + */ + public final function getSegmentTable() + { + return $this->_segmentTable; + } + + /** + * Returns the total page size with the header in bytes. + * + * @return integer + */ + public final function getSize() + { + return $this->_size; + } + + /** + * Returns the total header size in bytes. + * + * @return integer + */ + public final function getHeaderSize() + { + return $this->_headerSize; + } + + /** + * Returns the total page size without the header in bytes. The page size is calculated directly from the known + * lacing values in the segment table. + * + * @return integer + */ + public final function getPageSize() + { + return $this->_pageSize; + } +} diff --git a/app/libs/vendor/Zend/Media/Ogg/Reader.php b/app/libs/vendor/Zend/Media/Ogg/Reader.php index 5f814e45..375239f1 100644 --- a/app/libs/vendor/Zend/Media/Ogg/Reader.php +++ b/app/libs/vendor/Zend/Media/Ogg/Reader.php @@ -1,191 +1,191 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Reader.php 239 2011-06-04 09:35:48Z svollbehr $ - * @todo Currently supports only one logical bitstream - */ -final class Zend_Media_Ogg_Reader extends Zend_Io_Reader -{ - /** @var Array */ - private $_pages = array(); - - /** @var integer */ - private $_currentPageNumber = 0; - - /** @var integer */ - private $_currentPagePosition = 0; - - /** - * Constructs the Ogg class with given file. - * - * @param string $filename The path to the file. - * @throws Zend_Io_Exception if an error occur in stream handling. - * @throws Zend_Media_Ogg_Exception if an error occurs in Ogg bitstream reading. - */ - public function __construct($filename) - { - $reader = new Zend_Io_FileReader($filename); - $fileSize = $reader->getSize(); - while ($reader->getOffset() < $fileSize) { - $this->_pages[] = array( - 'offset' => $reader->getOffset(), - 'page' => $page = new Zend_Media_Ogg_Page($reader) - ); - $this->_size += $page->getPageSize(); - $reader->skip($page->getPageSize()); - } - $reader->setOffset - ($this->_pages[$this->_currentPageNumber]['offset'] + - $this->_pages[$this->_currentPageNumber]['page']->getHeaderSize()); - $this->_fd = $reader->getFileDescriptor(); - } - - /** - * Overwrite the method to return the current point of operation within the Ogg bitstream. - * - * @return integer - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function getOffset() - { - $offset = 0; - for ($i = 0; $i < $this->_currentPageNumber; $i++) { - $offset += $this->_pages[$i]['page']->getPageSize(); - } - return $offset += $this->_currentPagePosition; - } - - /** - * Overwrite the method to set the point of operation within the Ogg bitstream. - * - * @param integer $offset The new point of operation. - * @return void - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function setOffset($offset) - { - $streamSize = 0; - for ($i = 0, $pageCount = count($this->_pages); $i < $pageCount; $i++) { - if (($streamSize + $this->_pages[$i]['page']->getPageSize()) >= $offset) { - $this->_currentPageNumber = $i; - $this->_currentPagePosition = $offset - $streamSize; - parent::setOffset - ($this->_pages[$i]['offset'] + $this->_pages[$i]['page']->getHeaderSize() + - $this->_currentPagePosition); - break; - } - $streamSize += $this->_pages[$i]['page']->getPageSize(); - } - } - - /** - * Overwrite the method to jump size amount of bytes in the Ogg bitstream. - * - * @param integer $size The amount of bytes to jump within the Ogg bitstream. - * @return void - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function skip($size) - { - $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); - if (($this->_currentPagePosition + $size) >= $currentPageSize) { - parent::skip - (($currentPageSize - $this->_currentPagePosition) + - $this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize() + - ($this->_currentPagePosition = ($size - ($currentPageSize - $this->_currentPagePosition)))); - } else { - $this->_currentPagePosition += $size; - parent::skip($size); - } - } - - /** - * Overwrite the method to read bytes within the Ogg bitstream. - * - * @param integer $length The amount of bytes to read within the Ogg bitstream. - * @return string - * @throws Zend_Io_Exception if an I/O error occurs - */ - public function read($length) - { - $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); - if (($this->_currentPagePosition + $length) >= $currentPageSize) { - $buffer = parent::read($currentPageSize - $this->_currentPagePosition); - parent::skip($this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize()); - return $buffer . parent::read - ($this->_currentPagePosition = ($length - ($currentPageSize - $this->_currentPagePosition))); - } else { - $buffer = parent::read($length); - $this->_currentPagePosition += $length; - return $buffer; - } - } - - /** - * Returns the underlying Ogg page at given number. - * - * @param integer $pageNumber The number of the page to return. - * @return Zend_Media_Ogg_Page - */ - public function getPage($pageNumber) - { - return $this->_pages[$pageNumber]['page']; - } - - /** - * Returns the underlying Ogg page number. - * - * @return integer - */ - public function getCurrentPageNumber() - { - return $this->_currentPageNumber; - } - - /** - * Returns the underlying Ogg page position, in bytes. - * - * @return integer - */ - public function getCurrentPagePosition() - { - return $this->_currentPagePosition; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Reader.php 239 2011-06-04 09:35:48Z svollbehr $ + * @todo Currently supports only one logical bitstream + */ +final class Zend_Media_Ogg_Reader extends Zend_Io_Reader +{ + /** @var Array */ + private $_pages = array(); + + /** @var integer */ + private $_currentPageNumber = 0; + + /** @var integer */ + private $_currentPagePosition = 0; + + /** + * Constructs the Ogg class with given file. + * + * @param string $filename The path to the file. + * @throws Zend_Io_Exception if an error occur in stream handling. + * @throws Zend_Media_Ogg_Exception if an error occurs in Ogg bitstream reading. + */ + public function __construct($filename) + { + $reader = new Zend_Io_FileReader($filename); + $fileSize = $reader->getSize(); + while ($reader->getOffset() < $fileSize) { + $this->_pages[] = array( + 'offset' => $reader->getOffset(), + 'page' => $page = new Zend_Media_Ogg_Page($reader) + ); + $this->_size += $page->getPageSize(); + $reader->skip($page->getPageSize()); + } + $reader->setOffset + ($this->_pages[$this->_currentPageNumber]['offset'] + + $this->_pages[$this->_currentPageNumber]['page']->getHeaderSize()); + $this->_fd = $reader->getFileDescriptor(); + } + + /** + * Overwrite the method to return the current point of operation within the Ogg bitstream. + * + * @return integer + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function getOffset() + { + $offset = 0; + for ($i = 0; $i < $this->_currentPageNumber; $i++) { + $offset += $this->_pages[$i]['page']->getPageSize(); + } + return $offset += $this->_currentPagePosition; + } + + /** + * Overwrite the method to set the point of operation within the Ogg bitstream. + * + * @param integer $offset The new point of operation. + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function setOffset($offset) + { + $streamSize = 0; + for ($i = 0, $pageCount = count($this->_pages); $i < $pageCount; $i++) { + if (($streamSize + $this->_pages[$i]['page']->getPageSize()) >= $offset) { + $this->_currentPageNumber = $i; + $this->_currentPagePosition = $offset - $streamSize; + parent::setOffset + ($this->_pages[$i]['offset'] + $this->_pages[$i]['page']->getHeaderSize() + + $this->_currentPagePosition); + break; + } + $streamSize += $this->_pages[$i]['page']->getPageSize(); + } + } + + /** + * Overwrite the method to jump size amount of bytes in the Ogg bitstream. + * + * @param integer $size The amount of bytes to jump within the Ogg bitstream. + * @return void + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function skip($size) + { + $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); + if (($this->_currentPagePosition + $size) >= $currentPageSize) { + parent::skip + (($currentPageSize - $this->_currentPagePosition) + + $this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize() + + ($this->_currentPagePosition = ($size - ($currentPageSize - $this->_currentPagePosition)))); + } else { + $this->_currentPagePosition += $size; + parent::skip($size); + } + } + + /** + * Overwrite the method to read bytes within the Ogg bitstream. + * + * @param integer $length The amount of bytes to read within the Ogg bitstream. + * @return string + * @throws Zend_Io_Exception if an I/O error occurs + */ + public function read($length) + { + $currentPageSize = $this->_pages[$this->_currentPageNumber]['page']->getPageSize(); + if (($this->_currentPagePosition + $length) >= $currentPageSize) { + $buffer = parent::read($currentPageSize - $this->_currentPagePosition); + parent::skip($this->_pages[++$this->_currentPageNumber]['page']->getHeaderSize()); + return $buffer . parent::read + ($this->_currentPagePosition = ($length - ($currentPageSize - $this->_currentPagePosition))); + } else { + $buffer = parent::read($length); + $this->_currentPagePosition += $length; + return $buffer; + } + } + + /** + * Returns the underlying Ogg page at given number. + * + * @param integer $pageNumber The number of the page to return. + * @return Zend_Media_Ogg_Page + */ + public function getPage($pageNumber) + { + return $this->_pages[$pageNumber]['page']; + } + + /** + * Returns the underlying Ogg page number. + * + * @return integer + */ + public function getCurrentPageNumber() + { + return $this->_currentPageNumber; + } + + /** + * Returns the underlying Ogg page position, in bytes. + * + * @return integer + */ + public function getCurrentPagePosition() + { + return $this->_currentPagePosition; + } +} diff --git a/app/libs/vendor/Zend/Media/Riff.php b/app/libs/vendor/Zend/Media/Riff.php index a238c9cd..78a5c947 100644 --- a/app/libs/vendor/Zend/Media/Riff.php +++ b/app/libs/vendor/Zend/Media/Riff.php @@ -1,75 +1,75 @@ - - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Riff.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff extends Zend_Media_Riff_ContainerChunk -{ - /** @var string */ - private $_filename = null; - - /** - * Constructs the class with given file. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, file descriptor of an opened file, or a - * {@link Zend_Io_Reader} instance. - * @throws Zend_Media_Riff_Exception if given file descriptor is not valid or an error occurs in stream handling. - */ - public function __construct($filename) - { - if ($filename instanceof Zend_Io_Reader) { - $reader = &$filename; - } else { - $this->_filename = $filename; - require_once('Zend/Io/FileReader.php'); - try { - $reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - require_once 'Zend/Media/Riff/Exception.php'; - throw new Zend_Media_Riff_Exception($e->getMessage()); - } - } - - parent::__construct($reader); - } -} + + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Riff.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff extends Zend_Media_Riff_ContainerChunk +{ + /** @var string */ + private $_filename = null; + + /** + * Constructs the class with given file. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, file descriptor of an opened file, or a + * {@link Zend_Io_Reader} instance. + * @throws Zend_Media_Riff_Exception if given file descriptor is not valid or an error occurs in stream handling. + */ + public function __construct($filename) + { + if ($filename instanceof Zend_Io_Reader) { + $reader = &$filename; + } else { + $this->_filename = $filename; + require_once('Zend/Io/FileReader.php'); + try { + $reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + require_once 'Zend/Media/Riff/Exception.php'; + throw new Zend_Media_Riff_Exception($e->getMessage()); + } + } + + parent::__construct($reader); + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk.php b/app/libs/vendor/Zend/Media/Riff/Chunk.php index 5bb769c0..e09d8a89 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk.php @@ -1,125 +1,125 @@ - - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Chunk.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -abstract class Zend_Media_Riff_Chunk -{ - /** - * The reader object. - * - * @var Reader - */ - protected $_reader; - - /** @var integer */ - protected $_identifier; - - /** @var integer */ - protected $_size; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - $this->_reader = $reader; - $this->_identifier = $this->_reader->read(4); - $this->_size = $this->_reader->readUInt32LE(); - } - - /** - * Returns a four-character code that identifies the representation of the chunk data. A program reading a RIFF file - * can skip over any chunk whose chunk ID it doesn't recognize; it simply skips the number of bytes specified by - * size plus the pad byte, if present. - * - * @return string - */ - public final function getIdentifier() - { - return $this->_identifier; - } - - /** - * Sets the four-character code that identifies the representation of the chunk data. - * - * @param string $identifier The chunk identifier. - */ - public final function setIdentifier($identifier) - { - $this->_identifier = $identifier; - } - - /** - * Returns the size of chunk data. This size value does not include the size of the identifier or size fields or the - * pad byte at the end of chunk data. - * - * @return integer - */ - public final function getSize() - { - return $this->_size; - } - - /** - * Sets the size of chunk data. This size value must not include the size of the identifier or size fields or the - * pad byte at the end of chunk data. - * - * @param integer $size The size of chunk data. - */ - public final function setSize($size) - { - $this->_size = $size; - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { - return call_user_func(array($this, 'get' . ucfirst(strtolower($name)))); - } else { - require_once('Zend/Media/Riff/Exception.php'); - throw new Zend_Media_Riff_Exception('Unknown field: ' . $name); - } - } - - /** - * Magic function so that assignments with $obj->value will work. - * - * @param string $name The field name. - * @param string $value The field value. - * @return mixed - */ - public function __set($name, $value) - { - if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { - call_user_func(array($this, 'set' . ucfirst(strtolower($name))), $value); - } else { - require_once('Zend/Media/Riff/Exception.php'); - throw new Zend_Media_Riff_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Chunk.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +abstract class Zend_Media_Riff_Chunk +{ + /** + * The reader object. + * + * @var Reader + */ + protected $_reader; + + /** @var integer */ + protected $_identifier; + + /** @var integer */ + protected $_size; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + $this->_reader = $reader; + $this->_identifier = $this->_reader->read(4); + $this->_size = $this->_reader->readUInt32LE(); + } + + /** + * Returns a four-character code that identifies the representation of the chunk data. A program reading a RIFF file + * can skip over any chunk whose chunk ID it doesn't recognize; it simply skips the number of bytes specified by + * size plus the pad byte, if present. + * + * @return string + */ + public final function getIdentifier() + { + return $this->_identifier; + } + + /** + * Sets the four-character code that identifies the representation of the chunk data. + * + * @param string $identifier The chunk identifier. + */ + public final function setIdentifier($identifier) + { + $this->_identifier = $identifier; + } + + /** + * Returns the size of chunk data. This size value does not include the size of the identifier or size fields or the + * pad byte at the end of chunk data. + * + * @return integer + */ + public final function getSize() + { + return $this->_size; + } + + /** + * Sets the size of chunk data. This size value must not include the size of the identifier or size fields or the + * pad byte at the end of chunk data. + * + * @param integer $size The size of chunk data. + */ + public final function setSize($size) + { + $this->_size = $size; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst(strtolower($name)))) { + return call_user_func(array($this, 'get' . ucfirst(strtolower($name)))); + } else { + require_once('Zend/Media/Riff/Exception.php'); + throw new Zend_Media_Riff_Exception('Unknown field: ' . $name); + } + } + + /** + * Magic function so that assignments with $obj->value will work. + * + * @param string $name The field name. + * @param string $value The field value. + * @return mixed + */ + public function __set($name, $value) + { + if (method_exists($this, 'set' . ucfirst(strtolower($name)))) { + call_user_func(array($this, 'set' . ucfirst(strtolower($name))), $value); + } else { + require_once('Zend/Media/Riff/Exception.php'); + throw new Zend_Media_Riff_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Cgrp.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Cgrp.php index 5275f876..65b331a3 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Cgrp.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Cgrp.php @@ -1,47 +1,47 @@ -Compound File Element Group chunk stores the actual elements of data referenced by the - * {@link Zend_Media_Riff_Chunk_Ctoc CTOC} chunk. The CGRP chunk contains all the compound file elements, concatenated - * together into one contiguous block of data. Some of the elements in the CGRP chunk might be unused, if the element - * was marked for deletion or was altered and stored elsewhere within the CGRP chunk. - * - * Elements within the CGRP chunk are of arbitrary size and can appear in a specific or arbitrary order, depending upon - * the file format definition. Each element is identified by a corresponding {@link Zend_Media_Riff_Chunk_Ctoc CTOC} - * table entry. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Cgrp.php 257 2012-01-26 05:30:58Z svollbehr $ - * @todo Implementation - */ -final class Zend_Media_Riff_Chunk_Cgrp extends Zend_Media_Riff_Chunk -{ - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - require_once('Zend/Media/Riff/Exception.php'); - throw new Zend_Media_Riff_Exception('Not yet implemented'); - } -} +Compound File Element Group chunk stores the actual elements of data referenced by the + * {@link Zend_Media_Riff_Chunk_Ctoc CTOC} chunk. The CGRP chunk contains all the compound file elements, concatenated + * together into one contiguous block of data. Some of the elements in the CGRP chunk might be unused, if the element + * was marked for deletion or was altered and stored elsewhere within the CGRP chunk. + * + * Elements within the CGRP chunk are of arbitrary size and can appear in a specific or arbitrary order, depending upon + * the file format definition. Each element is identified by a corresponding {@link Zend_Media_Riff_Chunk_Ctoc CTOC} + * table entry. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Cgrp.php 257 2012-01-26 05:30:58Z svollbehr $ + * @todo Implementation + */ +final class Zend_Media_Riff_Chunk_Cgrp extends Zend_Media_Riff_Chunk +{ + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + require_once('Zend/Media/Riff/Exception.php'); + throw new Zend_Media_Riff_Exception('Not yet implemented'); + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Cset.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Cset.php index 93d7b631..97d7d018 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Cset.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Cset.php @@ -1,172 +1,172 @@ -Character Set chunk defines the code page and country, language, and dialect codes for the file. These - * values can be overridden for specific file elements. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Cset.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Cset extends Zend_Media_Riff_Chunk -{ - /** @var integer */ - private $_codePage; - - /** @var integer */ - private $_countryCode; - - /** @var integer */ - private $_language; - - /** @var integer */ - private $_dialect; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - $this->_codePage = $this->_reader->readUInt16LE(); - $this->_countryCode = $this->_reader->readUInt16LE(); - $this->_language = $this->_reader->readUInt16LE(); - $this->_dialect = $this->_reader->readUInt16LE(); - } - - /** - * Returns the code page used for file elements. If the CSET chunk is not present, or if this field has value zero, - * assume standard ISO-8859-1 code page (identical to code page 1004 without code points defined in hex columns 0, - * 1, 8, and 9). - * - * @return integer - */ - public final function getCodePage() - { - return $this->_codePage; - } - - /** - * Sets the code page used for file elements. Value can be one of the following. - * o 000 None (ignore this field) - * o 001 USA - * o 002 Canada - * o 003 Latin America - * o 030 Greece - * o 031 Netherlands - * o 032 Belgium - * o 033 France - * o 034 Spain - * o 039 Italy - * o 041 Switzerland - * o 043 Austria - * o 044 United Kingdom - * o 045 Denmark - * o 046 Sweden - * o 047 Norway - * o 049 West Germany - * o 052 Mexico - * o 055 Brazil - * o 061 Australia - * o 064 New Zealand - * o 081 Japan - * o 082 Korea - * o 086 People’s Republic of China - * o 088 Taiwan - * o 090 Turkey - * o 351 Portugal - * o 352 Luxembourg - * o 354 Iceland - * o 358 Finland - * - * @param string $type The code page used for file elements. - */ - public final function setCodePage($codePage) - { - $this->_codePage = $codePage; - } - - /** - * Returns the country code used for file elements. See the file format specification for a list of currently - * defined country codes. If the CSET chunk is not present, or if this field has value zero, assume USA (country - * code 001). - * - * @return integer - */ - public final function getCountryCode() - { - return $this->_countryCode; - } - - /** - * Sets the country code used for file elements. - * - * @param string $type The country code used for file elements. - */ - public final function setCountryCode($countryCode) - { - $this->_countryCode = $countryCode; - } - - /** - * Returns the language used for file elements. See the file format specification for a list of language codes. - * If the CSET chunk is not present, or if these fields have value zero, assume US English (language code 9, - * dialect code 1). - * - * @return integer - */ - public final function getLanguage() - { - return $this->_language; - } - - /** - * Sets the language used for file elements. - * - * @param string $type The language used for file elements. - */ - public final function setLanguage($language) - { - $this->_language = $language; - } - - /** - * Returns the dialect used for file elements. See the file format specification for a list of dialect codes. - * If the CSET chunk is not present, or if these fields have value zero, assume US English (language code 9, - * dialect code 1). - * - * @return integer - */ - public final function getDialect() - { - return $this->_dialect; - } - - /** - * Sets the dialect used for file elements. - * - * @param string $type The dialect used for file elements. - */ - public final function setDialect($dialect) - { - $this->_dialect = $dialect; - } -} +Character Set chunk defines the code page and country, language, and dialect codes for the file. These + * values can be overridden for specific file elements. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Cset.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Cset extends Zend_Media_Riff_Chunk +{ + /** @var integer */ + private $_codePage; + + /** @var integer */ + private $_countryCode; + + /** @var integer */ + private $_language; + + /** @var integer */ + private $_dialect; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + $this->_codePage = $this->_reader->readUInt16LE(); + $this->_countryCode = $this->_reader->readUInt16LE(); + $this->_language = $this->_reader->readUInt16LE(); + $this->_dialect = $this->_reader->readUInt16LE(); + } + + /** + * Returns the code page used for file elements. If the CSET chunk is not present, or if this field has value zero, + * assume standard ISO-8859-1 code page (identical to code page 1004 without code points defined in hex columns 0, + * 1, 8, and 9). + * + * @return integer + */ + public final function getCodePage() + { + return $this->_codePage; + } + + /** + * Sets the code page used for file elements. Value can be one of the following. + * o 000 None (ignore this field) + * o 001 USA + * o 002 Canada + * o 003 Latin America + * o 030 Greece + * o 031 Netherlands + * o 032 Belgium + * o 033 France + * o 034 Spain + * o 039 Italy + * o 041 Switzerland + * o 043 Austria + * o 044 United Kingdom + * o 045 Denmark + * o 046 Sweden + * o 047 Norway + * o 049 West Germany + * o 052 Mexico + * o 055 Brazil + * o 061 Australia + * o 064 New Zealand + * o 081 Japan + * o 082 Korea + * o 086 People’s Republic of China + * o 088 Taiwan + * o 090 Turkey + * o 351 Portugal + * o 352 Luxembourg + * o 354 Iceland + * o 358 Finland + * + * @param string $type The code page used for file elements. + */ + public final function setCodePage($codePage) + { + $this->_codePage = $codePage; + } + + /** + * Returns the country code used for file elements. See the file format specification for a list of currently + * defined country codes. If the CSET chunk is not present, or if this field has value zero, assume USA (country + * code 001). + * + * @return integer + */ + public final function getCountryCode() + { + return $this->_countryCode; + } + + /** + * Sets the country code used for file elements. + * + * @param string $type The country code used for file elements. + */ + public final function setCountryCode($countryCode) + { + $this->_countryCode = $countryCode; + } + + /** + * Returns the language used for file elements. See the file format specification for a list of language codes. + * If the CSET chunk is not present, or if these fields have value zero, assume US English (language code 9, + * dialect code 1). + * + * @return integer + */ + public final function getLanguage() + { + return $this->_language; + } + + /** + * Sets the language used for file elements. + * + * @param string $type The language used for file elements. + */ + public final function setLanguage($language) + { + $this->_language = $language; + } + + /** + * Returns the dialect used for file elements. See the file format specification for a list of dialect codes. + * If the CSET chunk is not present, or if these fields have value zero, assume US English (language code 9, + * dialect code 1). + * + * @return integer + */ + public final function getDialect() + { + return $this->_dialect; + } + + /** + * Sets the dialect used for file elements. + * + * @param string $type The dialect used for file elements. + */ + public final function setDialect($dialect) + { + $this->_dialect = $dialect; + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ctoc.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ctoc.php index 9a860042..565b3dbf 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ctoc.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ctoc.php @@ -1,47 +1,47 @@ -Compound File Table of Contents chunk functions mainly as an index, allowing direct access to elements - * within a compound file. The CTOC chunk also contains information about the attributes of the entire file and of each - * media element within the file. - * - * To provide the maximum flexibility for defining compound file formats, the CTOC chunk can be customized at several - * levels. The CTOC chunk contains fields whose length and usage is defined by other CTOC fields. This parameterization - * adds complexity, but it provides flexibility to file format designers and allows applications to correctly read data - * without necessarily knowing the specific file format definition. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ctoc.php 257 2012-01-26 05:30:58Z svollbehr $ - * @todo Implementation - */ -final class Zend_Media_Riff_Chunk_Ctoc extends Zend_Media_Riff_Chunk -{ - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - require_once('Zend/Media/Riff/Exception.php'); - throw new Zend_Media_Riff_Exception('Not yet implemented'); - } -} +Compound File Table of Contents chunk functions mainly as an index, allowing direct access to elements + * within a compound file. The CTOC chunk also contains information about the attributes of the entire file and of each + * media element within the file. + * + * To provide the maximum flexibility for defining compound file formats, the CTOC chunk can be customized at several + * levels. The CTOC chunk contains fields whose length and usage is defined by other CTOC fields. This parameterization + * adds complexity, but it provides flexibility to file format designers and allows applications to correctly read data + * without necessarily knowing the specific file format definition. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ctoc.php 257 2012-01-26 05:30:58Z svollbehr $ + * @todo Implementation + */ +final class Zend_Media_Riff_Chunk_Ctoc extends Zend_Media_Riff_Chunk +{ + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + require_once('Zend/Media/Riff/Exception.php'); + throw new Zend_Media_Riff_Exception('Not yet implemented'); + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Iarl.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Iarl.php index 1ac8977f..db481cbd 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Iarl.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Iarl.php @@ -1,28 +1,28 @@ -Archival Location chunk indicates where the subject of the file is archived. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iarl.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Iarl extends Zend_Media_Riff_StringChunk -{ -} +Archival Location chunk indicates where the subject of the file is archived. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iarl.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Iarl extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Iart.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Iart.php index 825d9257..8b47b9b4 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Iart.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Iart.php @@ -1,28 +1,28 @@ -Artist chunk lists the artist of the original subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iart.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Iart extends Zend_Media_Riff_StringChunk -{ -} +Artist chunk lists the artist of the original subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iart.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Iart extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Icms.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Icms.php index 1772d6d0..79e5377a 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Icms.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Icms.php @@ -1,28 +1,28 @@ -Commissioned chunk lists the name of the person or organization that commissioned the subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Icms.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Icms extends Zend_Media_Riff_StringChunk -{ -} +Commissioned chunk lists the name of the person or organization that commissioned the subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Icms.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Icms extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Icmt.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Icmt.php index 75e2e7fd..ee241697 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Icmt.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Icmt.php @@ -1,29 +1,29 @@ -Comments chunk provides general comments about the file or the subject of the file. If the comment is - * several sentences long, end each sentence with a period. Do not include newline characters. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Icmt.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Icmt extends Zend_Media_Riff_StringChunk -{ -} +Comments chunk provides general comments about the file or the subject of the file. If the comment is + * several sentences long, end each sentence with a period. Do not include newline characters. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Icmt.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Icmt extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Icop.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Icop.php index 08f137a0..cad54e12 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Icop.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Icop.php @@ -1,29 +1,29 @@ -Copyright chunk records the copyright information for the file. If there are multiple copyrights, separate - * them by a semicolon followed by a space. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Icop.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Icop extends Zend_Media_Riff_StringChunk -{ -} +Copyright chunk records the copyright information for the file. If there are multiple copyrights, separate + * them by a semicolon followed by a space. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Icop.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Icop extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Icrd.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Icrd.php index efff936b..d151dd20 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Icrd.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Icrd.php @@ -1,29 +1,29 @@ -Creation date chunk specifies the date the subject of the file was created. List dates in year-month-day - * format, padding one-digit months and days with a zero on the left. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Icrd.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Icrd extends Zend_Media_Riff_StringChunk -{ -} +Creation date chunk specifies the date the subject of the file was created. List dates in year-month-day + * format, padding one-digit months and days with a zero on the left. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Icrd.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Icrd extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Icrp.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Icrp.php index 99452939..bc2883d3 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Icrp.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Icrp.php @@ -1,28 +1,28 @@ -Cropped chunk describes whether an image has been cropped and, if so, how it was cropped. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Icrp.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Icrp extends Zend_Media_Riff_StringChunk -{ -} +Cropped chunk describes whether an image has been cropped and, if so, how it was cropped. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Icrp.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Icrp extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Id3.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Id3.php index ccb2e726..1042a3dd 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Id3.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Id3.php @@ -1,62 +1,62 @@ -ID3 Tag chunk contains an {@link Zend_Media_Id3v2 ID3v2} tag. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Id3.php 258 2012-01-26 05:33:46Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Id3 extends Zend_Media_Riff_Chunk -{ - /** @var Zend_Media_Id3v2 */ - private $_tag; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - $this->_tag = new Zend_Media_Id3v2($this->_reader, array('readonly' => true)); - } - - /** - * Returns the {@link Zend_Media_Id3v2 Id3v2} tag class instance. - * - * @return string - */ - public function getTag() - { - return $this->_tag; - } - - /** - * Sets the {@link Zend_Media_Id3v2 Id3v2} tag class instance. - * - * @param Zend_Media_Id3v2 $tag The tag instance. - */ - public function setTag($tag) - { - $this->_tag = $tag; - } -} +ID3 Tag chunk contains an {@link Zend_Media_Id3v2 ID3v2} tag. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Id3.php 258 2012-01-26 05:33:46Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Id3 extends Zend_Media_Riff_Chunk +{ + /** @var Zend_Media_Id3v2 */ + private $_tag; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + $this->_tag = new Zend_Media_Id3v2($this->_reader, array('readonly' => true)); + } + + /** + * Returns the {@link Zend_Media_Id3v2 Id3v2} tag class instance. + * + * @return string + */ + public function getTag() + { + return $this->_tag; + } + + /** + * Sets the {@link Zend_Media_Id3v2 Id3v2} tag class instance. + * + * @param Zend_Media_Id3v2 $tag The tag instance. + */ + public function setTag($tag) + { + $this->_tag = $tag; + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Idim.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Idim.php index 48b8500f..f16965c9 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Idim.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Idim.php @@ -1,28 +1,28 @@ -Dimensions chunk specifies the size of the original subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Idim.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Idim extends Zend_Media_Riff_StringChunk -{ -} +Dimensions chunk specifies the size of the original subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Idim.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Idim extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Idpi.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Idpi.php index 556b6b5b..fe80a048 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Idpi.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Idpi.php @@ -1,28 +1,28 @@ -Dots Per Inch chunk stores dots per inch setting of the digitizer used to produce the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Idpi.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Idpi extends Zend_Media_Riff_StringChunk -{ -} +Dots Per Inch chunk stores dots per inch setting of the digitizer used to produce the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Idpi.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Idpi extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ieng.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ieng.php index cc23526f..780519b7 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ieng.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ieng.php @@ -1,29 +1,29 @@ -Engineer stores the name of the engineer who worked on the file. If there are multiple engineers, separate - * the names by a semicolon and a blank. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ieng.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Ieng extends Zend_Media_Riff_StringChunk -{ -} +Engineer stores the name of the engineer who worked on the file. If there are multiple engineers, separate + * the names by a semicolon and a blank. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ieng.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Ieng extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ignr.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ignr.php index 6a25900f..cda4971d 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ignr.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ignr.php @@ -1,28 +1,28 @@ -Genre chunk describes the original work, such as, landscape, portrait, still life, etc. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ignr.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Ignr extends Zend_Media_Riff_StringChunk -{ -} +Genre chunk describes the original work, such as, landscape, portrait, still life, etc. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ignr.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Ignr extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ikey.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ikey.php index c8892238..3bee0288 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ikey.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ikey.php @@ -1,29 +1,29 @@ -Keywords provides a list of keywords that refer to the file or subject of the file. Separate multiple - * keywords with a semicolon and a blank. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ikey.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Ikey extends Zend_Media_Riff_StringChunk -{ -} +Keywords provides a list of keywords that refer to the file or subject of the file. Separate multiple + * keywords with a semicolon and a blank. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ikey.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Ikey extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ilgt.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ilgt.php index 6596a50d..3071b4a1 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ilgt.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ilgt.php @@ -1,29 +1,29 @@ -Lightness chunk describes the changes in lightness settings on the digitizer required to produce the file. - * Note that the format of this information depends on hardware used. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ilgt.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Ilgt extends Zend_Media_Riff_StringChunk -{ -} +Lightness chunk describes the changes in lightness settings on the digitizer required to produce the file. + * Note that the format of this information depends on hardware used. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ilgt.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Ilgt extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Imed.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Imed.php index 8f3a4a59..a1ce934e 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Imed.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Imed.php @@ -1,28 +1,28 @@ -Medium describes the original subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Imed.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Imed extends Zend_Media_Riff_StringChunk -{ -} +Medium describes the original subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Imed.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Imed extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Inam.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Inam.php index 962b3fd1..7363117a 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Inam.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Inam.php @@ -1,28 +1,28 @@ -Name chunk stores the title of the subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Inam.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Inam extends Zend_Media_Riff_StringChunk -{ -} +Name chunk stores the title of the subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Inam.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Inam extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Iplt.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Iplt.php index 554f345f..67e419ad 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Iplt.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Iplt.php @@ -1,28 +1,28 @@ -Palette Setting specifies the number of colors requested when digitizing an image. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iplt.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Iplt extends Zend_Media_Riff_StringChunk -{ -} +Palette Setting specifies the number of colors requested when digitizing an image. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iplt.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Iplt extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Iprd.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Iprd.php index 632b0881..0c38e7b1 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Iprd.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Iprd.php @@ -1,28 +1,28 @@ -Product chunk specifies the name of the title the file was originally intended for. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Iprd.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Iprd extends Zend_Media_Riff_StringChunk -{ -} +Product chunk specifies the name of the title the file was originally intended for. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Iprd.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Iprd extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Isbj.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Isbj.php index cd593a3d..2d9d6c19 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Isbj.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Isbj.php @@ -1,28 +1,28 @@ -Subject describes the conbittents of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Isbj.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Isbj extends Zend_Media_Riff_StringChunk -{ -} +Subject describes the conbittents of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Isbj.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Isbj extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Isft.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Isft.php index 3545db18..45b7c0be 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Isft.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Isft.php @@ -1,28 +1,28 @@ -Software identifies the name of the software package used to create the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Isft.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Isft extends Zend_Media_Riff_StringChunk -{ -} +Software identifies the name of the software package used to create the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Isft.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Isft extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Ishp.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Ishp.php index 1f3c59ad..cf838829 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Ishp.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Ishp.php @@ -1,29 +1,29 @@ -Sharpness chunk identifies the changes in sharpness for the digitizer required to produce the file (the - * format depends on the hardware used). - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Ishp.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Ishp extends Zend_Media_Riff_StringChunk -{ -} +Sharpness chunk identifies the changes in sharpness for the digitizer required to produce the file (the + * format depends on the hardware used). + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Ishp.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Ishp extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Isrc.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Isrc.php index c927848c..1fe467b3 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Isrc.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Isrc.php @@ -1,28 +1,28 @@ -Source chunk identifies the name of the person or organization who supplied the original subject of the file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Isrc.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Isrc extends Zend_Media_Riff_StringChunk -{ -} +Source chunk identifies the name of the person or organization who supplied the original subject of the file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Isrc.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Isrc extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Isrf.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Isrf.php index dea63fc5..a1beeb37 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Isrf.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Isrf.php @@ -1,29 +1,29 @@ -Source Form chunk identifies the original form of the material that was digitized, such as slide, paper, map, - * and so forth. This is not necessarily the same as {@link Zend_Media_Riff_Chunk_Imed IMED}. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Isrf.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Isrf extends Zend_Media_Riff_StringChunk -{ -} +Source Form chunk identifies the original form of the material that was digitized, such as slide, paper, map, + * and so forth. This is not necessarily the same as {@link Zend_Media_Riff_Chunk_Imed IMED}. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Isrf.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Isrf extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Itch.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Itch.php index ab62bea3..588229a9 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Itch.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Itch.php @@ -1,28 +1,28 @@ -Technician chunk identifies the technician who digitized the subject file. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Itch.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Itch extends Zend_Media_Riff_StringChunk -{ -} +Technician chunk identifies the technician who digitized the subject file. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Itch.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Itch extends Zend_Media_Riff_StringChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/Junk.php b/app/libs/vendor/Zend/Media/Riff/Chunk/Junk.php index 00192bf7..cf557ca9 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/Junk.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/Junk.php @@ -1,29 +1,29 @@ -Filler chunk represents padding, filler or outdated information. It contains no relevant data; it is a - * space filler of arbitrary size. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Junk.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_Junk extends Zend_Media_Riff_Chunk -{ -} +Filler chunk represents padding, filler or outdated information. It contains no relevant data; it is a + * space filler of arbitrary size. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Junk.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_Junk extends Zend_Media_Riff_Chunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/Chunk/List.php b/app/libs/vendor/Zend/Media/Riff/Chunk/List.php index 68110716..42dcc73f 100644 --- a/app/libs/vendor/Zend/Media/Riff/Chunk/List.php +++ b/app/libs/vendor/Zend/Media/Riff/Chunk/List.php @@ -1,28 +1,28 @@ -LIST chunk contains a list, or ordered sequence, of subchunks. - * - * @category Zend - * @package Zend_Media - * @subpackage Riff - * @author Sven Vollbehr - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: List.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -final class Zend_Media_Riff_Chunk_List extends Zend_Media_Riff_ContainerChunk -{ -} +LIST chunk contains a list, or ordered sequence, of subchunks. + * + * @category Zend + * @package Zend_Media + * @subpackage Riff + * @author Sven Vollbehr + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: List.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +final class Zend_Media_Riff_Chunk_List extends Zend_Media_Riff_ContainerChunk +{ +} diff --git a/app/libs/vendor/Zend/Media/Riff/ContainerChunk.php b/app/libs/vendor/Zend/Media/Riff/ContainerChunk.php index 991f3ebd..aaaac0fc 100644 --- a/app/libs/vendor/Zend/Media/Riff/ContainerChunk.php +++ b/app/libs/vendor/Zend/Media/Riff/ContainerChunk.php @@ -1,142 +1,142 @@ - - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: ContainerChunk.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -abstract class Zend_Media_Riff_ContainerChunk extends Zend_Media_Riff_Chunk -{ - /** @var string */ - protected $_type; - - /** @var Array */ - private $_chunks = array(); - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - $startOffset = $this->_reader->getOffset(); - $this->_type = $this->_reader->read(4); - while (($this->_reader->getOffset() - $startOffset) < $this->_size) { - $offset = $this->_reader->getOffset(); - - $identifier = $this->_reader->read(4); - $size = $this->_reader->readUInt32LE(); - - $this->_reader->setOffset($offset); - if (@fopen - ($file = 'Zend/Media/Riff/Chunk/' . - ucfirst(strtolower(rtrim($identifier, ' '))) . '.php', 'r', true) !== false) { - require_once($file); - } - if (class_exists($classname = 'Zend_Media_Riff_Chunk_' . ucfirst(strtolower(rtrim($identifier, ' '))))) { - $this->_chunks[] = new $classname($this->_reader); - - $this->_reader->setOffset($offset + 8 + $size); - } else { - trigger_error('Unknown RIFF chunk: \'' . $identifier . '\' skipped', E_USER_WARNING); - $this->_reader->skip(8 + $size); - } - } - } - - /** - * Returns a four-character code that identifies the contents of the container chunk. - * - * @return string - */ - public final function getType() - { - return $this->_type; - } - - /** - * Sets the four-character code that identifies the contents of the container chunk. - * - * @param string $type The chunk container type. - */ - public final function setType($type) - { - $this->_type = $type; - } - - /** - * Returns all the chunks this chunk contains as an array. - * - * @return Array - */ - public final function getChunks() - { - return $this->_chunks; - } - - /** - * Returns an array of chunks matching the given identifier or an empty array if no chunks matched the identifier. - * - * The identifier may contain wildcard characters '*' and '?'. The asterisk matches against zero or more characters, - * and the question mark matches any single character. - * - * Please note that one may also use the shorthand $obj->identifier to access the first chunk with the identifier - * given. Wildcards cannot be used with the shorthand. - * - * @param string $identifier The chunk identifier. - * @return Array - */ - public final function getChunksByIdentifier($identifier) - { - $matches = array(); - $searchPattern = "/^" . str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; - foreach ($this->_chunks as $chunk) { - if (preg_match($searchPattern, rtrim($chunk->getIdentifier(), ' '))) { - $matches[] = $chunk; - } - } - return $matches; - } - - /** - * Magic function so that $obj->value will work. The method will first attempt to return the first contained chunk - * whose identifier matches the given name, and if not found, invoke a getter method. - * - * If there are no chunks or getter methods with the given name, an exception is thrown. - * - * @param string $name The chunk or field name. - * @return mixed - */ - public function __get($name) - { - $chunks = $this->getChunksByIdentifier($name); - if (count($chunks) > 0) { - return $chunks[0]; - } - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - require_once 'Zend/Media/Riff/Exception.php'; - throw new Zend_Media_Riff_Exception('Unknown chunk/field: ' . $name); - } -} + + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: ContainerChunk.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +abstract class Zend_Media_Riff_ContainerChunk extends Zend_Media_Riff_Chunk +{ + /** @var string */ + protected $_type; + + /** @var Array */ + private $_chunks = array(); + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + $startOffset = $this->_reader->getOffset(); + $this->_type = $this->_reader->read(4); + while (($this->_reader->getOffset() - $startOffset) < $this->_size) { + $offset = $this->_reader->getOffset(); + + $identifier = $this->_reader->read(4); + $size = $this->_reader->readUInt32LE(); + + $this->_reader->setOffset($offset); + if (@fopen + ($file = 'Zend/Media/Riff/Chunk/' . + ucfirst(strtolower(rtrim($identifier, ' '))) . '.php', 'r', true) !== false) { + require_once($file); + } + if (class_exists($classname = 'Zend_Media_Riff_Chunk_' . ucfirst(strtolower(rtrim($identifier, ' '))))) { + $this->_chunks[] = new $classname($this->_reader); + + $this->_reader->setOffset($offset + 8 + $size); + } else { + trigger_error('Unknown RIFF chunk: \'' . $identifier . '\' skipped', E_USER_WARNING); + $this->_reader->skip(8 + $size); + } + } + } + + /** + * Returns a four-character code that identifies the contents of the container chunk. + * + * @return string + */ + public final function getType() + { + return $this->_type; + } + + /** + * Sets the four-character code that identifies the contents of the container chunk. + * + * @param string $type The chunk container type. + */ + public final function setType($type) + { + $this->_type = $type; + } + + /** + * Returns all the chunks this chunk contains as an array. + * + * @return Array + */ + public final function getChunks() + { + return $this->_chunks; + } + + /** + * Returns an array of chunks matching the given identifier or an empty array if no chunks matched the identifier. + * + * The identifier may contain wildcard characters '*' and '?'. The asterisk matches against zero or more characters, + * and the question mark matches any single character. + * + * Please note that one may also use the shorthand $obj->identifier to access the first chunk with the identifier + * given. Wildcards cannot be used with the shorthand. + * + * @param string $identifier The chunk identifier. + * @return Array + */ + public final function getChunksByIdentifier($identifier) + { + $matches = array(); + $searchPattern = "/^" . str_replace(array("*", "?"), array(".*", "."), $identifier) . "$/i"; + foreach ($this->_chunks as $chunk) { + if (preg_match($searchPattern, rtrim($chunk->getIdentifier(), ' '))) { + $matches[] = $chunk; + } + } + return $matches; + } + + /** + * Magic function so that $obj->value will work. The method will first attempt to return the first contained chunk + * whose identifier matches the given name, and if not found, invoke a getter method. + * + * If there are no chunks or getter methods with the given name, an exception is thrown. + * + * @param string $name The chunk or field name. + * @return mixed + */ + public function __get($name) + { + $chunks = $this->getChunksByIdentifier($name); + if (count($chunks) > 0) { + return $chunks[0]; + } + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + require_once 'Zend/Media/Riff/Exception.php'; + throw new Zend_Media_Riff_Exception('Unknown chunk/field: ' . $name); + } +} diff --git a/app/libs/vendor/Zend/Media/Riff/Exception.php b/app/libs/vendor/Zend/Media/Riff/Exception.php index 20d6f927..a1cb147a 100644 --- a/app/libs/vendor/Zend/Media/Riff/Exception.php +++ b/app/libs/vendor/Zend/Media/Riff/Exception.php @@ -1,28 +1,28 @@ - - * @copyright Copyright (c) Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -class Zend_Media_Riff_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +class Zend_Media_Riff_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Riff/StringChunk.php b/app/libs/vendor/Zend/Media/Riff/StringChunk.php index 3e35cc2f..d1340f3f 100644 --- a/app/libs/vendor/Zend/Media/Riff/StringChunk.php +++ b/app/libs/vendor/Zend/Media/Riff/StringChunk.php @@ -1,67 +1,67 @@ - - * @copyright Copyright (c) 2011 Sven Vollbehr - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: StringChunk.php 257 2012-01-26 05:30:58Z svollbehr $ - */ -abstract class Zend_Media_Riff_StringChunk extends Zend_Media_Riff_Chunk -{ - /** @var string */ - protected $_value; - - /** - * Constructs the class with given parameters and options. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - $this->_value = rtrim($this->_reader->read($this->_size), "\0"); - } - - /** - * Returns the text string value. - * - * @return string - */ - public final function getValue() - { - return $this->_value; - } - - /** - * Sets the text string value. - * - * @param string $type The text string value. - */ - public final function setValue($value) - { - $this->_value = $value; - } -} + + * @copyright Copyright (c) 2011 Sven Vollbehr + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: StringChunk.php 257 2012-01-26 05:30:58Z svollbehr $ + */ +abstract class Zend_Media_Riff_StringChunk extends Zend_Media_Riff_Chunk +{ + /** @var string */ + protected $_value; + + /** + * Constructs the class with given parameters and options. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + $this->_value = rtrim($this->_reader->read($this->_size), "\0"); + } + + /** + * Returns the text string value. + * + * @return string + */ + public final function getValue() + { + return $this->_value; + } + + /** + * Sets the text string value. + * + * @param string $type The text string value. + */ + public final function setValue($value) + { + $this->_value = $value; + } +} diff --git a/app/libs/vendor/Zend/Media/Vorbis.php b/app/libs/vendor/Zend/Media/Vorbis.php index 89e31fde..0ab74ac1 100644 --- a/app/libs/vendor/Zend/Media/Vorbis.php +++ b/app/libs/vendor/Zend/Media/Vorbis.php @@ -1,141 +1,141 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Vorbis.php 239 2011-06-04 09:35:48Z svollbehr $ - * @todo Setup header is not yet supported - */ -final class Zend_Media_Vorbis -{ - /** @var Zend_Io_Reader */ - private $_reader; - - /** @var string */ - private $_filename = null; - - /** @var Zend_Media_Vorbis_Header_Identification */ - private $_identificationHeader; - - /** @var Zend_Media_Vorbis_Header_Comment */ - private $_commentHeader; - - /** @var Zend_Media_Vorbis_Header_Setup */ - private $_setupHeader; - - /** - * Constructs the Zend_Media_Vorbis class with given file. - * - * @param string|resource|Zend_Io_Reader $filename The path to the file, - * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. - * @throws Zend_Io_Exception if an error occur in stream handling. - * @throws Zend_Media_Vorbis_Exception if an error occurs in vorbis bitstream reading. - */ - public function __construct($filename) - { - if ($filename instanceof Zend_Io_Reader) { - $this->_reader = &$filename; - } else { - $this->_filename = $filename; - require_once('Zend/Io/FileReader.php'); - try { - $this->_reader = new Zend_Io_FileReader($filename); - } catch (Zend_Io_Exception $e) { - $this->_reader = null; - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception($e->getMessage()); - } - } - - $this->_identificationHeader = new Zend_Media_Vorbis_Header_Identification($this->_reader); - $this->_commentHeader = new Zend_Media_Vorbis_Header_Comment($this->_reader); - $this->_setupHeader = new Zend_Media_Vorbis_Header_Setup($this->_reader); - } - - /** - * Returns the identification header. - * - * @return Zend_Media_Vorbis_Header_Identification - */ - public function getIdentificationHeader() - { - return $this->_identificationHeader; - } - - /** - * Returns the comment header. - * - * @return Zend_Media_Vorbis_Header_Comment - */ - public function getCommentHeader() - { - return $this->_commentHeader; - } - - /** - * Returns the setup header. - * - * @return Zend_Media_Vorbis_Header_Setup - */ - public function getSetupHeader() - { - return $this->_setupHeader; - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } else { - require_once('Zend/Media/Vorbis/Exception.php'); - throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Vorbis.php 239 2011-06-04 09:35:48Z svollbehr $ + * @todo Setup header is not yet supported + */ +final class Zend_Media_Vorbis +{ + /** @var Zend_Io_Reader */ + private $_reader; + + /** @var string */ + private $_filename = null; + + /** @var Zend_Media_Vorbis_Header_Identification */ + private $_identificationHeader; + + /** @var Zend_Media_Vorbis_Header_Comment */ + private $_commentHeader; + + /** @var Zend_Media_Vorbis_Header_Setup */ + private $_setupHeader; + + /** + * Constructs the Zend_Media_Vorbis class with given file. + * + * @param string|resource|Zend_Io_Reader $filename The path to the file, + * file descriptor of an opened file, or a {@link Zend_Io_Reader} instance. + * @throws Zend_Io_Exception if an error occur in stream handling. + * @throws Zend_Media_Vorbis_Exception if an error occurs in vorbis bitstream reading. + */ + public function __construct($filename) + { + if ($filename instanceof Zend_Io_Reader) { + $this->_reader = &$filename; + } else { + $this->_filename = $filename; + require_once('Zend/Io/FileReader.php'); + try { + $this->_reader = new Zend_Io_FileReader($filename); + } catch (Zend_Io_Exception $e) { + $this->_reader = null; + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception($e->getMessage()); + } + } + + $this->_identificationHeader = new Zend_Media_Vorbis_Header_Identification($this->_reader); + $this->_commentHeader = new Zend_Media_Vorbis_Header_Comment($this->_reader); + $this->_setupHeader = new Zend_Media_Vorbis_Header_Setup($this->_reader); + } + + /** + * Returns the identification header. + * + * @return Zend_Media_Vorbis_Header_Identification + */ + public function getIdentificationHeader() + { + return $this->_identificationHeader; + } + + /** + * Returns the comment header. + * + * @return Zend_Media_Vorbis_Header_Comment + */ + public function getCommentHeader() + { + return $this->_commentHeader; + } + + /** + * Returns the setup header. + * + * @return Zend_Media_Vorbis_Header_Setup + */ + public function getSetupHeader() + { + return $this->_setupHeader; + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } else { + require_once('Zend/Media/Vorbis/Exception.php'); + throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Vorbis/Exception.php b/app/libs/vendor/Zend/Media/Vorbis/Exception.php index a660c441..27727b95 100644 --- a/app/libs/vendor/Zend/Media/Vorbis/Exception.php +++ b/app/libs/vendor/Zend/Media/Vorbis/Exception.php @@ -1,39 +1,39 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Exception.php 232 2011-05-14 13:09:03Z svollbehr $ - */ -class Zend_Media_Vorbis_Exception extends Zend_Media_Exception -{} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Exception.php 232 2011-05-14 13:09:03Z svollbehr $ + */ +class Zend_Media_Vorbis_Exception extends Zend_Media_Exception +{} diff --git a/app/libs/vendor/Zend/Media/Vorbis/Header.php b/app/libs/vendor/Zend/Media/Vorbis/Header.php index bc2ef8fd..0b6b49de 100644 --- a/app/libs/vendor/Zend/Media/Vorbis/Header.php +++ b/app/libs/vendor/Zend/Media/Vorbis/Header.php @@ -1,115 +1,115 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Header.php 239 2011-06-04 09:35:48Z svollbehr $ - */ -abstract class Zend_Media_Vorbis_Header -{ - /** - * The reader object. - * - * @var Reader - */ - protected $_reader; - - /** - * The packet type; the identication header is type 1, the comment header type 3 and the setup header type 5. - * - * @var Array - */ - protected $_packetType; - - /** $var integer */ - protected $_packetSize = 0; - - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options The options array. - */ - public function __construct($reader) - { - $this->_reader = $reader; - if (!in_array($this->_packetType = $this->_reader->readUInt8(), array(1, 3, 5))) { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Unknown header packet type: ' . $this->_packetType); - } - if (($vorbis = $this->_reader->read(6)) != 'vorbis') { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Unknown header packet: ' . $vorbis); - } - - $skipBytes = $this->_reader->getCurrentPagePosition(); - for ($page = $this->_reader->getCurrentPageNumber(); /* goes on until we find packet end */; $page++) { - $segments = $this->_reader->getPage($page)->getSegmentTable(); - for ($i = 0, $skippedSegments = 0; $i < count($segments); $i++) { - // Skip page segments that are already read in - if ($skipBytes > $segments[$i]) { - $skipBytes -= $segments[$i]; - continue; - } - - // Skip segments that are full - if ($segments[$i] == 255 && ++$skippedSegments) { - continue; - } - - // Record packet size from the first non-255 segment - $this->_packetSize += $i * 255 + $segments[$i]; - break 2; - } - $this->_packetSize += $skippedSegments * 255; - } - } - - /** - * Magic function so that $obj->value will work. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } else { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name); - } - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Header.php 239 2011-06-04 09:35:48Z svollbehr $ + */ +abstract class Zend_Media_Vorbis_Header +{ + /** + * The reader object. + * + * @var Reader + */ + protected $_reader; + + /** + * The packet type; the identication header is type 1, the comment header type 3 and the setup header type 5. + * + * @var Array + */ + protected $_packetType; + + /** $var integer */ + protected $_packetSize = 0; + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options The options array. + */ + public function __construct($reader) + { + $this->_reader = $reader; + if (!in_array($this->_packetType = $this->_reader->readUInt8(), array(1, 3, 5))) { + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Unknown header packet type: ' . $this->_packetType); + } + if (($vorbis = $this->_reader->read(6)) != 'vorbis') { + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Unknown header packet: ' . $vorbis); + } + + $skipBytes = $this->_reader->getCurrentPagePosition(); + for ($page = $this->_reader->getCurrentPageNumber(); /* goes on until we find packet end */; $page++) { + $segments = $this->_reader->getPage($page)->getSegmentTable(); + for ($i = 0, $skippedSegments = 0; $i < count($segments); $i++) { + // Skip page segments that are already read in + if ($skipBytes > $segments[$i]) { + $skipBytes -= $segments[$i]; + continue; + } + + // Skip segments that are full + if ($segments[$i] == 255 && ++$skippedSegments) { + continue; + } + + // Record packet size from the first non-255 segment + $this->_packetSize += $i * 255 + $segments[$i]; + break 2; + } + $this->_packetSize += $skippedSegments * 255; + } + } + + /** + * Magic function so that $obj->value will work. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } else { + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Unknown field: ' . $name); + } + } +} diff --git a/app/libs/vendor/Zend/Media/Vorbis/Header/Comment.php b/app/libs/vendor/Zend/Media/Vorbis/Header/Comment.php index 82dc4275..1506e561 100644 --- a/app/libs/vendor/Zend/Media/Vorbis/Header/Comment.php +++ b/app/libs/vendor/Zend/Media/Vorbis/Header/Comment.php @@ -1,199 +1,199 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Comment.php 251 2011-06-13 15:41:51Z svollbehr $ - */ -final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header -{ - /** @var string */ - private $_vendor; - - /** @var Array */ - private $_comments; - - /** @var integer */ - private $_framingFlag = 1; - - /** - * Constructs the class with given parameters and reads object related data from the bitstream. - * - * The following options are currently recognized: - * o vorbisContext -- Indicates whether to expect comments to be in the context of a vorbis bitstream or not. This - * option can be used to parse vorbis comments in another formats, eg FLAC, that do not use for example the - * framing flags. Defaults to true. - * - * @param Zend_Io_Reader $reader The reader object. - * @param Array $options Array of options. - */ - public function __construct($reader, $options = array()) - { - if (!isset($options['vorbisContext']) || $options['vorbisContext']) { - parent::__construct($reader); - } else { - $this->_reader = $reader; - } - $this->_vendor = $this->_reader->read($this->_reader->readUInt32LE()); - $userCommentListLength = $this->_reader->readUInt32LE(); - for ($i = 0; $i < $userCommentListLength; $i++) { - list ($name, $value) = preg_split('/=/', $this->_reader->read($this->_reader->readUInt32LE()), 2); - if (!isset($this->_comments[strtoupper($name)])) { - $this->_comments[strtoupper($name)] = array(); - } - $this->_comments[strtoupper($name)][] = $value; - } - if (!isset($options['vorbisContext']) || $options['vorbisContext']) { - $this->_framingFlag = $this->_reader->readUInt8() & 0x1; - if ($this->_framingFlag == 0) { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream'); - } - $this->_reader->skip($this->_packetSize - $this->_reader->getOffset() + 30 /* header */); - } - } - - /** - * Returns the vendor string. - * - * @return string - */ - public function getVendor() - { - return $this->_vendor; - } - - /** - * Returns an array of comments having the field names as keys and an array of values as a value. - * - * @return Array - */ - public function getComments() - { - return $this->_comments; - } - - /** - * Returns an array of comments having the field names as keys and an array of values as a value. The array is - * restricted to field names that matches the given criteria. Unlike the getX() methods, which return the first - * value, this method returns an array of field values. - * - * @return Array - */ - public function getCommentsByName($name) - { - if (!empty($this->_comments[strtoupper($name)])) { - return $this->_comments[strtoupper($name)]; - } - return array(); - } - - /** - * Magic function so that $obj->X() or $obj->getX() will work, where X is the name of the comment field. The method - * will attempt to return the first field by the given name from the comment. If there is no field with given name, - * an exception is thrown. - * - * @param string $name The field name. - * @return mixed - */ - public function __call($name, $arguments) - { - if (preg_match('/^(?:get)([A-Z].*)$/', $name, $matches)) { - $name = $matches[1]; - } - if (!empty($this->_comments[strtoupper($name)])) { - return $this->_comments[strtoupper($name)][0]; - } - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Unknown field: ' . strtoupper($name)); - } - - /** - * Magic function so that $obj->value will work. The method will attempt to return the first field by the given - * name from the comment. If there is no field with given name, functionality of the parent method is executed. - * - * @param string $name The field name. - * @return mixed - */ - public function __get($name) - { - if (method_exists($this, 'get' . ucfirst($name))) { - return call_user_func(array($this, 'get' . ucfirst($name))); - } - if (!empty($this->_comments[strtoupper($name)])) { - return $this->_comments[strtoupper($name)][0]; - } - parent::__get($name); - } - - /** - * Magic function so that isset($obj->value) will work. This method checks whether the comment contains a field by - * the given name. - * - * @param string $name The field name. - * @return boolean - */ - public function __isset($name) - { - return count($this->_comments[strtoupper($name)]) > 0; - } - - /** - * Magic function so that unset($obj->value) will work. This method removes all the comments matching the field - * name. - * - * @param string $name The field name. - */ - public function __unset($name) - { - unset($this->_comments[strtoupper($name)]); - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Comment.php 251 2011-06-13 15:41:51Z svollbehr $ + */ +final class Zend_Media_Vorbis_Header_Comment extends Zend_Media_Vorbis_Header +{ + /** @var string */ + private $_vendor; + + /** @var Array */ + private $_comments; + + /** @var integer */ + private $_framingFlag = 1; + + /** + * Constructs the class with given parameters and reads object related data from the bitstream. + * + * The following options are currently recognized: + * o vorbisContext -- Indicates whether to expect comments to be in the context of a vorbis bitstream or not. This + * option can be used to parse vorbis comments in another formats, eg FLAC, that do not use for example the + * framing flags. Defaults to true. + * + * @param Zend_Io_Reader $reader The reader object. + * @param Array $options Array of options. + */ + public function __construct($reader, $options = array()) + { + if (!isset($options['vorbisContext']) || $options['vorbisContext']) { + parent::__construct($reader); + } else { + $this->_reader = $reader; + } + $this->_vendor = $this->_reader->read($this->_reader->readUInt32LE()); + $userCommentListLength = $this->_reader->readUInt32LE(); + for ($i = 0; $i < $userCommentListLength; $i++) { + list ($name, $value) = preg_split('/=/', $this->_reader->read($this->_reader->readUInt32LE()), 2); + if (!isset($this->_comments[strtoupper($name)])) { + $this->_comments[strtoupper($name)] = array(); + } + $this->_comments[strtoupper($name)][] = $value; + } + if (!isset($options['vorbisContext']) || $options['vorbisContext']) { + $this->_framingFlag = $this->_reader->readUInt8() & 0x1; + if ($this->_framingFlag == 0) { + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream'); + } + $this->_reader->skip($this->_packetSize - $this->_reader->getOffset() + 30 /* header */); + } + } + + /** + * Returns the vendor string. + * + * @return string + */ + public function getVendor() + { + return $this->_vendor; + } + + /** + * Returns an array of comments having the field names as keys and an array of values as a value. + * + * @return Array + */ + public function getComments() + { + return $this->_comments; + } + + /** + * Returns an array of comments having the field names as keys and an array of values as a value. The array is + * restricted to field names that matches the given criteria. Unlike the getX() methods, which return the first + * value, this method returns an array of field values. + * + * @return Array + */ + public function getCommentsByName($name) + { + if (!empty($this->_comments[strtoupper($name)])) { + return $this->_comments[strtoupper($name)]; + } + return array(); + } + + /** + * Magic function so that $obj->X() or $obj->getX() will work, where X is the name of the comment field. The method + * will attempt to return the first field by the given name from the comment. If there is no field with given name, + * an exception is thrown. + * + * @param string $name The field name. + * @return mixed + */ + public function __call($name, $arguments) + { + if (preg_match('/^(?:get)([A-Z].*)$/', $name, $matches)) { + $name = $matches[1]; + } + if (!empty($this->_comments[strtoupper($name)])) { + return $this->_comments[strtoupper($name)][0]; + } + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Unknown field: ' . strtoupper($name)); + } + + /** + * Magic function so that $obj->value will work. The method will attempt to return the first field by the given + * name from the comment. If there is no field with given name, functionality of the parent method is executed. + * + * @param string $name The field name. + * @return mixed + */ + public function __get($name) + { + if (method_exists($this, 'get' . ucfirst($name))) { + return call_user_func(array($this, 'get' . ucfirst($name))); + } + if (!empty($this->_comments[strtoupper($name)])) { + return $this->_comments[strtoupper($name)][0]; + } + parent::__get($name); + } + + /** + * Magic function so that isset($obj->value) will work. This method checks whether the comment contains a field by + * the given name. + * + * @param string $name The field name. + * @return boolean + */ + public function __isset($name) + { + return count($this->_comments[strtoupper($name)]) > 0; + } + + /** + * Magic function so that unset($obj->value) will work. This method removes all the comments matching the field + * name. + * + * @param string $name The field name. + */ + public function __unset($name) + { + unset($this->_comments[strtoupper($name)]); + } +} diff --git a/app/libs/vendor/Zend/Media/Vorbis/Header/Identification.php b/app/libs/vendor/Zend/Media/Vorbis/Header/Identification.php index c53ea838..6934bf5a 100644 --- a/app/libs/vendor/Zend/Media/Vorbis/Header/Identification.php +++ b/app/libs/vendor/Zend/Media/Vorbis/Header/Identification.php @@ -1,170 +1,170 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Identification.php 233 2011-05-14 16:00:55Z svollbehr $ - */ -final class Zend_Media_Vorbis_Header_Identification extends Zend_Media_Vorbis_Header -{ - /** @var integer */ - private $_vorbisVersion; - - /** @var integer */ - private $_audioChannels; - - /** @var integer */ - private $_audioSampleRate; - - /** @var integer */ - private $_bitrateMaximum; - - /** @var integer */ - private $_bitrateNominal; - - /** @var integer */ - private $_bitrateMinimum; - - /** @var integer */ - private $_blocksize0; - - /** @var integer */ - private $_blocksize1; - - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_vorbisVersion = $this->_reader->readUInt32LE(); - $this->_audioChannels = $this->_reader->readUInt8(); - $this->_audioSampleRate = $this->_reader->readUInt32LE(); - $this->_bitrateMaximum = $this->_reader->readInt32LE(); - $this->_bitrateNominal = $this->_reader->readInt32LE(); - $this->_bitrateMinimum = $this->_reader->readInt32LE(); - $this->_blocksize0 = pow(2, ($tmp = $this->_reader->readUInt8()) & 0xf); - $this->_blocksize1 = pow(2, ($tmp >> 4) & 0xf); - $framingFlag = $this->_reader->readUInt8() & 0x1; - if ($this->_blocksize0 > $this->_blocksize1 || $framingFlag == 0) { - require_once 'Zend/Media/Vorbis/Exception.php'; - throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream'); - } - } - - /** - * Returns the vorbis version. - * - * @return integer - */ - public function getVorbisVersion() - { - return $this->_vorbisVersion; - } - - /** - * Returns the number of audio channels. - * - * @return integer - */ - public function getAudioChannels() - { - return $this->_audioChannels; - } - - /** - * Returns the audio sample rate. - * - * @return integer - */ - public function getAudioSampleRate() - { - return $this->_audioSampleRate; - } - - /** - * Returns the maximum bitrate. - * - * @return integer - */ - public function getBitrateMaximum() - { - return $this->_bitrateMaximum; - } - - /** - * Returns the nominal bitrate. - * - * @return integer - */ - public function getBitrateNominal() - { - return $this->_bitrateNominal; - } - - /** - * Returns the minimum bitrate. - * - * @return integer - */ - public function getBitrateMinimum() - { - return $this->_bitrateMinimum; - } - - /** - * Returns the first block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in - * Vorbis I. - * - * @return integer - */ - public function getBlocksize1() - { - return $this->_blocksize1; - } - - /** - * Returns the second block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in - * Vorbis I. - * - * @return integer - */ - public function getBlocksize2() - { - return $this->_blocksize2; - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Identification.php 233 2011-05-14 16:00:55Z svollbehr $ + */ +final class Zend_Media_Vorbis_Header_Identification extends Zend_Media_Vorbis_Header +{ + /** @var integer */ + private $_vorbisVersion; + + /** @var integer */ + private $_audioChannels; + + /** @var integer */ + private $_audioSampleRate; + + /** @var integer */ + private $_bitrateMaximum; + + /** @var integer */ + private $_bitrateNominal; + + /** @var integer */ + private $_bitrateMinimum; + + /** @var integer */ + private $_blocksize0; + + /** @var integer */ + private $_blocksize1; + + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_vorbisVersion = $this->_reader->readUInt32LE(); + $this->_audioChannels = $this->_reader->readUInt8(); + $this->_audioSampleRate = $this->_reader->readUInt32LE(); + $this->_bitrateMaximum = $this->_reader->readInt32LE(); + $this->_bitrateNominal = $this->_reader->readInt32LE(); + $this->_bitrateMinimum = $this->_reader->readInt32LE(); + $this->_blocksize0 = pow(2, ($tmp = $this->_reader->readUInt8()) & 0xf); + $this->_blocksize1 = pow(2, ($tmp >> 4) & 0xf); + $framingFlag = $this->_reader->readUInt8() & 0x1; + if ($this->_blocksize0 > $this->_blocksize1 || $framingFlag == 0) { + require_once 'Zend/Media/Vorbis/Exception.php'; + throw new Zend_Media_Vorbis_Exception('Undecodable Vorbis stream'); + } + } + + /** + * Returns the vorbis version. + * + * @return integer + */ + public function getVorbisVersion() + { + return $this->_vorbisVersion; + } + + /** + * Returns the number of audio channels. + * + * @return integer + */ + public function getAudioChannels() + { + return $this->_audioChannels; + } + + /** + * Returns the audio sample rate. + * + * @return integer + */ + public function getAudioSampleRate() + { + return $this->_audioSampleRate; + } + + /** + * Returns the maximum bitrate. + * + * @return integer + */ + public function getBitrateMaximum() + { + return $this->_bitrateMaximum; + } + + /** + * Returns the nominal bitrate. + * + * @return integer + */ + public function getBitrateNominal() + { + return $this->_bitrateNominal; + } + + /** + * Returns the minimum bitrate. + * + * @return integer + */ + public function getBitrateMinimum() + { + return $this->_bitrateMinimum; + } + + /** + * Returns the first block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in + * Vorbis I. + * + * @return integer + */ + public function getBlocksize1() + { + return $this->_blocksize1; + } + + /** + * Returns the second block size. Allowed final blocksize values are 64, 128, 256, 512, 1024, 2048, 4096 and 8192 in + * Vorbis I. + * + * @return integer + */ + public function getBlocksize2() + { + return $this->_blocksize2; + } +} diff --git a/app/libs/vendor/Zend/Media/Vorbis/Header/Setup.php b/app/libs/vendor/Zend/Media/Vorbis/Header/Setup.php index 3a6a88ec..215e2006 100644 --- a/app/libs/vendor/Zend/Media/Vorbis/Header/Setup.php +++ b/app/libs/vendor/Zend/Media/Vorbis/Header/Setup.php @@ -1,54 +1,54 @@ - - * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Setup.php 240 2011-06-04 17:52:40Z svollbehr $ - * @todo Implementation - */ -final class Zend_Media_Vorbis_Header_Setup extends Zend_Media_Vorbis_Header -{ - /** - * Constructs the class with given parameters. - * - * @param Zend_Io_Reader $reader The reader object. - */ - public function __construct($reader) - { - parent::__construct($reader); - - $this->_reader->skip($this->_packetSize - 7 /* header */); - } -} + + * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Setup.php 240 2011-06-04 17:52:40Z svollbehr $ + * @todo Implementation + */ +final class Zend_Media_Vorbis_Header_Setup extends Zend_Media_Vorbis_Header +{ + /** + * Constructs the class with given parameters. + * + * @param Zend_Io_Reader $reader The reader object. + */ + public function __construct($reader) + { + parent::__construct($reader); + + $this->_reader->skip($this->_packetSize - 7 /* header */); + } +} diff --git a/app/libs/vendor/Zend/Mime/Magic.php b/app/libs/vendor/Zend/Mime/Magic.php index b23d7155..31224d86 100644 --- a/app/libs/vendor/Zend/Mime/Magic.php +++ b/app/libs/vendor/Zend/Mime/Magic.php @@ -1,196 +1,196 @@ -1 -- byte number to begin checking from. '>' indicates a dependency - * upon the previous non-'>' line - * o 2 -- type of data to match. Can be one of following - * - byte (single character) - * - short (machine-order 16-bit integer) - * - long (machine-order 32-bit integer) - * - string (arbitrary-length string) - * - date (long integer date (seconds since Unix epoch/1970)) - * - beshort (big-endian 16-bit integer) - * - belong (big-endian 32-bit integer) - * - bedate (big-endian 32-bit integer date) - * - leshort (little-endian 16-bit integer) - * - lelong (little-endian 32-bit integer) - * - ledate (little-endian 32-bit integer date) - * o 3 -- contents of data to match - * o 4 -- file description/MIME type if matched - * o 5 -- optional MIME encoding if matched and if above was a MIME type - * - * @category Zend - * @package Zend_Mime - * @subpackage Magic - * @author Sven Vollbehr - * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - * @license http://framework.zend.com/license/new-bsd New BSD License - * @version $Id: Magic.php 193 2010-04-08 14:46:41Z svollbehr $ - */ -final class Zend_Mime_Magic -{ - /** @var string */ - private $_magic; - - /** - * Reads the magic information from given magic file. - * - * @param string $filename The path to the magic file. - */ - public function __construct($filename) - { - $reader = new Zend_Io_FileReader($filename); - $this->_magic = $reader->read($reader->getSize()); - } - - /** - * Returns the recognized MIME type/description of the given file. The type - * is determined by the content using magic bytes characteristic for the - * particular file type. - * - * If the type could not be found, the function returns the default value, - * or null. - * - * @param string $filename The file path whose type to determine. - * @param string $default The default value. - * @return string|false - */ - public function getMimeType($filename, $default = null) - { - $reader = new Zend_Io_FileReader($filename); - - $parentOffset = 0; - foreach (preg_split('/^/m', $this->_magic) as $line) { - $chunks = array(); - if (!preg_match("/^(?P>?)(?P\d+)\s+(?P\S+)\s+(?P\S+)(?:\s+(?P[a-" . - "z]+\/[a-z-0-9]+)?(?:\s+(?P.?+))?)?$/", - $line, $chunks)) { - continue; - } - - if ($chunks['Dependant']) { - $reader->setOffset($parentOffset); - $reader->skip($chunks['Byte']); - } else { - $reader->setOffset($parentOffset = $chunks['Byte']); - } - - $matchType = strtolower($chunks['MatchType']); - $matchData = preg_replace - (array("/\\\\ /", "/\\\\\\\\/", "/\\\\([0-7]{1,3})/e", - "/\\\\x([0-9A-Fa-f]{1,2})/e", "/0x([0-9A-Fa-f]+)/e"), - array(" ", "\\\\", - "pack(\"H*\", base_convert(\"$1\", 8, 16));", - "pack(\"H*\", \"$1\");", "hexdec(\"$1\");"), - $chunks["MatchData"]); - - switch ($matchType) { - case 'byte': // single character - $data = $reader->readInt8(); - break; - case 'short': // machine-order 16-bit integer - $data = $reader->readInt16(); - break; - case 'long': // machine-order 32-bit integer - $data = $reader->readInt32(); - break; - case 'string': // arbitrary-length string - $data = $reader->readString8(strlen($matchData)); - break; - case 'date': // long integer date (seconds since Unix epoch) - $data = $reader->readInt64BE(); - break; - case 'beshort': // big-endian 16-bit integer - $data = $reader->readUInt16BE(); - break; - case 'belong': // big-endian 32-bit integer - // break intentionally omitted - case 'bedate': // big-endian 32-bit integer date - $data = $reader->readUInt32BE(); - break; - case 'leshort': // little-endian 16-bit integer - $data = $reader->readUInt16LE(); - break; - case 'lelong': // little-endian 32-bit integer - // break intentionally omitted - case 'ledate': // little-endian 32-bit integer date - $data = $reader->readUInt32LE(); - break; - default: - $data = null; - break; - } - - if (strcmp($data, $matchData) == 0) { - if (!empty($chunks['MIMEType'])) { - return $chunks['MIMEType']; - } - if (!empty($chunks['Description'])) { - return rtrim($chunks['Description'], "\n"); - } - } - } - return $default; - } - - /** - * Returns the results of the mime type check either as a boolean or an - * array of boolean values. - * - * @param string|Array $filename The file path whose type to test. - * @param string|Array $mimeType The mime type to test against. - * @return boolean|Array - */ - public function isMimeType($filename, $mimeType) - { - if (is_array($filename)) { - $result = array(); - foreach ($filename as $key => $value) { - $result[] = - ($this->getMimeType($value) == - (is_array($mimeType) ? $mimeType[$key] : $mimeType)) ? - true : false; - } - return $result; - } else { - return $this->getMimeType($filename) == $mimeType ? true : false; - } - } -} +1 -- byte number to begin checking from. '>' indicates a dependency + * upon the previous non-'>' line + * o 2 -- type of data to match. Can be one of following + * - byte (single character) + * - short (machine-order 16-bit integer) + * - long (machine-order 32-bit integer) + * - string (arbitrary-length string) + * - date (long integer date (seconds since Unix epoch/1970)) + * - beshort (big-endian 16-bit integer) + * - belong (big-endian 32-bit integer) + * - bedate (big-endian 32-bit integer date) + * - leshort (little-endian 16-bit integer) + * - lelong (little-endian 32-bit integer) + * - ledate (little-endian 32-bit integer date) + * o 3 -- contents of data to match + * o 4 -- file description/MIME type if matched + * o 5 -- optional MIME encoding if matched and if above was a MIME type + * + * @category Zend + * @package Zend_Mime + * @subpackage Magic + * @author Sven Vollbehr + * @copyright Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + * @version $Id: Magic.php 193 2010-04-08 14:46:41Z svollbehr $ + */ +final class Zend_Mime_Magic +{ + /** @var string */ + private $_magic; + + /** + * Reads the magic information from given magic file. + * + * @param string $filename The path to the magic file. + */ + public function __construct($filename) + { + $reader = new Zend_Io_FileReader($filename); + $this->_magic = $reader->read($reader->getSize()); + } + + /** + * Returns the recognized MIME type/description of the given file. The type + * is determined by the content using magic bytes characteristic for the + * particular file type. + * + * If the type could not be found, the function returns the default value, + * or null. + * + * @param string $filename The file path whose type to determine. + * @param string $default The default value. + * @return string|false + */ + public function getMimeType($filename, $default = null) + { + $reader = new Zend_Io_FileReader($filename); + + $parentOffset = 0; + foreach (preg_split('/^/m', $this->_magic) as $line) { + $chunks = array(); + if (!preg_match("/^(?P>?)(?P\d+)\s+(?P\S+)\s+(?P\S+)(?:\s+(?P[a-" . + "z]+\/[a-z-0-9]+)?(?:\s+(?P.?+))?)?$/", + $line, $chunks)) { + continue; + } + + if ($chunks['Dependant']) { + $reader->setOffset($parentOffset); + $reader->skip($chunks['Byte']); + } else { + $reader->setOffset($parentOffset = $chunks['Byte']); + } + + $matchType = strtolower($chunks['MatchType']); + $matchData = preg_replace + (array("/\\\\ /", "/\\\\\\\\/", "/\\\\([0-7]{1,3})/e", + "/\\\\x([0-9A-Fa-f]{1,2})/e", "/0x([0-9A-Fa-f]+)/e"), + array(" ", "\\\\", + "pack(\"H*\", base_convert(\"$1\", 8, 16));", + "pack(\"H*\", \"$1\");", "hexdec(\"$1\");"), + $chunks["MatchData"]); + + switch ($matchType) { + case 'byte': // single character + $data = $reader->readInt8(); + break; + case 'short': // machine-order 16-bit integer + $data = $reader->readInt16(); + break; + case 'long': // machine-order 32-bit integer + $data = $reader->readInt32(); + break; + case 'string': // arbitrary-length string + $data = $reader->readString8(strlen($matchData)); + break; + case 'date': // long integer date (seconds since Unix epoch) + $data = $reader->readInt64BE(); + break; + case 'beshort': // big-endian 16-bit integer + $data = $reader->readUInt16BE(); + break; + case 'belong': // big-endian 32-bit integer + // break intentionally omitted + case 'bedate': // big-endian 32-bit integer date + $data = $reader->readUInt32BE(); + break; + case 'leshort': // little-endian 16-bit integer + $data = $reader->readUInt16LE(); + break; + case 'lelong': // little-endian 32-bit integer + // break intentionally omitted + case 'ledate': // little-endian 32-bit integer date + $data = $reader->readUInt32LE(); + break; + default: + $data = null; + break; + } + + if (strcmp($data, $matchData) == 0) { + if (!empty($chunks['MIMEType'])) { + return $chunks['MIMEType']; + } + if (!empty($chunks['Description'])) { + return rtrim($chunks['Description'], "\n"); + } + } + } + return $default; + } + + /** + * Returns the results of the mime type check either as a boolean or an + * array of boolean values. + * + * @param string|Array $filename The file path whose type to test. + * @param string|Array $mimeType The mime type to test against. + * @return boolean|Array + */ + public function isMimeType($filename, $mimeType) + { + if (is_array($filename)) { + $result = array(); + foreach ($filename as $key => $value) { + $result[] = + ($this->getMimeType($value) == + (is_array($mimeType) ? $mimeType[$key] : $mimeType)) ? + true : false; + } + return $result; + } else { + return $this->getMimeType($filename) == $mimeType ? true : false; + } + } +} diff --git a/app/libs/vendor/autoload.php b/app/libs/vendor/autoload.php index b4755b6b..59786a41 100644 --- a/app/libs/vendor/autoload.php +++ b/app/libs/vendor/autoload.php @@ -1,7 +1,7 @@ - - * Jordi Boggiano - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Composer\Autoload; - -/** - * ClassLoader implements a PSR-0 class loader - * - * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md - * - * $loader = new \Composer\Autoload\ClassLoader(); - * - * // register classes with namespaces - * $loader->add('Symfony\Component', __DIR__.'/component'); - * $loader->add('Symfony', __DIR__.'/framework'); - * - * // activate the autoloader - * $loader->register(); - * - * // to enable searching the include path (eg. for PEAR packages) - * $loader->setUseIncludePath(true); - * - * In this example, if you try to use a class in the Symfony\Component - * namespace or one of its children (Symfony\Component\Console for instance), - * the autoloader will first look for the class under the component/ - * directory, and it will then fallback to the framework/ directory if not - * found before giving up. - * - * This class is loosely based on the Symfony UniversalClassLoader. - * - * @author Fabien Potencier - * @author Jordi Boggiano - */ -class ClassLoader -{ - // PSR-4 - private $prefixLengthsPsr4 = array(); - private $prefixDirsPsr4 = array(); - private $fallbackDirsPsr4 = array(); - - // PSR-0 - private $prefixesPsr0 = array(); - private $fallbackDirsPsr0 = array(); - - private $useIncludePath = false; - private $classMap = array(); - - public function getPrefixes() - { - return call_user_func_array('array_merge', $this->prefixesPsr0); - } - - public function getPrefixesPsr4() - { - return $this->prefixDirsPsr4; - } - - public function getFallbackDirs() - { - return $this->fallbackDirsPsr0; - } - - public function getFallbackDirsPsr4() - { - return $this->fallbackDirsPsr4; - } - - public function getClassMap() - { - return $this->classMap; - } - - /** - * @param array $classMap Class to filename map - */ - public function addClassMap(array $classMap) - { - if ($this->classMap) { - $this->classMap = array_merge($this->classMap, $classMap); - } else { - $this->classMap = $classMap; - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, either - * appending or prepending to the ones previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories - */ - public function add($prefix, $paths, $prepend = false) - { - if (!$prefix) { - if ($prepend) { - $this->fallbackDirsPsr0 = array_merge( - (array) $paths, - $this->fallbackDirsPsr0 - ); - } else { - $this->fallbackDirsPsr0 = array_merge( - $this->fallbackDirsPsr0, - (array) $paths - ); - } - - return; - } - - $first = $prefix[0]; - if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; - - return; - } - if ($prepend) { - $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, - $this->prefixesPsr0[$first][$prefix] - ); - } else { - $this->prefixesPsr0[$first][$prefix] = array_merge( - $this->prefixesPsr0[$first][$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, either - * appending or prepending to the ones previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-0 base directories - * @param bool $prepend Whether to prepend the directories - */ - public function addPsr4($prefix, $paths, $prepend = false) - { - if (!$prefix) { - // Register directories for the root namespace. - if ($prepend) { - $this->fallbackDirsPsr4 = array_merge( - (array) $paths, - $this->fallbackDirsPsr4 - ); - } else { - $this->fallbackDirsPsr4 = array_merge( - $this->fallbackDirsPsr4, - (array) $paths - ); - } - } elseif (!isset($this->prefixDirsPsr4[$prefix])) { - // Register directories for a new namespace. - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } elseif ($prepend) { - // Prepend directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, - $this->prefixDirsPsr4[$prefix] - ); - } else { - // Append directories for an already registered namespace. - $this->prefixDirsPsr4[$prefix] = array_merge( - $this->prefixDirsPsr4[$prefix], - (array) $paths - ); - } - } - - /** - * Registers a set of PSR-0 directories for a given prefix, - * replacing any others previously set for this prefix. - * - * @param string $prefix The prefix - * @param array|string $paths The PSR-0 base directories - */ - public function set($prefix, $paths) - { - if (!$prefix) { - $this->fallbackDirsPsr0 = (array) $paths; - } else { - $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; - } - } - - /** - * Registers a set of PSR-4 directories for a given namespace, - * replacing any others previously set for this namespace. - * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param array|string $paths The PSR-4 base directories - */ - public function setPsr4($prefix, $paths) { - if (!$prefix) { - $this->fallbackDirsPsr4 = (array) $paths; - } else { - $length = strlen($prefix); - if ('\\' !== $prefix[$length - 1]) { - throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); - } - $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; - } - } - - /** - * Turns on searching the include path for class files. - * - * @param bool $useIncludePath - */ - public function setUseIncludePath($useIncludePath) - { - $this->useIncludePath = $useIncludePath; - } - - /** - * Can be used to check if the autoloader uses the include path to check - * for classes. - * - * @return bool - */ - public function getUseIncludePath() - { - return $this->useIncludePath; - } - - /** - * Registers this instance as an autoloader. - * - * @param bool $prepend Whether to prepend the autoloader or not - */ - public function register($prepend = false) - { - spl_autoload_register(array($this, 'loadClass'), true, $prepend); - } - - /** - * Unregisters this instance as an autoloader. - */ - public function unregister() - { - spl_autoload_unregister(array($this, 'loadClass')); - } - - /** - * Loads the given class or interface. - * - * @param string $class The name of the class - * @return bool|null True if loaded, null otherwise - */ - public function loadClass($class) - { - if ($file = $this->findFile($class)) { - includeFile($file); - - return true; - } - } - - /** - * Finds the path to the file where the class is defined. - * - * @param string $class The name of the class - * - * @return string|false The path if found, false otherwise - */ - public function findFile($class) - { - // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 - if ('\\' == $class[0]) { - $class = substr($class, 1); - } - - // class map lookup - if (isset($this->classMap[$class])) { - return $this->classMap[$class]; - } - - $file = $this->findFileWithExtension($class, '.php'); - - // Search for Hack files if we are running on HHVM - if ($file === null && defined('HHVM_VERSION')) { - $file = $this->findFileWithExtension($class, '.hh'); - } - - if ($file === null) { - // Remember that this class does not exist. - return $this->classMap[$class] = false; - } - - return $file; - } - - private function findFileWithExtension($class, $ext) - { - // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; - - $first = $class[0]; - if (isset($this->prefixLengthsPsr4[$first])) { - foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { - if (0 === strpos($class, $prefix)) { - foreach ($this->prefixDirsPsr4[$prefix] as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { - return $file; - } - } - } - } - } - - // PSR-4 fallback dirs - foreach ($this->fallbackDirsPsr4 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { - return $file; - } - } - - // PSR-0 lookup - if (false !== $pos = strrpos($class, '\\')) { - // namespaced class name - $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) - . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); - } else { - // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; - } - - if (isset($this->prefixesPsr0[$first])) { - foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { - if (0 === strpos($class, $prefix)) { - foreach ($dirs as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - } - } - } - - // PSR-0 fallback dirs - foreach ($this->fallbackDirsPsr0 as $dir) { - if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { - return $file; - } - } - - // PSR-0 include paths. - if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { - return $file; - } - } -} - -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - */ -function includeFile($file) -{ - include $file; -} + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0 class loader + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + public function getPrefixes() + { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-0 base directories + * @param bool $prepend Whether to prepend the directories + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + */ + public function setPsr4($prefix, $paths) { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/app/libs/vendor/composer/autoload_classmap.php b/app/libs/vendor/composer/autoload_classmap.php index b50890d1..7a91153b 100644 --- a/app/libs/vendor/composer/autoload_classmap.php +++ b/app/libs/vendor/composer/autoload_classmap.php @@ -1,9 +1,9 @@ - array($vendorDir . '/react/promise/src'), - 'Guzzle\\Parser' => array($vendorDir . '/guzzle/parser'), - 'Evenement' => array($vendorDir . '/evenement/evenement/src'), -); + array($vendorDir . '/react/promise/src'), + 'Guzzle\\Parser' => array($vendorDir . '/guzzle/parser'), + 'Evenement' => array($vendorDir . '/evenement/evenement/src'), +); diff --git a/app/libs/vendor/composer/autoload_psr4.php b/app/libs/vendor/composer/autoload_psr4.php index a71572c2..ff1bee2e 100644 --- a/app/libs/vendor/composer/autoload_psr4.php +++ b/app/libs/vendor/composer/autoload_psr4.php @@ -1,11 +1,11 @@ - array($vendorDir . '/react/react/src'), - 'League\\Plates\\' => array($vendorDir . '/league/plates/src'), -); + array($vendorDir . '/react/react/src'), + 'League\\Plates\\' => array($vendorDir . '/league/plates/src'), +); diff --git a/app/libs/vendor/composer/autoload_real.php b/app/libs/vendor/composer/autoload_real.php index 4702ed3d..782ce6de 100644 --- a/app/libs/vendor/composer/autoload_real.php +++ b/app/libs/vendor/composer/autoload_real.php @@ -1,58 +1,58 @@ - $path) { - $loader->set($namespace, $path); - } - - $map = require __DIR__ . '/autoload_psr4.php'; - foreach ($map as $namespace => $path) { - $loader->setPsr4($namespace, $path); - } - - $classMap = require __DIR__ . '/autoload_classmap.php'; - if ($classMap) { - $loader->addClassMap($classMap); - } - - $loader->register(true); - - $includeFiles = require __DIR__ . '/autoload_files.php'; - foreach ($includeFiles as $file) { - composerRequire4b9ec2e9f523b34097efe94fbee44622($file); - } - - return $loader; - } -} - -function composerRequire4b9ec2e9f523b34097efe94fbee44622($file) -{ - require $file; -} + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + $includeFiles = require __DIR__ . '/autoload_files.php'; + foreach ($includeFiles as $file) { + composerRequire4b9ec2e9f523b34097efe94fbee44622($file); + } + + return $loader; + } +} + +function composerRequire4b9ec2e9f523b34097efe94fbee44622($file) +{ + require $file; +} diff --git a/app/libs/vendor/composer/installed.json b/app/libs/vendor/composer/installed.json index 2d3363d6..d2a49048 100644 --- a/app/libs/vendor/composer/installed.json +++ b/app/libs/vendor/composer/installed.json @@ -1,253 +1,253 @@ -[ - { - "name": "league/plates", - "version": "1.1.0", - "version_normalized": "1.1.0.0", - "source": { - "type": "git", - "url": "https://github.com/thephpleague/plates.git", - "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/thephpleague/plates/zipball/d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", - "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", - "shasum": "" - }, - "require-dev": { - "mikey179/vfsstream": "v1.2.0", - "mockery/mockery": "dev-master@dev", - "phpunit/phpunit": "3.7.*" - }, - "time": "2014-01-31 23:43:18", - "type": "library", - "installation-source": "dist", - "autoload": { - "psr-4": { - "League\\Plates\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jonathan Reinink", - "email": "jonathan@reinink.ca", - "role": "Developer" - } - ], - "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", - "homepage": "http://platesphp.com", - "keywords": [ - "league", - "package", - "templating" - ] - }, - { - "name": "react/promise", - "version": "v2.0.0", - "version_normalized": "2.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "time": "2013-12-10 15:40:36", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "React\\Promise": "src/" - }, - "files": [ - "src/React/Promise/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@googlemail.com", - "homepage": "http://sorgalla.com", - "role": "maintainer" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP" - }, - { - "name": "guzzle/parser", - "version": "v3.8.1", - "version_normalized": "3.8.1.0", - "target-dir": "Guzzle/Parser", - "source": { - "type": "git", - "url": "https://github.com/guzzle/parser.git", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "time": "2013-10-24 00:04:09", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Guzzle\\Parser": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Interchangeable parsers used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "URI Template", - "cookie", - "http", - "message", - "url" - ] - }, - { - "name": "evenement/evenement", - "version": "v2.0.0", - "version_normalized": "2.0.0.0", - "source": { - "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "time": "2012-11-02 14:49:47", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-0": { - "Evenement": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch", - "homepage": "http://wiedler.ch/igor/" - } - ], - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": [ - "event-dispatcher", - "event-emitter" - ] - }, - { - "name": "react/react", - "version": "v0.4.1", - "version_normalized": "0.4.1.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/react.git", - "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/react/zipball/17044db0ab6a9c145fb1ac40822c5c17d045dc36", - "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36", - "shasum": "" - }, - "require": { - "evenement/evenement": "~2.0", - "guzzle/parser": "~3.0", - "php": ">=5.4.0", - "react/promise": "~2.0" - }, - "replace": { - "react/cache": "self.version", - "react/dns": "self.version", - "react/event-loop": "self.version", - "react/http": "self.version", - "react/http-client": "self.version", - "react/socket": "self.version", - "react/socket-client": "self.version", - "react/stream": "self.version" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "suggest": { - "ext-event": "Allows for use of a more performant event-loop implementation.", - "ext-libev": "Allows for use of a more performant event-loop implementation.", - "ext-libevent": "Allows for use of a more performant event-loop implementation." - }, - "time": "2014-04-13 17:03:14", - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "0.5-dev" - } - }, - "installation-source": "dist", - "autoload": { - "psr-4": { - "React\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Nuclear Reactor written in PHP.", - "keywords": [ - "event-loop", - "reactor" - ] - } -] +[ + { + "name": "league/plates", + "version": "1.1.0", + "version_normalized": "1.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/plates.git", + "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/plates/zipball/d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", + "reference": "d73a08f8094e7d2aac0018ec1c2200ba2ac07a6e", + "shasum": "" + }, + "require-dev": { + "mikey179/vfsstream": "v1.2.0", + "mockery/mockery": "dev-master@dev", + "phpunit/phpunit": "3.7.*" + }, + "time": "2014-01-31 23:43:18", + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-4": { + "League\\Plates\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "role": "Developer" + } + ], + "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", + "homepage": "http://platesphp.com", + "keywords": [ + "league", + "package", + "templating" + ] + }, + { + "name": "react/promise", + "version": "v2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "time": "2013-12-10 15:40:36", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "React\\Promise": "src/" + }, + "files": [ + "src/React/Promise/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com", + "homepage": "http://sorgalla.com", + "role": "maintainer" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP" + }, + { + "name": "guzzle/parser", + "version": "v3.8.1", + "version_normalized": "3.8.1.0", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/guzzle/parser.git", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "time": "2013-10-24 00:04:09", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ] + }, + { + "name": "evenement/evenement", + "version": "v2.0.0", + "version_normalized": "2.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "time": "2012-11-02 14:49:47", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch", + "homepage": "http://wiedler.ch/igor/" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ] + }, + { + "name": "react/react", + "version": "v0.4.1", + "version_normalized": "0.4.1.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/react.git", + "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/react/zipball/17044db0ab6a9c145fb1ac40822c5c17d045dc36", + "reference": "17044db0ab6a9c145fb1ac40822c5c17d045dc36", + "shasum": "" + }, + "require": { + "evenement/evenement": "~2.0", + "guzzle/parser": "~3.0", + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "replace": { + "react/cache": "self.version", + "react/dns": "self.version", + "react/event-loop": "self.version", + "react/http": "self.version", + "react/http-client": "self.version", + "react/socket": "self.version", + "react/socket-client": "self.version", + "react/stream": "self.version" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "suggest": { + "ext-event": "Allows for use of a more performant event-loop implementation.", + "ext-libev": "Allows for use of a more performant event-loop implementation.", + "ext-libevent": "Allows for use of a more performant event-loop implementation." + }, + "time": "2014-04-13 17:03:14", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.5-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "React\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Nuclear Reactor written in PHP.", + "keywords": [ + "event-loop", + "reactor" + ] + } +] diff --git a/app/libs/vendor/evenement/evenement/.gitignore b/app/libs/vendor/evenement/evenement/.gitignore index ae420aab..987e2a25 100644 --- a/app/libs/vendor/evenement/evenement/.gitignore +++ b/app/libs/vendor/evenement/evenement/.gitignore @@ -1,2 +1,2 @@ -composer.lock -vendor +composer.lock +vendor diff --git a/app/libs/vendor/evenement/evenement/.travis.yml b/app/libs/vendor/evenement/evenement/.travis.yml index 16f02630..67e61349 100644 --- a/app/libs/vendor/evenement/evenement/.travis.yml +++ b/app/libs/vendor/evenement/evenement/.travis.yml @@ -1,10 +1,10 @@ -language: php - -php: - - 5.4 - -before_script: - - wget http://getcomposer.org/composer.phar - - php composer.phar install - -script: phpunit --coverage-text +language: php + +php: + - 5.4 + +before_script: + - wget http://getcomposer.org/composer.phar + - php composer.phar install + +script: phpunit --coverage-text diff --git a/app/libs/vendor/evenement/evenement/CHANGELOG.md b/app/libs/vendor/evenement/evenement/CHANGELOG.md index 7b952773..3f299565 100644 --- a/app/libs/vendor/evenement/evenement/CHANGELOG.md +++ b/app/libs/vendor/evenement/evenement/CHANGELOG.md @@ -1,8 +1,8 @@ -CHANGELOG -========= - -* 2.0.0 (2012-11-02) - - * Require PHP >=5.4.0 - * Added EventEmitterTrait - * Removed EventEmitter2 +CHANGELOG +========= + +* 2.0.0 (2012-11-02) + + * Require PHP >=5.4.0 + * Added EventEmitterTrait + * Removed EventEmitter2 diff --git a/app/libs/vendor/evenement/evenement/README.md b/app/libs/vendor/evenement/evenement/README.md index 5641cff8..2b81ccc8 100644 --- a/app/libs/vendor/evenement/evenement/README.md +++ b/app/libs/vendor/evenement/evenement/README.md @@ -1,83 +1,83 @@ -# Événement - -Événement is a very simple event dispatching library for PHP. - -It has the same design goals as [Silex](http://silex-project.org) and -[Pimple](http://pimple-project.org), to empower the user while staying concise -and simple. - -It is very strongly inspired by the EventEmitter API found in -[node.js](http://nodejs.org). - -[![Build Status](https://secure.travis-ci.org/igorw/evenement.png?branch=master)](http://travis-ci.org/igorw/evenement) - -## Fetch - -The recommended way to install Événement is [through composer](http://getcomposer.org). - -Just create a composer.json file for your project: - -```JSON -{ - "require": { - "evenement/evenement": "2.0.*" - } -} -``` - -**Note:** The `2.0.*` version of Événement requires PHP 5.4. If you are -using PHP 5.3, please use the `1.0.*` version: - -```JSON -{ - "require": { - "evenement/evenement": "1.0.*" - } -} -``` - -And run these two commands to install it: - - $ curl -s http://getcomposer.org/installer | php - $ php composer.phar install - -Now you can add the autoloader, and you will have access to the library: - -```php -on('user.created', function (User $user) use ($logger) { - $logger->log(sprintf("User '%s' was created.", $user->getLogin())); -}); -``` - -### Emitting Events - -```php -emit('user.created', array($user)); -``` - -Tests ------ - - $ phpunit - -License -------- -MIT, see LICENSE. +# Événement + +Événement is a very simple event dispatching library for PHP. + +It has the same design goals as [Silex](http://silex-project.org) and +[Pimple](http://pimple-project.org), to empower the user while staying concise +and simple. + +It is very strongly inspired by the EventEmitter API found in +[node.js](http://nodejs.org). + +[![Build Status](https://secure.travis-ci.org/igorw/evenement.png?branch=master)](http://travis-ci.org/igorw/evenement) + +## Fetch + +The recommended way to install Événement is [through composer](http://getcomposer.org). + +Just create a composer.json file for your project: + +```JSON +{ + "require": { + "evenement/evenement": "2.0.*" + } +} +``` + +**Note:** The `2.0.*` version of Événement requires PHP 5.4. If you are +using PHP 5.3, please use the `1.0.*` version: + +```JSON +{ + "require": { + "evenement/evenement": "1.0.*" + } +} +``` + +And run these two commands to install it: + + $ curl -s http://getcomposer.org/installer | php + $ php composer.phar install + +Now you can add the autoloader, and you will have access to the library: + +```php +on('user.created', function (User $user) use ($logger) { + $logger->log(sprintf("User '%s' was created.", $user->getLogin())); +}); +``` + +### Emitting Events + +```php +emit('user.created', array($user)); +``` + +Tests +----- + + $ phpunit + +License +------- +MIT, see LICENSE. diff --git a/app/libs/vendor/evenement/evenement/composer.json b/app/libs/vendor/evenement/evenement/composer.json index 33acae6c..277bb12a 100644 --- a/app/libs/vendor/evenement/evenement/composer.json +++ b/app/libs/vendor/evenement/evenement/composer.json @@ -1,25 +1,25 @@ -{ - "name": "evenement/evenement", - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": ["event-dispatcher", "event-emitter"], - "license": "MIT", - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch" - } - ], - "require": { - "php": ">=5.4.0" - }, - "autoload": { - "psr-0": { - "Evenement": "src" - } - }, - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - } -} +{ + "name": "evenement/evenement", + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": ["event-dispatcher", "event-emitter"], + "license": "MIT", + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch" + } + ], + "require": { + "php": ">=5.4.0" + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + } +} diff --git a/app/libs/vendor/evenement/evenement/phpunit.xml.dist b/app/libs/vendor/evenement/evenement/phpunit.xml.dist index f4f4778d..8be06518 100644 --- a/app/libs/vendor/evenement/evenement/phpunit.xml.dist +++ b/app/libs/vendor/evenement/evenement/phpunit.xml.dist @@ -1,25 +1,25 @@ - - - - - - ./tests/Evenement/ - - - - - - ./src/ - - - + + + + + + ./tests/Evenement/ + + + + + + ./src/ + + + diff --git a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitter.php b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitter.php index 1d904048..0ef51fc2 100644 --- a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitter.php +++ b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitter.php @@ -1,17 +1,17 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Evenement; - -class EventEmitter implements EventEmitterInterface -{ - use EventEmitterTrait; -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement; + +class EventEmitter implements EventEmitterInterface +{ + use EventEmitterTrait; +} diff --git a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php index 21bf65d7..9b0b136a 100644 --- a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php +++ b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterInterface.php @@ -1,22 +1,22 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Evenement; - -interface EventEmitterInterface -{ - public function on($event, callable $listener); - public function once($event, callable $listener); - public function removeListener($event, callable $listener); - public function removeAllListeners($event = null); - public function listeners($event); - public function emit($event, array $arguments = []); -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement; + +interface EventEmitterInterface +{ + public function on($event, callable $listener); + public function once($event, callable $listener); + public function removeListener($event, callable $listener); + public function removeAllListeners($event = null); + public function listeners($event); + public function emit($event, array $arguments = []); +} diff --git a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php index 150ac319..5f427172 100644 --- a/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php +++ b/app/libs/vendor/evenement/evenement/src/Evenement/EventEmitterTrait.php @@ -1,67 +1,67 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Evenement; - -trait EventEmitterTrait -{ - protected $listeners = []; - - public function on($event, callable $listener) - { - if (!isset($this->listeners[$event])) { - $this->listeners[$event] = []; - } - - $this->listeners[$event][] = $listener; - } - - public function once($event, callable $listener) - { - $onceListener = function () use (&$onceListener, $event, $listener) { - $this->removeListener($event, $onceListener); - - call_user_func_array($listener, func_get_args()); - }; - - $this->on($event, $onceListener); - } - - public function removeListener($event, callable $listener) - { - if (isset($this->listeners[$event])) { - if (false !== $index = array_search($listener, $this->listeners[$event], true)) { - unset($this->listeners[$event][$index]); - } - } - } - - public function removeAllListeners($event = null) - { - if ($event !== null) { - unset($this->listeners[$event]); - } else { - $this->listeners = []; - } - } - - public function listeners($event) - { - return isset($this->listeners[$event]) ? $this->listeners[$event] : []; - } - - public function emit($event, array $arguments = []) - { - foreach ($this->listeners($event) as $listener) { - call_user_func_array($listener, $arguments); - } - } -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement; + +trait EventEmitterTrait +{ + protected $listeners = []; + + public function on($event, callable $listener) + { + if (!isset($this->listeners[$event])) { + $this->listeners[$event] = []; + } + + $this->listeners[$event][] = $listener; + } + + public function once($event, callable $listener) + { + $onceListener = function () use (&$onceListener, $event, $listener) { + $this->removeListener($event, $onceListener); + + call_user_func_array($listener, func_get_args()); + }; + + $this->on($event, $onceListener); + } + + public function removeListener($event, callable $listener) + { + if (isset($this->listeners[$event])) { + if (false !== $index = array_search($listener, $this->listeners[$event], true)) { + unset($this->listeners[$event][$index]); + } + } + } + + public function removeAllListeners($event = null) + { + if ($event !== null) { + unset($this->listeners[$event]); + } else { + $this->listeners = []; + } + } + + public function listeners($event) + { + return isset($this->listeners[$event]) ? $this->listeners[$event] : []; + } + + public function emit($event, array $arguments = []) + { + foreach ($this->listeners($event) as $listener) { + call_user_func_array($listener, $arguments); + } + } +} diff --git a/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php b/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php index 2007352c..7eeaa3d8 100644 --- a/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php +++ b/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/EventEmitterTest.php @@ -1,235 +1,235 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Evenement\Tests; - -use Evenement\EventEmitter; - -class EventEmitterTest extends \PHPUnit_Framework_TestCase -{ - private $emitter; - - public function setUp() - { - $this->emitter = new EventEmitter(); - } - - public function testAddListenerWithLambda() - { - $this->emitter->on('foo', function () {}); - } - - public function testAddListenerWithMethod() - { - $listener = new Listener(); - $this->emitter->on('foo', [$listener, 'onFoo']); - } - - public function testAddListenerWithStaticMethod() - { - $this->emitter->on('bar', ['Evenement\Tests\Listener', 'onBar']); - } - - public function testAddListenerWithInvalidListener() - { - try { - $this->emitter->on('foo', 'not a callable'); - $this->fail(); - } catch (\Exception $e) { - } - } - - public function testOnce() - { - $listenerCalled = 0; - - $this->emitter->once('foo', function () use (&$listenerCalled) { - $listenerCalled++; - }); - - $this->assertSame(0, $listenerCalled); - - $this->emitter->emit('foo'); - - $this->assertSame(1, $listenerCalled); - - $this->emitter->emit('foo'); - - $this->assertSame(1, $listenerCalled); - } - - public function testOnceWithArguments() - { - $capturedArgs = []; - - $this->emitter->once('foo', function ($a, $b) use (&$capturedArgs) { - $capturedArgs = array($a, $b); - }); - - $this->emitter->emit('foo', array('a', 'b')); - - $this->assertSame(array('a', 'b'), $capturedArgs); - } - - public function testEmitWithoutArguments() - { - $listenerCalled = false; - - $this->emitter->on('foo', function () use (&$listenerCalled) { - $listenerCalled = true; - }); - - $this->assertSame(false, $listenerCalled); - $this->emitter->emit('foo'); - $this->assertSame(true, $listenerCalled); - } - - public function testEmitWithOneArgument() - { - $test = $this; - - $listenerCalled = false; - - $this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) { - $listenerCalled = true; - - $test->assertSame('bar', $value); - }); - - $this->assertSame(false, $listenerCalled); - $this->emitter->emit('foo', ['bar']); - $this->assertSame(true, $listenerCalled); - } - - public function testEmitWithTwoArguments() - { - $test = $this; - - $listenerCalled = false; - - $this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) { - $listenerCalled = true; - - $test->assertSame('bar', $arg1); - $test->assertSame('baz', $arg2); - }); - - $this->assertSame(false, $listenerCalled); - $this->emitter->emit('foo', ['bar', 'baz']); - $this->assertSame(true, $listenerCalled); - } - - public function testEmitWithNoListeners() - { - $this->emitter->emit('foo'); - $this->emitter->emit('foo', ['bar']); - $this->emitter->emit('foo', ['bar', 'baz']); - } - - public function testEmitWithTwoListeners() - { - $listenersCalled = 0; - - $this->emitter->on('foo', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->emitter->on('foo', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->assertSame(2, $listenersCalled); - } - - public function testRemoveListenerMatching() - { - $listenersCalled = 0; - - $listener = function () use (&$listenersCalled) { - $listenersCalled++; - }; - - $this->emitter->on('foo', $listener); - $this->emitter->removeListener('foo', $listener); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->assertSame(0, $listenersCalled); - } - - public function testRemoveListenerNotMatching() - { - $listenersCalled = 0; - - $listener = function () use (&$listenersCalled) { - $listenersCalled++; - }; - - $this->emitter->on('foo', $listener); - $this->emitter->removeListener('bar', $listener); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->assertSame(1, $listenersCalled); - } - - public function testRemoveAllListenersMatching() - { - $listenersCalled = 0; - - $this->emitter->on('foo', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->emitter->removeAllListeners('foo'); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->assertSame(0, $listenersCalled); - } - - public function testRemoveAllListenersNotMatching() - { - $listenersCalled = 0; - - $this->emitter->on('foo', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->emitter->removeAllListeners('bar'); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->assertSame(1, $listenersCalled); - } - - public function testRemoveAllListenersWithoutArguments() - { - $listenersCalled = 0; - - $this->emitter->on('foo', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->emitter->on('bar', function () use (&$listenersCalled) { - $listenersCalled++; - }); - - $this->emitter->removeAllListeners(); - - $this->assertSame(0, $listenersCalled); - $this->emitter->emit('foo'); - $this->emitter->emit('bar'); - $this->assertSame(0, $listenersCalled); - } -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement\Tests; + +use Evenement\EventEmitter; + +class EventEmitterTest extends \PHPUnit_Framework_TestCase +{ + private $emitter; + + public function setUp() + { + $this->emitter = new EventEmitter(); + } + + public function testAddListenerWithLambda() + { + $this->emitter->on('foo', function () {}); + } + + public function testAddListenerWithMethod() + { + $listener = new Listener(); + $this->emitter->on('foo', [$listener, 'onFoo']); + } + + public function testAddListenerWithStaticMethod() + { + $this->emitter->on('bar', ['Evenement\Tests\Listener', 'onBar']); + } + + public function testAddListenerWithInvalidListener() + { + try { + $this->emitter->on('foo', 'not a callable'); + $this->fail(); + } catch (\Exception $e) { + } + } + + public function testOnce() + { + $listenerCalled = 0; + + $this->emitter->once('foo', function () use (&$listenerCalled) { + $listenerCalled++; + }); + + $this->assertSame(0, $listenerCalled); + + $this->emitter->emit('foo'); + + $this->assertSame(1, $listenerCalled); + + $this->emitter->emit('foo'); + + $this->assertSame(1, $listenerCalled); + } + + public function testOnceWithArguments() + { + $capturedArgs = []; + + $this->emitter->once('foo', function ($a, $b) use (&$capturedArgs) { + $capturedArgs = array($a, $b); + }); + + $this->emitter->emit('foo', array('a', 'b')); + + $this->assertSame(array('a', 'b'), $capturedArgs); + } + + public function testEmitWithoutArguments() + { + $listenerCalled = false; + + $this->emitter->on('foo', function () use (&$listenerCalled) { + $listenerCalled = true; + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo'); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithOneArgument() + { + $test = $this; + + $listenerCalled = false; + + $this->emitter->on('foo', function ($value) use (&$listenerCalled, $test) { + $listenerCalled = true; + + $test->assertSame('bar', $value); + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo', ['bar']); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithTwoArguments() + { + $test = $this; + + $listenerCalled = false; + + $this->emitter->on('foo', function ($arg1, $arg2) use (&$listenerCalled, $test) { + $listenerCalled = true; + + $test->assertSame('bar', $arg1); + $test->assertSame('baz', $arg2); + }); + + $this->assertSame(false, $listenerCalled); + $this->emitter->emit('foo', ['bar', 'baz']); + $this->assertSame(true, $listenerCalled); + } + + public function testEmitWithNoListeners() + { + $this->emitter->emit('foo'); + $this->emitter->emit('foo', ['bar']); + $this->emitter->emit('foo', ['bar', 'baz']); + } + + public function testEmitWithTwoListeners() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(2, $listenersCalled); + } + + public function testRemoveListenerMatching() + { + $listenersCalled = 0; + + $listener = function () use (&$listenersCalled) { + $listenersCalled++; + }; + + $this->emitter->on('foo', $listener); + $this->emitter->removeListener('foo', $listener); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(0, $listenersCalled); + } + + public function testRemoveListenerNotMatching() + { + $listenersCalled = 0; + + $listener = function () use (&$listenersCalled) { + $listenersCalled++; + }; + + $this->emitter->on('foo', $listener); + $this->emitter->removeListener('bar', $listener); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(1, $listenersCalled); + } + + public function testRemoveAllListenersMatching() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners('foo'); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(0, $listenersCalled); + } + + public function testRemoveAllListenersNotMatching() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners('bar'); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->assertSame(1, $listenersCalled); + } + + public function testRemoveAllListenersWithoutArguments() + { + $listenersCalled = 0; + + $this->emitter->on('foo', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->on('bar', function () use (&$listenersCalled) { + $listenersCalled++; + }); + + $this->emitter->removeAllListeners(); + + $this->assertSame(0, $listenersCalled); + $this->emitter->emit('foo'); + $this->emitter->emit('bar'); + $this->assertSame(0, $listenersCalled); + } +} diff --git a/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php b/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php index 7711c97e..72d3375f 100644 --- a/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php +++ b/app/libs/vendor/evenement/evenement/tests/Evenement/Tests/Listener.php @@ -1,23 +1,23 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Evenement\Tests; - -class Listener -{ - public function onFoo() - { - } - - public static function onBar() - { - } -} + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Evenement\Tests; + +class Listener +{ + public function onFoo() + { + } + + public static function onBar() + { + } +} diff --git a/app/libs/vendor/evenement/evenement/tests/bootstrap.php b/app/libs/vendor/evenement/evenement/tests/bootstrap.php index 794c5623..eed375d9 100644 --- a/app/libs/vendor/evenement/evenement/tests/bootstrap.php +++ b/app/libs/vendor/evenement/evenement/tests/bootstrap.php @@ -1,13 +1,13 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -$loader = require __DIR__.'/../vendor/autoload.php'; -$loader->add('Evenement\Tests', __DIR__); + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$loader = require __DIR__.'/../vendor/autoload.php'; +$loader->add('Evenement\Tests', __DIR__); diff --git a/app/libs/vendor/getid3/audioinfo.class.php b/app/libs/vendor/getid3/audioinfo.class.php index 2063e3fc..c7bec567 100644 --- a/app/libs/vendor/getid3/audioinfo.class.php +++ b/app/libs/vendor/getid3/audioinfo.class.php @@ -1,316 +1,316 @@ -Info('file.flac'); | -// +----------------------------------------------------------------------+ -// | Authors: Allan Hansen | -// +----------------------------------------------------------------------+ -// - - - -/** -* getID3() settings -*/ - -require_once('getid3/getid3.php'); - - - - -/** -* Class for extracting information from audio files with getID3(). -*/ - -class AudioInfo { - - /** - * Private variables - */ - var $result = NULL; - var $info = NULL; - - - - - /** - * Constructor - */ - - function AudioInfo() { - - // Initialize getID3 engine - $this->getID3 = new getID3; - $this->getID3->option_md5_data = true; - $this->getID3->option_md5_data_source = true; - $this->getID3->encoding = 'UTF-8'; - } - - - - - /** - * Extract information - only public function - * - * @access public - * @param string file Audio file to extract info from. - */ - - function Info($file) { - - // Analyze file - $this->info = $this->getID3->analyze($file); - - // Exit here on error - if (isset($this->info['error'])) { - return array ('error' => $this->info['error']); - } - - // Init wrapper object - $this->result = array(); - $this->result['format_name'] = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'/'.(isset($this->info['audio']['dataformat']) ? $this->info['audio']['dataformat'] : '').(isset($this->info['video']['dataformat']) ? '/'.$this->info['video']['dataformat'] : ''); - $this->result['encoder_version'] = (isset($this->info['audio']['encoder']) ? $this->info['audio']['encoder'] : ''); - $this->result['encoder_options'] = (isset($this->info['audio']['encoder_options']) ? $this->info['audio']['encoder_options'] : ''); - $this->result['bitrate_mode'] = (isset($this->info['audio']['bitrate_mode']) ? $this->info['audio']['bitrate_mode'] : ''); - $this->result['channels'] = (isset($this->info['audio']['channels']) ? $this->info['audio']['channels'] : ''); - $this->result['sample_rate'] = (isset($this->info['audio']['sample_rate']) ? $this->info['audio']['sample_rate'] : ''); - $this->result['bits_per_sample'] = (isset($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : ''); - $this->result['playing_time'] = (isset($this->info['playtime_seconds']) ? $this->info['playtime_seconds'] : ''); - $this->result['avg_bit_rate'] = (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : ''); - $this->result['tags'] = (isset($this->info['tags']) ? $this->info['tags'] : ''); - $this->result['comments'] = (isset($this->info['comments']) ? $this->info['comments'] : ''); - $this->result['warning'] = (isset($this->info['warning']) ? $this->info['warning'] : ''); - $this->result['md5'] = (isset($this->info['md5_data']) ? $this->info['md5_data'] : ''); - - // Post getID3() data handling based on file format - $method = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'Info'; - if ($method && method_exists($this, $method)) { - $this->$method(); - } - - return $this->result; - } - - - - - /** - * post-getID3() data handling for AAC files. - * - * @access private - */ - - function aacInfo() { - $this->result['format_name'] = 'AAC'; - } - - - - - /** - * post-getID3() data handling for Wave files. - * - * @access private - */ - - function riffInfo() { - if ($this->info['audio']['dataformat'] == 'wav') { - - $this->result['format_name'] = 'Wave'; - - } elseif (preg_match('#^mp[1-3]$#', $this->info['audio']['dataformat'])) { - - $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); - - } else { - - $this->result['format_name'] = 'riff/'.$this->info['audio']['dataformat']; - - } - } - - - - - /** - * * post-getID3() data handling for FLAC files. - * - * @access private - */ - - function flacInfo() { - $this->result['format_name'] = 'FLAC'; - } - - - - - - /** - * post-getID3() data handling for Monkey's Audio files. - * - * @access private - */ - - function macInfo() { - $this->result['format_name'] = 'Monkey\'s Audio'; - } - - - - - - /** - * post-getID3() data handling for Lossless Audio files. - * - * @access private - */ - - function laInfo() { - $this->result['format_name'] = 'La'; - } - - - - - - /** - * post-getID3() data handling for Ogg Vorbis files. - * - * @access private - */ - - function oggInfo() { - if ($this->info['audio']['dataformat'] == 'vorbis') { - - $this->result['format_name'] = 'Ogg Vorbis'; - - } else if ($this->info['audio']['dataformat'] == 'flac') { - - $this->result['format_name'] = 'Ogg FLAC'; - - } else if ($this->info['audio']['dataformat'] == 'speex') { - - $this->result['format_name'] = 'Ogg Speex'; - - } else { - - $this->result['format_name'] = 'Ogg '.$this->info['audio']['dataformat']; - - } - } - - - - - /** - * post-getID3() data handling for Musepack files. - * - * @access private - */ - - function mpcInfo() { - $this->result['format_name'] = 'Musepack'; - } - - - - - /** - * post-getID3() data handling for MPEG files. - * - * @access private - */ - - function mp3Info() { - $this->result['format_name'] = 'MP3'; - } - - - - - /** - * post-getID3() data handling for MPEG files. - * - * @access private - */ - - function mp2Info() { - $this->result['format_name'] = 'MP2'; - } - - - - - - /** - * post-getID3() data handling for MPEG files. - * - * @access private - */ - - function mp1Info() { - $this->result['format_name'] = 'MP1'; - } - - - - - /** - * post-getID3() data handling for WMA files. - * - * @access private - */ - - function asfInfo() { - $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); - } - - - - /** - * post-getID3() data handling for Real files. - * - * @access private - */ - - function realInfo() { - $this->result['format_name'] = 'Real'; - } - - - - - - /** - * post-getID3() data handling for VQF files. - * - * @access private - */ - - function vqfInfo() { - $this->result['format_name'] = 'VQF'; - } - -} +Info('file.flac'); | +// +----------------------------------------------------------------------+ +// | Authors: Allan Hansen | +// +----------------------------------------------------------------------+ +// + + + +/** +* getID3() settings +*/ + +require_once('getid3/getid3.php'); + + + + +/** +* Class for extracting information from audio files with getID3(). +*/ + +class AudioInfo { + + /** + * Private variables + */ + var $result = NULL; + var $info = NULL; + + + + + /** + * Constructor + */ + + function AudioInfo() { + + // Initialize getID3 engine + $this->getID3 = new getID3; + $this->getID3->option_md5_data = true; + $this->getID3->option_md5_data_source = true; + $this->getID3->encoding = 'UTF-8'; + } + + + + + /** + * Extract information - only public function + * + * @access public + * @param string file Audio file to extract info from. + */ + + function Info($file) { + + // Analyze file + $this->info = $this->getID3->analyze($file); + + // Exit here on error + if (isset($this->info['error'])) { + return array ('error' => $this->info['error']); + } + + // Init wrapper object + $this->result = array(); + $this->result['format_name'] = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'/'.(isset($this->info['audio']['dataformat']) ? $this->info['audio']['dataformat'] : '').(isset($this->info['video']['dataformat']) ? '/'.$this->info['video']['dataformat'] : ''); + $this->result['encoder_version'] = (isset($this->info['audio']['encoder']) ? $this->info['audio']['encoder'] : ''); + $this->result['encoder_options'] = (isset($this->info['audio']['encoder_options']) ? $this->info['audio']['encoder_options'] : ''); + $this->result['bitrate_mode'] = (isset($this->info['audio']['bitrate_mode']) ? $this->info['audio']['bitrate_mode'] : ''); + $this->result['channels'] = (isset($this->info['audio']['channels']) ? $this->info['audio']['channels'] : ''); + $this->result['sample_rate'] = (isset($this->info['audio']['sample_rate']) ? $this->info['audio']['sample_rate'] : ''); + $this->result['bits_per_sample'] = (isset($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : ''); + $this->result['playing_time'] = (isset($this->info['playtime_seconds']) ? $this->info['playtime_seconds'] : ''); + $this->result['avg_bit_rate'] = (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : ''); + $this->result['tags'] = (isset($this->info['tags']) ? $this->info['tags'] : ''); + $this->result['comments'] = (isset($this->info['comments']) ? $this->info['comments'] : ''); + $this->result['warning'] = (isset($this->info['warning']) ? $this->info['warning'] : ''); + $this->result['md5'] = (isset($this->info['md5_data']) ? $this->info['md5_data'] : ''); + + // Post getID3() data handling based on file format + $method = (isset($this->info['fileformat']) ? $this->info['fileformat'] : '').'Info'; + if ($method && method_exists($this, $method)) { + $this->$method(); + } + + return $this->result; + } + + + + + /** + * post-getID3() data handling for AAC files. + * + * @access private + */ + + function aacInfo() { + $this->result['format_name'] = 'AAC'; + } + + + + + /** + * post-getID3() data handling for Wave files. + * + * @access private + */ + + function riffInfo() { + if ($this->info['audio']['dataformat'] == 'wav') { + + $this->result['format_name'] = 'Wave'; + + } elseif (preg_match('#^mp[1-3]$#', $this->info['audio']['dataformat'])) { + + $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); + + } else { + + $this->result['format_name'] = 'riff/'.$this->info['audio']['dataformat']; + + } + } + + + + + /** + * * post-getID3() data handling for FLAC files. + * + * @access private + */ + + function flacInfo() { + $this->result['format_name'] = 'FLAC'; + } + + + + + + /** + * post-getID3() data handling for Monkey's Audio files. + * + * @access private + */ + + function macInfo() { + $this->result['format_name'] = 'Monkey\'s Audio'; + } + + + + + + /** + * post-getID3() data handling for Lossless Audio files. + * + * @access private + */ + + function laInfo() { + $this->result['format_name'] = 'La'; + } + + + + + + /** + * post-getID3() data handling for Ogg Vorbis files. + * + * @access private + */ + + function oggInfo() { + if ($this->info['audio']['dataformat'] == 'vorbis') { + + $this->result['format_name'] = 'Ogg Vorbis'; + + } else if ($this->info['audio']['dataformat'] == 'flac') { + + $this->result['format_name'] = 'Ogg FLAC'; + + } else if ($this->info['audio']['dataformat'] == 'speex') { + + $this->result['format_name'] = 'Ogg Speex'; + + } else { + + $this->result['format_name'] = 'Ogg '.$this->info['audio']['dataformat']; + + } + } + + + + + /** + * post-getID3() data handling for Musepack files. + * + * @access private + */ + + function mpcInfo() { + $this->result['format_name'] = 'Musepack'; + } + + + + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + */ + + function mp3Info() { + $this->result['format_name'] = 'MP3'; + } + + + + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + */ + + function mp2Info() { + $this->result['format_name'] = 'MP2'; + } + + + + + + /** + * post-getID3() data handling for MPEG files. + * + * @access private + */ + + function mp1Info() { + $this->result['format_name'] = 'MP1'; + } + + + + + /** + * post-getID3() data handling for WMA files. + * + * @access private + */ + + function asfInfo() { + $this->result['format_name'] = strtoupper($this->info['audio']['dataformat']); + } + + + + /** + * post-getID3() data handling for Real files. + * + * @access private + */ + + function realInfo() { + $this->result['format_name'] = 'Real'; + } + + + + + + /** + * post-getID3() data handling for VQF files. + * + * @access private + */ + + function vqfInfo() { + $this->result['format_name'] = 'VQF'; + } + +} diff --git a/app/libs/vendor/getid3/extension.cache.dbm.php b/app/libs/vendor/getid3/extension.cache.dbm.php index 5f5e1bd6..7eea33c0 100644 --- a/app/libs/vendor/getid3/extension.cache.dbm.php +++ b/app/libs/vendor/getid3/extension.cache.dbm.php @@ -1,208 +1,208 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// // -// extension.cache.dbm.php - part of getID3() // -// Please see readme.txt for more information // -// /// -///////////////////////////////////////////////////////////////// -// // -// This extension written by Allan Hansen // -// /// -///////////////////////////////////////////////////////////////// - - -/** -* This is a caching extension for getID3(). It works the exact same -* way as the getID3 class, but return cached information very fast -* -* Example: -* -* Normal getID3 usage (example): -* -* require_once 'getid3/getid3.php'; -* $getID3 = new getID3; -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* getID3_cached usage: -* -* require_once 'getid3/getid3.php'; -* require_once 'getid3/getid3/extension.cache.dbm.php'; -* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm', -* '/tmp/getid3_cache.lock'); -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* -* Supported Cache Types -* -* SQL Databases: (use extension.cache.mysql) -* -* cache_type cache_options -* ------------------------------------------------------------------- -* mysql host, database, username, password -* -* -* DBM-Style Databases: (this extension) -* -* cache_type cache_options -* ------------------------------------------------------------------- -* gdbm dbm_filename, lock_filename -* ndbm dbm_filename, lock_filename -* db2 dbm_filename, lock_filename -* db3 dbm_filename, lock_filename -* db4 dbm_filename, lock_filename (PHP5 required) -* -* PHP must have write access to both dbm_filename and lock_filename. -* -* -* Recommended Cache Types -* -* Infrequent updates, many reads any DBM -* Frequent updates mysql -*/ - - -class getID3_cached_dbm extends getID3 -{ - - // public: constructor - see top of this file for cache type and cache_options - public function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) { - - // Check for dba extension - if (!extension_loaded('dba')) { - throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.'); - } - - // Check for specific dba driver - if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) { - throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); - } - - // Create lock file if needed - if (!file_exists($lock_filename)) { - if (!touch($lock_filename)) { - throw new Exception('failed to create lock file: '.$lock_filename); - } - } - - // Open lock file for writing - if (!is_writeable($lock_filename)) { - throw new Exception('lock file: '.$lock_filename.' is not writable'); - } - $this->lock = fopen($lock_filename, 'w'); - - // Acquire exclusive write lock to lock file - flock($this->lock, LOCK_EX); - - // Create dbm-file if needed - if (!file_exists($dbm_filename)) { - if (!touch($dbm_filename)) { - throw new Exception('failed to create dbm file: '.$dbm_filename); - } - } - - // Try to open dbm file for writing - $this->dba = dba_open($dbm_filename, 'w', $cache_type); - if (!$this->dba) { - - // Failed - create new dbm file - $this->dba = dba_open($dbm_filename, 'n', $cache_type); - - if (!$this->dba) { - throw new Exception('failed to create dbm file: '.$dbm_filename); - } - - // Insert getID3 version number - dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); - } - - // Init misc values - $this->cache_type = $cache_type; - $this->dbm_filename = $dbm_filename; - - // Register destructor - register_shutdown_function(array($this, '__destruct')); - - // Check version number and clear cache if changed - if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { - $this->clear_cache(); - } - - parent::getID3(); - } - - - - // public: destructor - public function __destruct() { - - // Close dbm file - dba_close($this->dba); - - // Release exclusive lock - flock($this->lock, LOCK_UN); - - // Close lock file - fclose($this->lock); - } - - - - // public: clear cache - public function clear_cache() { - - // Close dbm file - dba_close($this->dba); - - // Create new dbm file - $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); - - if (!$this->dba) { - throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename); - } - - // Insert getID3 version number - dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); - - // Re-register shutdown function - register_shutdown_function(array($this, '__destruct')); - } - - - - // public: analyze file - public function analyze($filename) { - - if (file_exists($filename)) { - - // Calc key filename::mod_time::size - should be unique - $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); - - // Loopup key - $result = dba_fetch($key, $this->dba); - - // Hit - if ($result !== false) { - return unserialize($result); - } - } - - // Miss - $result = parent::analyze($filename); - - // Save result - if (file_exists($filename)) { - dba_insert($key, serialize($result), $this->dba); - } - - return $result; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// extension.cache.dbm.php - part of getID3() // +// Please see readme.txt for more information // +// /// +///////////////////////////////////////////////////////////////// +// // +// This extension written by Allan Hansen // +// /// +///////////////////////////////////////////////////////////////// + + +/** +* This is a caching extension for getID3(). It works the exact same +* way as the getID3 class, but return cached information very fast +* +* Example: +* +* Normal getID3 usage (example): +* +* require_once 'getid3/getid3.php'; +* $getID3 = new getID3; +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* getID3_cached usage: +* +* require_once 'getid3/getid3.php'; +* require_once 'getid3/getid3/extension.cache.dbm.php'; +* $getID3 = new getID3_cached('db3', '/tmp/getid3_cache.dbm', +* '/tmp/getid3_cache.lock'); +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* +* Supported Cache Types +* +* SQL Databases: (use extension.cache.mysql) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* mysql host, database, username, password +* +* +* DBM-Style Databases: (this extension) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* gdbm dbm_filename, lock_filename +* ndbm dbm_filename, lock_filename +* db2 dbm_filename, lock_filename +* db3 dbm_filename, lock_filename +* db4 dbm_filename, lock_filename (PHP5 required) +* +* PHP must have write access to both dbm_filename and lock_filename. +* +* +* Recommended Cache Types +* +* Infrequent updates, many reads any DBM +* Frequent updates mysql +*/ + + +class getID3_cached_dbm extends getID3 +{ + + // public: constructor - see top of this file for cache type and cache_options + public function getID3_cached_dbm($cache_type, $dbm_filename, $lock_filename) { + + // Check for dba extension + if (!extension_loaded('dba')) { + throw new Exception('PHP is not compiled with dba support, required to use DBM style cache.'); + } + + // Check for specific dba driver + if (!function_exists('dba_handlers') || !in_array($cache_type, dba_handlers())) { + throw new Exception('PHP is not compiled --with '.$cache_type.' support, required to use DBM style cache.'); + } + + // Create lock file if needed + if (!file_exists($lock_filename)) { + if (!touch($lock_filename)) { + throw new Exception('failed to create lock file: '.$lock_filename); + } + } + + // Open lock file for writing + if (!is_writeable($lock_filename)) { + throw new Exception('lock file: '.$lock_filename.' is not writable'); + } + $this->lock = fopen($lock_filename, 'w'); + + // Acquire exclusive write lock to lock file + flock($this->lock, LOCK_EX); + + // Create dbm-file if needed + if (!file_exists($dbm_filename)) { + if (!touch($dbm_filename)) { + throw new Exception('failed to create dbm file: '.$dbm_filename); + } + } + + // Try to open dbm file for writing + $this->dba = dba_open($dbm_filename, 'w', $cache_type); + if (!$this->dba) { + + // Failed - create new dbm file + $this->dba = dba_open($dbm_filename, 'n', $cache_type); + + if (!$this->dba) { + throw new Exception('failed to create dbm file: '.$dbm_filename); + } + + // Insert getID3 version number + dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); + } + + // Init misc values + $this->cache_type = $cache_type; + $this->dbm_filename = $dbm_filename; + + // Register destructor + register_shutdown_function(array($this, '__destruct')); + + // Check version number and clear cache if changed + if (dba_fetch(getID3::VERSION, $this->dba) != getID3::VERSION) { + $this->clear_cache(); + } + + parent::getID3(); + } + + + + // public: destructor + public function __destruct() { + + // Close dbm file + dba_close($this->dba); + + // Release exclusive lock + flock($this->lock, LOCK_UN); + + // Close lock file + fclose($this->lock); + } + + + + // public: clear cache + public function clear_cache() { + + // Close dbm file + dba_close($this->dba); + + // Create new dbm file + $this->dba = dba_open($this->dbm_filename, 'n', $this->cache_type); + + if (!$this->dba) { + throw new Exception('failed to clear cache/recreate dbm file: '.$this->dbm_filename); + } + + // Insert getID3 version number + dba_insert(getID3::VERSION, getID3::VERSION, $this->dba); + + // Re-register shutdown function + register_shutdown_function(array($this, '__destruct')); + } + + + + // public: analyze file + public function analyze($filename) { + + if (file_exists($filename)) { + + // Calc key filename::mod_time::size - should be unique + $key = $filename.'::'.filemtime($filename).'::'.filesize($filename); + + // Loopup key + $result = dba_fetch($key, $this->dba); + + // Hit + if ($result !== false) { + return unserialize($result); + } + } + + // Miss + $result = parent::analyze($filename); + + // Save result + if (file_exists($filename)) { + dba_insert($key, serialize($result), $this->dba); + } + + return $result; + } + +} diff --git a/app/libs/vendor/getid3/extension.cache.mysql.php b/app/libs/vendor/getid3/extension.cache.mysql.php index d43051ae..771c8b03 100644 --- a/app/libs/vendor/getid3/extension.cache.mysql.php +++ b/app/libs/vendor/getid3/extension.cache.mysql.php @@ -1,171 +1,171 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// // -// extension.cache.mysql.php - part of getID3() // -// Please see readme.txt for more information // -// /// -///////////////////////////////////////////////////////////////// -// // -// This extension written by Allan Hansen // -// Table name mod by Carlo Capocasa // -// /// -///////////////////////////////////////////////////////////////// - - -/** -* This is a caching extension for getID3(). It works the exact same -* way as the getID3 class, but return cached information very fast -* -* Example: (see also demo.cache.mysql.php in /demo/) -* -* Normal getID3 usage (example): -* -* require_once 'getid3/getid3.php'; -* $getID3 = new getID3; -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* getID3_cached usage: -* -* require_once 'getid3/getid3.php'; -* require_once 'getid3/getid3/extension.cache.mysql.php'; -* // 5th parameter (tablename) is optional, default is 'getid3_cache' -* $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename'); -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* -* Supported Cache Types (this extension) -* -* SQL Databases: -* -* cache_type cache_options -* ------------------------------------------------------------------- -* mysql host, database, username, password -* -* -* DBM-Style Databases: (use extension.cache.dbm) -* -* cache_type cache_options -* ------------------------------------------------------------------- -* gdbm dbm_filename, lock_filename -* ndbm dbm_filename, lock_filename -* db2 dbm_filename, lock_filename -* db3 dbm_filename, lock_filename -* db4 dbm_filename, lock_filename (PHP5 required) -* -* PHP must have write access to both dbm_filename and lock_filename. -* -* -* Recommended Cache Types -* -* Infrequent updates, many reads any DBM -* Frequent updates mysql -*/ - - -class getID3_cached_mysql extends getID3 -{ - - // private vars - private $cursor; - private $connection; - - - // public: constructor - see top of this file for cache type and cache_options - public function getID3_cached_mysql($host, $database, $username, $password, $table='getid3_cache') { - - // Check for mysql support - if (!function_exists('mysql_pconnect')) { - throw new Exception('PHP not compiled with mysql support.'); - } - - // Connect to database - $this->connection = mysql_pconnect($host, $username, $password); - if (!$this->connection) { - throw new Exception('mysql_pconnect() failed - check permissions and spelling.'); - } - - // Select database - if (!mysql_select_db($database, $this->connection)) { - throw new Exception('Cannot use database '.$database); - } - - // Set table - $this->table = $table; - - // Create cache table if not exists - $this->create_table(); - - // Check version number and clear cache if changed - $version = ''; - if ($this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string(getID3::VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) { - list($version) = mysql_fetch_array($this->cursor); - } - if ($version != getID3::VERSION) { - $this->clear_cache(); - } - - parent::getID3(); - } - - - - // public: clear cache - public function clear_cache() { - - $this->cursor = mysql_query("DELETE FROM `".mysql_real_escape_string($this->table)."`", $this->connection); - $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` VALUES ('".getID3::VERSION."', -1, -1, -1, '".getID3::VERSION."')", $this->connection); - } - - - - // public: analyze file - public function analyze($filename) { - - if (file_exists($filename)) { - - // Short-hands - $filetime = filemtime($filename); - $filesize = filesize($filename); - - // Lookup file - $this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection); - if (mysql_num_rows($this->cursor) > 0) { - // Hit - list($result) = mysql_fetch_array($this->cursor); - return unserialize(base64_decode($result)); - } - } - - // Miss - $analysis = parent::analyze($filename); - - // Save result - if (file_exists($filename)) { - $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection); - } - return $analysis; - } - - - - // private: (re)create sql table - private function create_table($drop=false) { - - $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `".mysql_real_escape_string($this->table)."` ( - `filename` VARCHAR(255) NOT NULL DEFAULT '', - `filesize` INT(11) NOT NULL DEFAULT '0', - `filetime` INT(11) NOT NULL DEFAULT '0', - `analyzetime` INT(11) NOT NULL DEFAULT '0', - `value` TEXT NOT NULL, - PRIMARY KEY (`filename`,`filesize`,`filetime`)) ENGINE=MyISAM", $this->connection); - echo mysql_error($this->connection); - } -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// extension.cache.mysql.php - part of getID3() // +// Please see readme.txt for more information // +// /// +///////////////////////////////////////////////////////////////// +// // +// This extension written by Allan Hansen // +// Table name mod by Carlo Capocasa // +// /// +///////////////////////////////////////////////////////////////// + + +/** +* This is a caching extension for getID3(). It works the exact same +* way as the getID3 class, but return cached information very fast +* +* Example: (see also demo.cache.mysql.php in /demo/) +* +* Normal getID3 usage (example): +* +* require_once 'getid3/getid3.php'; +* $getID3 = new getID3; +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* getID3_cached usage: +* +* require_once 'getid3/getid3.php'; +* require_once 'getid3/getid3/extension.cache.mysql.php'; +* // 5th parameter (tablename) is optional, default is 'getid3_cache' +* $getID3 = new getID3_cached_mysql('localhost', 'database', 'username', 'password', 'tablename'); +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* +* Supported Cache Types (this extension) +* +* SQL Databases: +* +* cache_type cache_options +* ------------------------------------------------------------------- +* mysql host, database, username, password +* +* +* DBM-Style Databases: (use extension.cache.dbm) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* gdbm dbm_filename, lock_filename +* ndbm dbm_filename, lock_filename +* db2 dbm_filename, lock_filename +* db3 dbm_filename, lock_filename +* db4 dbm_filename, lock_filename (PHP5 required) +* +* PHP must have write access to both dbm_filename and lock_filename. +* +* +* Recommended Cache Types +* +* Infrequent updates, many reads any DBM +* Frequent updates mysql +*/ + + +class getID3_cached_mysql extends getID3 +{ + + // private vars + private $cursor; + private $connection; + + + // public: constructor - see top of this file for cache type and cache_options + public function getID3_cached_mysql($host, $database, $username, $password, $table='getid3_cache') { + + // Check for mysql support + if (!function_exists('mysql_pconnect')) { + throw new Exception('PHP not compiled with mysql support.'); + } + + // Connect to database + $this->connection = mysql_pconnect($host, $username, $password); + if (!$this->connection) { + throw new Exception('mysql_pconnect() failed - check permissions and spelling.'); + } + + // Select database + if (!mysql_select_db($database, $this->connection)) { + throw new Exception('Cannot use database '.$database); + } + + // Set table + $this->table = $table; + + // Create cache table if not exists + $this->create_table(); + + // Check version number and clear cache if changed + $version = ''; + if ($this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string(getID3::VERSION)."') AND (`filesize` = '-1') AND (`filetime` = '-1') AND (`analyzetime` = '-1')", $this->connection)) { + list($version) = mysql_fetch_array($this->cursor); + } + if ($version != getID3::VERSION) { + $this->clear_cache(); + } + + parent::getID3(); + } + + + + // public: clear cache + public function clear_cache() { + + $this->cursor = mysql_query("DELETE FROM `".mysql_real_escape_string($this->table)."`", $this->connection); + $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` VALUES ('".getID3::VERSION."', -1, -1, -1, '".getID3::VERSION."')", $this->connection); + } + + + + // public: analyze file + public function analyze($filename) { + + if (file_exists($filename)) { + + // Short-hands + $filetime = filemtime($filename); + $filesize = filesize($filename); + + // Lookup file + $this->cursor = mysql_query("SELECT `value` FROM `".mysql_real_escape_string($this->table)."` WHERE (`filename` = '".mysql_real_escape_string($filename)."') AND (`filesize` = '".mysql_real_escape_string($filesize)."') AND (`filetime` = '".mysql_real_escape_string($filetime)."')", $this->connection); + if (mysql_num_rows($this->cursor) > 0) { + // Hit + list($result) = mysql_fetch_array($this->cursor); + return unserialize(base64_decode($result)); + } + } + + // Miss + $analysis = parent::analyze($filename); + + // Save result + if (file_exists($filename)) { + $this->cursor = mysql_query("INSERT INTO `".mysql_real_escape_string($this->table)."` (`filename`, `filesize`, `filetime`, `analyzetime`, `value`) VALUES ('".mysql_real_escape_string($filename)."', '".mysql_real_escape_string($filesize)."', '".mysql_real_escape_string($filetime)."', '".mysql_real_escape_string(time())."', '".mysql_real_escape_string(base64_encode(serialize($analysis)))."')", $this->connection); + } + return $analysis; + } + + + + // private: (re)create sql table + private function create_table($drop=false) { + + $this->cursor = mysql_query("CREATE TABLE IF NOT EXISTS `".mysql_real_escape_string($this->table)."` ( + `filename` VARCHAR(255) NOT NULL DEFAULT '', + `filesize` INT(11) NOT NULL DEFAULT '0', + `filetime` INT(11) NOT NULL DEFAULT '0', + `analyzetime` INT(11) NOT NULL DEFAULT '0', + `value` TEXT NOT NULL, + PRIMARY KEY (`filename`,`filesize`,`filetime`)) ENGINE=MyISAM", $this->connection); + echo mysql_error($this->connection); + } +} diff --git a/app/libs/vendor/getid3/extension.cache.sqlite3.php b/app/libs/vendor/getid3/extension.cache.sqlite3.php index 676685cd..d4d4f778 100644 --- a/app/libs/vendor/getid3/extension.cache.sqlite3.php +++ b/app/libs/vendor/getid3/extension.cache.sqlite3.php @@ -1,264 +1,264 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org /// -///////////////////////////////////////////////////////////////////////////////// -/// // -// extension.cache.sqlite3.php - part of getID3() // -// Please see readme.txt for more information // -// /// -///////////////////////////////////////////////////////////////////////////////// -/// // -// MySQL extension written by Allan Hansen // -// Table name mod by Carlo Capocasa // -// MySQL extension was reworked for SQLite3 by Karl G. Holz // -// /// -///////////////////////////////////////////////////////////////////////////////// -/** -* This is a caching extension for getID3(). It works the exact same -* way as the getID3 class, but return cached information much faster -* -* Normal getID3 usage (example): -* -* require_once 'getid3/getid3.php'; -* $getID3 = new getID3; -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* getID3_cached usage: -* -* require_once 'getid3/getid3.php'; -* require_once 'getid3/extension.cache.sqlite3.php'; -* // all parameters are optional, defaults are: -* $getID3 = new getID3_cached_sqlite3($table='getid3_cache', $hide=FALSE); -* $getID3->encoding = 'UTF-8'; -* $info1 = $getID3->analyze('file1.flac'); -* $info2 = $getID3->analyze('file2.wv'); -* -* -* Supported Cache Types (this extension) -* -* SQL Databases: -* -* cache_type cache_options -* ------------------------------------------------------------------- -* mysql host, database, username, password -* -* sqlite3 table='getid3_cache', hide=false (PHP5) -* - -*** database file will be stored in the same directory as this script, -*** webserver must have write access to that directory! -*** set $hide to TRUE to prefix db file with .ht to pervent access from web client -*** this is a default setting in the Apache configuration: - -# The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients. - - - Order allow,deny - Deny from all - Satisfy all - - -******************************************************************************** -* -* ------------------------------------------------------------------- -* DBM-Style Databases: (use extension.cache.dbm) -* -* cache_type cache_options -* ------------------------------------------------------------------- -* gdbm dbm_filename, lock_filename -* ndbm dbm_filename, lock_filename -* db2 dbm_filename, lock_filename -* db3 dbm_filename, lock_filename -* db4 dbm_filename, lock_filename (PHP5 required) -* -* PHP must have write access to both dbm_filename and lock_filename. -* -* Recommended Cache Types -* -* Infrequent updates, many reads any DBM -* Frequent updates mysql -******************************************************************************** -* -* IMHO this is still a bit slow, I'm using this with MP4/MOV/ M4v files -* there is a plan to add directory scanning and analyzing to make things work much faster -* -* -*/ -class getID3_cached_sqlite3 extends getID3 { - - /** - * __construct() - * @param string $table holds name of sqlite table - * @return type - */ - public function __construct($table='getid3_cache', $hide=false) { - $this->table = $table; // Set table - $file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite'; - if ($hide) { - $file = dirname(__FILE__).'/.ht.'.basename(__FILE__, 'php').'sqlite'; - } - $this->db = new SQLite3($file); - $db = $this->db; - $this->create_table(); // Create cache table if not exists - $version = ''; - $sql = $this->version_check; - $stmt = $db->prepare($sql); - $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT); - $result = $stmt->execute(); - list($version) = $result->fetchArray(); - if ($version != getID3::VERSION) { // Check version number and clear cache if changed - $this->clear_cache(); - } - return parent::__construct(); - } - - /** - * close the database connection - */ - public function __destruct() { - $db=$this->db; - $db->close(); - } - - /** - * hold the sqlite db - * @var SQLite Resource - */ - private $db; - - /** - * table to use for caching - * @var string $table - */ - private $table; - - /** - * clear the cache - * @access private - * @return type - */ - private function clear_cache() { - $db = $this->db; - $sql = $this->delete_cache; - $db->exec($sql); - $sql = $this->set_version; - $stmt = $db->prepare($sql); - $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT); - $stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT); - $stmt->bindValue(':val', getID3::VERSION, SQLITE3_TEXT); - return $stmt->execute(); - } - - /** - * analyze file and cache them, if cached pull from the db - * @param type $filename - * @return boolean - */ - public function analyze($filename) { - if (!file_exists($filename)) { - return false; - } - // items to track for caching - $filetime = filemtime($filename); - $filesize = filesize($filename); - // this will be saved for a quick directory lookup of analized files - // ... why do 50 seperate sql quries when you can do 1 for the same result - $dirname = dirname($filename); - // Lookup file - $db = $this->db; - $sql = $this->get_id3_data; - $stmt = $db->prepare($sql); - $stmt->bindValue(':filename', $filename, SQLITE3_TEXT); - $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); - $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); - $res = $stmt->execute(); - list($result) = $res->fetchArray(); - if (count($result) > 0 ) { - return unserialize(base64_decode($result)); - } - // if it hasn't been analyzed before, then do it now - $analysis = parent::analyze($filename); - // Save result - $sql = $this->cache_file; - $stmt = $db->prepare($sql); - $stmt->bindValue(':filename', $filename, SQLITE3_TEXT); - $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT); - $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); - $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); - $stmt->bindValue(':atime', time(), SQLITE3_INTEGER); - $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT); - $res = $stmt->execute(); - return $analysis; - } - - /** - * create data base table - * this is almost the same as MySQL, with the exception of the dirname being added - * @return type - */ - private function create_table() { - $db = $this->db; - $sql = $this->make_table; - return $db->exec($sql); - } - - /** - * get cached directory - * - * This function is not in the MySQL extention, it's ment to speed up requesting multiple files - * which is ideal for podcasting, playlists, etc. - * - * @access public - * @param string $dir directory to search the cache database for - * @return array return an array of matching id3 data - */ - public function get_cached_dir($dir) { - $db = $this->db; - $rows = array(); - $sql = $this->get_cached_dir; - $stmt = $db->prepare($sql); - $stmt->bindValue(':dirname', $dir, SQLITE3_TEXT); - $res = $stmt->execute(); - while ($row=$res->fetchArray()) { - $rows[] = unserialize(base64_decode($row)); - } - return $rows; - } - - /** - * use the magical __get() for sql queries - * - * access as easy as $this->{case name}, returns NULL if query is not found - */ - public function __get($name) { - switch($name) { - case 'version_check': - return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'"; - break; - case 'delete_cache': - return "DELETE FROM $this->table"; - break; - case 'set_version': - return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)"; - break; - case 'get_id3_data': - return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime"; - break; - case 'cache_file': - return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)"; - break; - case 'make_table': - return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))"; - break; - case 'get_cached_dir': - return "SELECT val FROM $this->table WHERE dirname = :dirname"; - break; - } - return null; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org /// +///////////////////////////////////////////////////////////////////////////////// +/// // +// extension.cache.sqlite3.php - part of getID3() // +// Please see readme.txt for more information // +// /// +///////////////////////////////////////////////////////////////////////////////// +/// // +// MySQL extension written by Allan Hansen // +// Table name mod by Carlo Capocasa // +// MySQL extension was reworked for SQLite3 by Karl G. Holz // +// /// +///////////////////////////////////////////////////////////////////////////////// +/** +* This is a caching extension for getID3(). It works the exact same +* way as the getID3 class, but return cached information much faster +* +* Normal getID3 usage (example): +* +* require_once 'getid3/getid3.php'; +* $getID3 = new getID3; +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* getID3_cached usage: +* +* require_once 'getid3/getid3.php'; +* require_once 'getid3/extension.cache.sqlite3.php'; +* // all parameters are optional, defaults are: +* $getID3 = new getID3_cached_sqlite3($table='getid3_cache', $hide=FALSE); +* $getID3->encoding = 'UTF-8'; +* $info1 = $getID3->analyze('file1.flac'); +* $info2 = $getID3->analyze('file2.wv'); +* +* +* Supported Cache Types (this extension) +* +* SQL Databases: +* +* cache_type cache_options +* ------------------------------------------------------------------- +* mysql host, database, username, password +* +* sqlite3 table='getid3_cache', hide=false (PHP5) +* + +*** database file will be stored in the same directory as this script, +*** webserver must have write access to that directory! +*** set $hide to TRUE to prefix db file with .ht to pervent access from web client +*** this is a default setting in the Apache configuration: + +# The following lines prevent .htaccess and .htpasswd files from being viewed by Web clients. + + + Order allow,deny + Deny from all + Satisfy all + + +******************************************************************************** +* +* ------------------------------------------------------------------- +* DBM-Style Databases: (use extension.cache.dbm) +* +* cache_type cache_options +* ------------------------------------------------------------------- +* gdbm dbm_filename, lock_filename +* ndbm dbm_filename, lock_filename +* db2 dbm_filename, lock_filename +* db3 dbm_filename, lock_filename +* db4 dbm_filename, lock_filename (PHP5 required) +* +* PHP must have write access to both dbm_filename and lock_filename. +* +* Recommended Cache Types +* +* Infrequent updates, many reads any DBM +* Frequent updates mysql +******************************************************************************** +* +* IMHO this is still a bit slow, I'm using this with MP4/MOV/ M4v files +* there is a plan to add directory scanning and analyzing to make things work much faster +* +* +*/ +class getID3_cached_sqlite3 extends getID3 { + + /** + * __construct() + * @param string $table holds name of sqlite table + * @return type + */ + public function __construct($table='getid3_cache', $hide=false) { + $this->table = $table; // Set table + $file = dirname(__FILE__).'/'.basename(__FILE__, 'php').'sqlite'; + if ($hide) { + $file = dirname(__FILE__).'/.ht.'.basename(__FILE__, 'php').'sqlite'; + } + $this->db = new SQLite3($file); + $db = $this->db; + $this->create_table(); // Create cache table if not exists + $version = ''; + $sql = $this->version_check; + $stmt = $db->prepare($sql); + $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT); + $result = $stmt->execute(); + list($version) = $result->fetchArray(); + if ($version != getID3::VERSION) { // Check version number and clear cache if changed + $this->clear_cache(); + } + return parent::__construct(); + } + + /** + * close the database connection + */ + public function __destruct() { + $db=$this->db; + $db->close(); + } + + /** + * hold the sqlite db + * @var SQLite Resource + */ + private $db; + + /** + * table to use for caching + * @var string $table + */ + private $table; + + /** + * clear the cache + * @access private + * @return type + */ + private function clear_cache() { + $db = $this->db; + $sql = $this->delete_cache; + $db->exec($sql); + $sql = $this->set_version; + $stmt = $db->prepare($sql); + $stmt->bindValue(':filename', getID3::VERSION, SQLITE3_TEXT); + $stmt->bindValue(':dirname', getID3::VERSION, SQLITE3_TEXT); + $stmt->bindValue(':val', getID3::VERSION, SQLITE3_TEXT); + return $stmt->execute(); + } + + /** + * analyze file and cache them, if cached pull from the db + * @param type $filename + * @return boolean + */ + public function analyze($filename) { + if (!file_exists($filename)) { + return false; + } + // items to track for caching + $filetime = filemtime($filename); + $filesize = filesize($filename); + // this will be saved for a quick directory lookup of analized files + // ... why do 50 seperate sql quries when you can do 1 for the same result + $dirname = dirname($filename); + // Lookup file + $db = $this->db; + $sql = $this->get_id3_data; + $stmt = $db->prepare($sql); + $stmt->bindValue(':filename', $filename, SQLITE3_TEXT); + $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); + $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); + $res = $stmt->execute(); + list($result) = $res->fetchArray(); + if (count($result) > 0 ) { + return unserialize(base64_decode($result)); + } + // if it hasn't been analyzed before, then do it now + $analysis = parent::analyze($filename); + // Save result + $sql = $this->cache_file; + $stmt = $db->prepare($sql); + $stmt->bindValue(':filename', $filename, SQLITE3_TEXT); + $stmt->bindValue(':dirname', $dirname, SQLITE3_TEXT); + $stmt->bindValue(':filesize', $filesize, SQLITE3_INTEGER); + $stmt->bindValue(':filetime', $filetime, SQLITE3_INTEGER); + $stmt->bindValue(':atime', time(), SQLITE3_INTEGER); + $stmt->bindValue(':val', base64_encode(serialize($analysis)), SQLITE3_TEXT); + $res = $stmt->execute(); + return $analysis; + } + + /** + * create data base table + * this is almost the same as MySQL, with the exception of the dirname being added + * @return type + */ + private function create_table() { + $db = $this->db; + $sql = $this->make_table; + return $db->exec($sql); + } + + /** + * get cached directory + * + * This function is not in the MySQL extention, it's ment to speed up requesting multiple files + * which is ideal for podcasting, playlists, etc. + * + * @access public + * @param string $dir directory to search the cache database for + * @return array return an array of matching id3 data + */ + public function get_cached_dir($dir) { + $db = $this->db; + $rows = array(); + $sql = $this->get_cached_dir; + $stmt = $db->prepare($sql); + $stmt->bindValue(':dirname', $dir, SQLITE3_TEXT); + $res = $stmt->execute(); + while ($row=$res->fetchArray()) { + $rows[] = unserialize(base64_decode($row)); + } + return $rows; + } + + /** + * use the magical __get() for sql queries + * + * access as easy as $this->{case name}, returns NULL if query is not found + */ + public function __get($name) { + switch($name) { + case 'version_check': + return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = '-1' AND filetime = '-1' AND analyzetime = '-1'"; + break; + case 'delete_cache': + return "DELETE FROM $this->table"; + break; + case 'set_version': + return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, -1, -1, -1, :val)"; + break; + case 'get_id3_data': + return "SELECT val FROM $this->table WHERE filename = :filename AND filesize = :filesize AND filetime = :filetime"; + break; + case 'cache_file': + return "INSERT INTO $this->table (filename, dirname, filesize, filetime, analyzetime, val) VALUES (:filename, :dirname, :filesize, :filetime, :atime, :val)"; + break; + case 'make_table': + return "CREATE TABLE IF NOT EXISTS $this->table (filename VARCHAR(255) NOT NULL DEFAULT '', dirname VARCHAR(255) NOT NULL DEFAULT '', filesize INT(11) NOT NULL DEFAULT '0', filetime INT(11) NOT NULL DEFAULT '0', analyzetime INT(11) NOT NULL DEFAULT '0', val text not null, PRIMARY KEY (filename, filesize, filetime))"; + break; + case 'get_cached_dir': + return "SELECT val FROM $this->table WHERE dirname = :dirname"; + break; + } + return null; + } + +} diff --git a/app/libs/vendor/getid3/getid3.lib.php b/app/libs/vendor/getid3/getid3.lib.php index 4ccc0a5b..54008194 100644 --- a/app/libs/vendor/getid3/getid3.lib.php +++ b/app/libs/vendor/getid3/getid3.lib.php @@ -1,1342 +1,1342 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// // -// getid3.lib.php - part of getID3() // -// See readme.txt for more details // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_lib -{ - - public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { - $returnstring = ''; - for ($i = 0; $i < strlen($string); $i++) { - if ($hex) { - $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); - } else { - $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤'); - } - if ($spaces) { - $returnstring .= ' '; - } - } - if (!empty($htmlencoding)) { - if ($htmlencoding === true) { - $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean - } - $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding); - } - return $returnstring; - } - - public static function trunc($floatnumber) { - // truncates a floating-point number at the decimal point - // returns int (if possible, otherwise float) - if ($floatnumber >= 1) { - $truncatednumber = floor($floatnumber); - } elseif ($floatnumber <= -1) { - $truncatednumber = ceil($floatnumber); - } else { - $truncatednumber = 0; - } - if (self::intValueSupported($truncatednumber)) { - $truncatednumber = (int) $truncatednumber; - } - return $truncatednumber; - } - - - public static function safe_inc(&$variable, $increment=1) { - if (isset($variable)) { - $variable += $increment; - } else { - $variable = $increment; - } - return true; - } - - public static function CastAsInt($floatnum) { - // convert to float if not already - $floatnum = (float) $floatnum; - - // convert a float to type int, only if possible - if (self::trunc($floatnum) == $floatnum) { - // it's not floating point - if (self::intValueSupported($floatnum)) { - // it's within int range - $floatnum = (int) $floatnum; - } - } - return $floatnum; - } - - public static function intValueSupported($num) { - // check if integers are 64-bit - static $hasINT64 = null; - if ($hasINT64 === null) { // 10x faster than is_null() - $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 - if (!$hasINT64 && !defined('PHP_INT_MIN')) { - define('PHP_INT_MIN', ~PHP_INT_MAX); - } - } - // if integers are 64-bit - no other check required - if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { - return true; - } - return false; - } - - public static function DecimalizeFraction($fraction) { - list($numerator, $denominator) = explode('/', $fraction); - return $numerator / ($denominator ? $denominator : 1); - } - - - public static function DecimalBinary2Float($binarynumerator) { - $numerator = self::Bin2Dec($binarynumerator); - $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); - return ($numerator / $denominator); - } - - - public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { - // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html - if (strpos($binarypointnumber, '.') === false) { - $binarypointnumber = '0.'.$binarypointnumber; - } elseif ($binarypointnumber{0} == '.') { - $binarypointnumber = '0'.$binarypointnumber; - } - $exponent = 0; - while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) { - if (substr($binarypointnumber, 1, 1) == '.') { - $exponent--; - $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); - } else { - $pointpos = strpos($binarypointnumber, '.'); - $exponent += ($pointpos - 1); - $binarypointnumber = str_replace('.', '', $binarypointnumber); - $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1); - } - } - $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); - return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); - } - - - public static function Float2BinaryDecimal($floatvalue) { - // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html - $maxbits = 128; // to how many bits of precision should the calculations be taken? - $intpart = self::trunc($floatvalue); - $floatpart = abs($floatvalue - $intpart); - $pointbitstring = ''; - while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { - $floatpart *= 2; - $pointbitstring .= (string) self::trunc($floatpart); - $floatpart -= self::trunc($floatpart); - } - $binarypointnumber = decbin($intpart).'.'.$pointbitstring; - return $binarypointnumber; - } - - - public static function Float2String($floatvalue, $bits) { - // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html - switch ($bits) { - case 32: - $exponentbits = 8; - $fractionbits = 23; - break; - - case 64: - $exponentbits = 11; - $fractionbits = 52; - break; - - default: - return false; - break; - } - if ($floatvalue >= 0) { - $signbit = '0'; - } else { - $signbit = '1'; - } - $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits); - $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent - $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT); - $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); - - return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); - } - - - public static function LittleEndian2Float($byteword) { - return self::BigEndian2Float(strrev($byteword)); - } - - - public static function BigEndian2Float($byteword) { - // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic - // http://www.psc.edu/general/software/packages/ieee/ieee.html - // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html - - $bitword = self::BigEndian2Bin($byteword); - if (!$bitword) { - return 0; - } - $signbit = $bitword{0}; - - switch (strlen($byteword) * 8) { - case 32: - $exponentbits = 8; - $fractionbits = 23; - break; - - case 64: - $exponentbits = 11; - $fractionbits = 52; - break; - - case 80: - // 80-bit Apple SANE format - // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ - $exponentstring = substr($bitword, 1, 15); - $isnormalized = intval($bitword{16}); - $fractionstring = substr($bitword, 17, 63); - $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); - $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); - $floatvalue = $exponent * $fraction; - if ($signbit == '1') { - $floatvalue *= -1; - } - return $floatvalue; - break; - - default: - return false; - break; - } - $exponentstring = substr($bitword, 1, $exponentbits); - $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); - $exponent = self::Bin2Dec($exponentstring); - $fraction = self::Bin2Dec($fractionstring); - - if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { - // Not a Number - $floatvalue = false; - } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { - if ($signbit == '1') { - $floatvalue = '-infinity'; - } else { - $floatvalue = '+infinity'; - } - } elseif (($exponent == 0) && ($fraction == 0)) { - if ($signbit == '1') { - $floatvalue = -0; - } else { - $floatvalue = 0; - } - $floatvalue = ($signbit ? 0 : -0); - } elseif (($exponent == 0) && ($fraction != 0)) { - // These are 'unnormalized' values - $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring); - if ($signbit == '1') { - $floatvalue *= -1; - } - } elseif ($exponent != 0) { - $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring)); - if ($signbit == '1') { - $floatvalue *= -1; - } - } - return (float) $floatvalue; - } - - - public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { - $intvalue = 0; - $bytewordlen = strlen($byteword); - if ($bytewordlen == 0) { - return false; - } - for ($i = 0; $i < $bytewordlen; $i++) { - if ($synchsafe) { // disregard MSB, effectively 7-bit bytes - //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems - $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); - } else { - $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); - } - } - if ($signed && !$synchsafe) { - // synchsafe ints are not allowed to be signed - if ($bytewordlen <= PHP_INT_SIZE) { - $signMaskBit = 0x80 << (8 * ($bytewordlen - 1)); - if ($intvalue & $signMaskBit) { - $intvalue = 0 - ($intvalue & ($signMaskBit - 1)); - } - } else { - throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()'); - break; - } - } - return self::CastAsInt($intvalue); - } - - - public static function LittleEndian2Int($byteword, $signed=false) { - return self::BigEndian2Int(strrev($byteword), false, $signed); - } - - - public static function BigEndian2Bin($byteword) { - $binvalue = ''; - $bytewordlen = strlen($byteword); - for ($i = 0; $i < $bytewordlen; $i++) { - $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT); - } - return $binvalue; - } - - - public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { - if ($number < 0) { - throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); - } - $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); - $intstring = ''; - if ($signed) { - if ($minbytes > PHP_INT_SIZE) { - throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()'); - } - $number = $number & (0x80 << (8 * ($minbytes - 1))); - } - while ($number != 0) { - $quotient = ($number / ($maskbyte + 1)); - $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring; - $number = floor($quotient); - } - return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT); - } - - - public static function Dec2Bin($number) { - while ($number >= 256) { - $bytes[] = (($number / 256) - (floor($number / 256))) * 256; - $number = floor($number / 256); - } - $bytes[] = $number; - $binstring = ''; - for ($i = 0; $i < count($bytes); $i++) { - $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring; - } - return $binstring; - } - - - public static function Bin2Dec($binstring, $signed=false) { - $signmult = 1; - if ($signed) { - if ($binstring{0} == '1') { - $signmult = -1; - } - $binstring = substr($binstring, 1); - } - $decvalue = 0; - for ($i = 0; $i < strlen($binstring); $i++) { - $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); - } - return self::CastAsInt($decvalue * $signmult); - } - - - public static function Bin2String($binstring) { - // return 'hi' for input of '0110100001101001' - $string = ''; - $binstringreversed = strrev($binstring); - for ($i = 0; $i < strlen($binstringreversed); $i += 8) { - $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; - } - return $string; - } - - - public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { - $intstring = ''; - while ($number > 0) { - if ($synchsafe) { - $intstring = $intstring.chr($number & 127); - $number >>= 7; - } else { - $intstring = $intstring.chr($number & 255); - $number >>= 8; - } - } - return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); - } - - - public static function array_merge_clobber($array1, $array2) { - // written by kcØhireability*com - // taken from http://www.php.net/manual/en/function.array-merge-recursive.php - if (!is_array($array1) || !is_array($array2)) { - return false; - } - $newarray = $array1; - foreach ($array2 as $key => $val) { - if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { - $newarray[$key] = self::array_merge_clobber($newarray[$key], $val); - } else { - $newarray[$key] = $val; - } - } - return $newarray; - } - - - public static function array_merge_noclobber($array1, $array2) { - if (!is_array($array1) || !is_array($array2)) { - return false; - } - $newarray = $array1; - foreach ($array2 as $key => $val) { - if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { - $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val); - } elseif (!isset($newarray[$key])) { - $newarray[$key] = $val; - } - } - return $newarray; - } - - - public static function ksort_recursive(&$theArray) { - ksort($theArray); - foreach ($theArray as $key => $value) { - if (is_array($value)) { - self::ksort_recursive($theArray[$key]); - } - } - return true; - } - - public static function fileextension($filename, $numextensions=1) { - if (strstr($filename, '.')) { - $reversedfilename = strrev($filename); - $offset = 0; - for ($i = 0; $i < $numextensions; $i++) { - $offset = strpos($reversedfilename, '.', $offset + 1); - if ($offset === false) { - return ''; - } - } - return strrev(substr($reversedfilename, 0, $offset)); - } - return ''; - } - - - public static function PlaytimeString($seconds) { - $sign = (($seconds < 0) ? '-' : ''); - $seconds = round(abs($seconds)); - $H = (int) floor( $seconds / 3600); - $M = (int) floor(($seconds - (3600 * $H) ) / 60); - $S = (int) round( $seconds - (3600 * $H) - (60 * $M) ); - return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT); - } - - - public static function DateMac2Unix($macdate) { - // Macintosh timestamp: seconds since 00:00h January 1, 1904 - // UNIX timestamp: seconds since 00:00h January 1, 1970 - return self::CastAsInt($macdate - 2082844800); - } - - - public static function FixedPoint8_8($rawdata) { - return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); - } - - - public static function FixedPoint16_16($rawdata) { - return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); - } - - - public static function FixedPoint2_30($rawdata) { - $binarystring = self::BigEndian2Bin($rawdata); - return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); - } - - - public static function CreateDeepArray($ArrayPath, $Separator, $Value) { - // assigns $Value to a nested array path: - // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') - // is the same as: - // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); - // or - // $foo['path']['to']['my'] = 'file.txt'; - $ArrayPath = ltrim($ArrayPath, $Separator); - if (($pos = strpos($ArrayPath, $Separator)) !== false) { - $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); - } else { - $ReturnedArray[$ArrayPath] = $Value; - } - return $ReturnedArray; - } - - public static function array_max($arraydata, $returnkey=false) { - $maxvalue = false; - $maxkey = false; - foreach ($arraydata as $key => $value) { - if (!is_array($value)) { - if ($value > $maxvalue) { - $maxvalue = $value; - $maxkey = $key; - } - } - } - return ($returnkey ? $maxkey : $maxvalue); - } - - public static function array_min($arraydata, $returnkey=false) { - $minvalue = false; - $minkey = false; - foreach ($arraydata as $key => $value) { - if (!is_array($value)) { - if ($value > $minvalue) { - $minvalue = $value; - $minkey = $key; - } - } - } - return ($returnkey ? $minkey : $minvalue); - } - - public static function XML2array($XMLstring) { - if (function_exists('simplexml_load_string')) { - if (function_exists('get_object_vars')) { - $XMLobject = simplexml_load_string($XMLstring); - return self::SimpleXMLelement2array($XMLobject); - } - } - return false; - } - - public static function SimpleXMLelement2array($XMLobject) { - if (!is_object($XMLobject) && !is_array($XMLobject)) { - return $XMLobject; - } - $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject); - foreach ($XMLarray as $key => $value) { - $XMLarray[$key] = self::SimpleXMLelement2array($value); - } - return $XMLarray; - } - - - // Allan Hansen - // self::md5_data() - returns md5sum for a file from startuing position to absolute end position - public static function hash_data($file, $offset, $end, $algorithm) { - static $tempdir = ''; - if (!self::intValueSupported($end)) { - return false; - } - switch ($algorithm) { - case 'md5': - $hash_function = 'md5_file'; - $unix_call = 'md5sum'; - $windows_call = 'md5sum.exe'; - $hash_length = 32; - break; - - case 'sha1': - $hash_function = 'sha1_file'; - $unix_call = 'sha1sum'; - $windows_call = 'sha1sum.exe'; - $hash_length = 40; - break; - - default: - throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()'); - break; - } - $size = $end - $offset; - while (true) { - if (GETID3_OS_ISWINDOWS) { - - // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data - // Fall back to create-temp-file method: - if ($algorithm == 'sha1') { - break; - } - - $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); - foreach ($RequiredFiles as $required_file) { - if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { - // helper apps not available - fall back to old method - break 2; - } - } - $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | '; - $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; - $commandline .= GETID3_HELPERAPPSDIR.$windows_call; - - } else { - - $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; - $commandline .= 'tail -c'.$size.' | '; - $commandline .= $unix_call; - - } - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'); - break; - } - return substr(`$commandline`, 0, $hash_length); - } - - if (empty($tempdir)) { - // yes this is ugly, feel free to suggest a better way - require_once(dirname(__FILE__).'/getid3.php'); - $getid3_temp = new getID3(); - $tempdir = $getid3_temp->tempdir; - unset($getid3_temp); - } - // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir - if (($data_filename = tempnam($tempdir, 'gI3')) === false) { - // can't find anywhere to create a temp file, just fail - return false; - } - - // Init - $result = false; - - // copy parts of file - try { - self::CopyFileParts($file, $data_filename, $offset, $end - $offset); - $result = $hash_function($data_filename); - } catch (Exception $e) { - throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage()); - } - unlink($data_filename); - return $result; - } - - public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) { - if (!self::intValueSupported($offset + $length)) { - throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); - } - if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) { - if (($fp_dest = fopen($filename_dest, 'wb'))) { - if (fseek($fp_src, $offset, SEEK_SET) == 0) { - $byteslefttowrite = $length; - while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) { - $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); - $byteslefttowrite -= $byteswritten; - } - return true; - } else { - throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); - } - fclose($fp_dest); - } else { - throw new Exception('failed to create file for writing '.$filename_dest); - } - fclose($fp_src); - } else { - throw new Exception('failed to open file for reading '.$filename_source); - } - return false; - } - - public static function iconv_fallback_int_utf8($charval) { - if ($charval < 128) { - // 0bbbbbbb - $newcharstring = chr($charval); - } elseif ($charval < 2048) { - // 110bbbbb 10bbbbbb - $newcharstring = chr(($charval >> 6) | 0xC0); - $newcharstring .= chr(($charval & 0x3F) | 0x80); - } elseif ($charval < 65536) { - // 1110bbbb 10bbbbbb 10bbbbbb - $newcharstring = chr(($charval >> 12) | 0xE0); - $newcharstring .= chr(($charval >> 6) | 0xC0); - $newcharstring .= chr(($charval & 0x3F) | 0x80); - } else { - // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - $newcharstring = chr(($charval >> 18) | 0xF0); - $newcharstring .= chr(($charval >> 12) | 0xC0); - $newcharstring .= chr(($charval >> 6) | 0xC0); - $newcharstring .= chr(($charval & 0x3F) | 0x80); - } - return $newcharstring; - } - - // ISO-8859-1 => UTF-8 - public static function iconv_fallback_iso88591_utf8($string, $bom=false) { - if (function_exists('utf8_encode')) { - return utf8_encode($string); - } - // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) - $newcharstring = ''; - if ($bom) { - $newcharstring .= "\xEF\xBB\xBF"; - } - for ($i = 0; $i < strlen($string); $i++) { - $charval = ord($string{$i}); - $newcharstring .= self::iconv_fallback_int_utf8($charval); - } - return $newcharstring; - } - - // ISO-8859-1 => UTF-16BE - public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { - $newcharstring = ''; - if ($bom) { - $newcharstring .= "\xFE\xFF"; - } - for ($i = 0; $i < strlen($string); $i++) { - $newcharstring .= "\x00".$string{$i}; - } - return $newcharstring; - } - - // ISO-8859-1 => UTF-16LE - public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { - $newcharstring = ''; - if ($bom) { - $newcharstring .= "\xFF\xFE"; - } - for ($i = 0; $i < strlen($string); $i++) { - $newcharstring .= $string{$i}."\x00"; - } - return $newcharstring; - } - - // ISO-8859-1 => UTF-16LE (BOM) - public static function iconv_fallback_iso88591_utf16($string) { - return self::iconv_fallback_iso88591_utf16le($string, true); - } - - // UTF-8 => ISO-8859-1 - public static function iconv_fallback_utf8_iso88591($string) { - if (function_exists('utf8_decode')) { - return utf8_decode($string); - } - // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) - $newcharstring = ''; - $offset = 0; - $stringlength = strlen($string); - while ($offset < $stringlength) { - if ((ord($string{$offset}) | 0x07) == 0xF7) { - // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & - ((ord($string{($offset + 1)}) & 0x3F) << 12) & - ((ord($string{($offset + 2)}) & 0x3F) << 6) & - (ord($string{($offset + 3)}) & 0x3F); - $offset += 4; - } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { - // 1110bbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & - ((ord($string{($offset + 1)}) & 0x3F) << 6) & - (ord($string{($offset + 2)}) & 0x3F); - $offset += 3; - } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { - // 110bbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & - (ord($string{($offset + 1)}) & 0x3F); - $offset += 2; - } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { - // 0bbbbbbb - $charval = ord($string{$offset}); - $offset += 1; - } else { - // error? throw some kind of warning here? - $charval = false; - $offset += 1; - } - if ($charval !== false) { - $newcharstring .= (($charval < 256) ? chr($charval) : '?'); - } - } - return $newcharstring; - } - - // UTF-8 => UTF-16BE - public static function iconv_fallback_utf8_utf16be($string, $bom=false) { - $newcharstring = ''; - if ($bom) { - $newcharstring .= "\xFE\xFF"; - } - $offset = 0; - $stringlength = strlen($string); - while ($offset < $stringlength) { - if ((ord($string{$offset}) | 0x07) == 0xF7) { - // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & - ((ord($string{($offset + 1)}) & 0x3F) << 12) & - ((ord($string{($offset + 2)}) & 0x3F) << 6) & - (ord($string{($offset + 3)}) & 0x3F); - $offset += 4; - } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { - // 1110bbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & - ((ord($string{($offset + 1)}) & 0x3F) << 6) & - (ord($string{($offset + 2)}) & 0x3F); - $offset += 3; - } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { - // 110bbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & - (ord($string{($offset + 1)}) & 0x3F); - $offset += 2; - } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { - // 0bbbbbbb - $charval = ord($string{$offset}); - $offset += 1; - } else { - // error? throw some kind of warning here? - $charval = false; - $offset += 1; - } - if ($charval !== false) { - $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?'); - } - } - return $newcharstring; - } - - // UTF-8 => UTF-16LE - public static function iconv_fallback_utf8_utf16le($string, $bom=false) { - $newcharstring = ''; - if ($bom) { - $newcharstring .= "\xFF\xFE"; - } - $offset = 0; - $stringlength = strlen($string); - while ($offset < $stringlength) { - if ((ord($string{$offset}) | 0x07) == 0xF7) { - // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & - ((ord($string{($offset + 1)}) & 0x3F) << 12) & - ((ord($string{($offset + 2)}) & 0x3F) << 6) & - (ord($string{($offset + 3)}) & 0x3F); - $offset += 4; - } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { - // 1110bbbb 10bbbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & - ((ord($string{($offset + 1)}) & 0x3F) << 6) & - (ord($string{($offset + 2)}) & 0x3F); - $offset += 3; - } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { - // 110bbbbb 10bbbbbb - $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & - (ord($string{($offset + 1)}) & 0x3F); - $offset += 2; - } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { - // 0bbbbbbb - $charval = ord($string{$offset}); - $offset += 1; - } else { - // error? maybe throw some warning here? - $charval = false; - $offset += 1; - } - if ($charval !== false) { - $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00"); - } - } - return $newcharstring; - } - - // UTF-8 => UTF-16LE (BOM) - public static function iconv_fallback_utf8_utf16($string) { - return self::iconv_fallback_utf8_utf16le($string, true); - } - - // UTF-16BE => UTF-8 - public static function iconv_fallback_utf16be_utf8($string) { - if (substr($string, 0, 2) == "\xFE\xFF") { - // strip BOM - $string = substr($string, 2); - } - $newcharstring = ''; - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::BigEndian2Int(substr($string, $i, 2)); - $newcharstring .= self::iconv_fallback_int_utf8($charval); - } - return $newcharstring; - } - - // UTF-16LE => UTF-8 - public static function iconv_fallback_utf16le_utf8($string) { - if (substr($string, 0, 2) == "\xFF\xFE") { - // strip BOM - $string = substr($string, 2); - } - $newcharstring = ''; - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::LittleEndian2Int(substr($string, $i, 2)); - $newcharstring .= self::iconv_fallback_int_utf8($charval); - } - return $newcharstring; - } - - // UTF-16BE => ISO-8859-1 - public static function iconv_fallback_utf16be_iso88591($string) { - if (substr($string, 0, 2) == "\xFE\xFF") { - // strip BOM - $string = substr($string, 2); - } - $newcharstring = ''; - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::BigEndian2Int(substr($string, $i, 2)); - $newcharstring .= (($charval < 256) ? chr($charval) : '?'); - } - return $newcharstring; - } - - // UTF-16LE => ISO-8859-1 - public static function iconv_fallback_utf16le_iso88591($string) { - if (substr($string, 0, 2) == "\xFF\xFE") { - // strip BOM - $string = substr($string, 2); - } - $newcharstring = ''; - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::LittleEndian2Int(substr($string, $i, 2)); - $newcharstring .= (($charval < 256) ? chr($charval) : '?'); - } - return $newcharstring; - } - - // UTF-16 (BOM) => ISO-8859-1 - public static function iconv_fallback_utf16_iso88591($string) { - $bom = substr($string, 0, 2); - if ($bom == "\xFE\xFF") { - return self::iconv_fallback_utf16be_iso88591(substr($string, 2)); - } elseif ($bom == "\xFF\xFE") { - return self::iconv_fallback_utf16le_iso88591(substr($string, 2)); - } - return $string; - } - - // UTF-16 (BOM) => UTF-8 - public static function iconv_fallback_utf16_utf8($string) { - $bom = substr($string, 0, 2); - if ($bom == "\xFE\xFF") { - return self::iconv_fallback_utf16be_utf8(substr($string, 2)); - } elseif ($bom == "\xFF\xFE") { - return self::iconv_fallback_utf16le_utf8(substr($string, 2)); - } - return $string; - } - - public static function iconv_fallback($in_charset, $out_charset, $string) { - - if ($in_charset == $out_charset) { - return $string; - } - - // iconv() availble - if (function_exists('iconv')) { - if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { - switch ($out_charset) { - case 'ISO-8859-1': - $converted_string = rtrim($converted_string, "\x00"); - break; - } - return $converted_string; - } - - // iconv() may sometimes fail with "illegal character in input string" error message - // and return an empty string, but returning the unconverted string is more useful - return $string; - } - - - // iconv() not available - static $ConversionFunctionList = array(); - if (empty($ConversionFunctionList)) { - $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8'; - $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16'; - $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be'; - $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le'; - $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591'; - $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16'; - $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be'; - $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le'; - $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591'; - $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8'; - $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591'; - $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8'; - $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591'; - $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8'; - } - if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) { - $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)]; - return self::$ConversionFunction($string); - } - throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); - } - - - public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') { - $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string - $HTMLstring = ''; - - switch ($charset) { - case '1251': - case '1252': - case '866': - case '932': - case '936': - case '950': - case 'BIG5': - case 'BIG5-HKSCS': - case 'cp1251': - case 'cp1252': - case 'cp866': - case 'EUC-JP': - case 'EUCJP': - case 'GB2312': - case 'ibm866': - case 'ISO-8859-1': - case 'ISO-8859-15': - case 'ISO8859-1': - case 'ISO8859-15': - case 'KOI8-R': - case 'koi8-ru': - case 'koi8r': - case 'Shift_JIS': - case 'SJIS': - case 'win-1251': - case 'Windows-1251': - case 'Windows-1252': - $HTMLstring = htmlentities($string, ENT_COMPAT, $charset); - break; - - case 'UTF-8': - $strlen = strlen($string); - for ($i = 0; $i < $strlen; $i++) { - $char_ord_val = ord($string{$i}); - $charval = 0; - if ($char_ord_val < 0x80) { - $charval = $char_ord_val; - } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { - $charval = (($char_ord_val & 0x07) << 18); - $charval += ((ord($string{++$i}) & 0x3F) << 12); - $charval += ((ord($string{++$i}) & 0x3F) << 6); - $charval += (ord($string{++$i}) & 0x3F); - } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { - $charval = (($char_ord_val & 0x0F) << 12); - $charval += ((ord($string{++$i}) & 0x3F) << 6); - $charval += (ord($string{++$i}) & 0x3F); - } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { - $charval = (($char_ord_val & 0x1F) << 6); - $charval += (ord($string{++$i}) & 0x3F); - } - if (($charval >= 32) && ($charval <= 127)) { - $HTMLstring .= htmlentities(chr($charval)); - } else { - $HTMLstring .= '&#'.$charval.';'; - } - } - break; - - case 'UTF-16LE': - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::LittleEndian2Int(substr($string, $i, 2)); - if (($charval >= 32) && ($charval <= 127)) { - $HTMLstring .= chr($charval); - } else { - $HTMLstring .= '&#'.$charval.';'; - } - } - break; - - case 'UTF-16BE': - for ($i = 0; $i < strlen($string); $i += 2) { - $charval = self::BigEndian2Int(substr($string, $i, 2)); - if (($charval >= 32) && ($charval <= 127)) { - $HTMLstring .= chr($charval); - } else { - $HTMLstring .= '&#'.$charval.';'; - } - } - break; - - default: - $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()'; - break; - } - return $HTMLstring; - } - - - - public static function RGADnameLookup($namecode) { - static $RGADname = array(); - if (empty($RGADname)) { - $RGADname[0] = 'not set'; - $RGADname[1] = 'Track Gain Adjustment'; - $RGADname[2] = 'Album Gain Adjustment'; - } - - return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); - } - - - public static function RGADoriginatorLookup($originatorcode) { - static $RGADoriginator = array(); - if (empty($RGADoriginator)) { - $RGADoriginator[0] = 'unspecified'; - $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer'; - $RGADoriginator[2] = 'set by user'; - $RGADoriginator[3] = 'determined automatically'; - } - - return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); - } - - - public static function RGADadjustmentLookup($rawadjustment, $signbit) { - $adjustment = $rawadjustment / 10; - if ($signbit == 1) { - $adjustment *= -1; - } - return (float) $adjustment; - } - - - public static function RGADgainString($namecode, $originatorcode, $replaygain) { - if ($replaygain < 0) { - $signbit = '1'; - } else { - $signbit = '0'; - } - $storedreplaygain = intval(round($replaygain * 10)); - $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT); - $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT); - $gainstring .= $signbit; - $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); - - return $gainstring; - } - - public static function RGADamplitude2dB($amplitude) { - return 20 * log10($amplitude); - } - - - public static function GetDataImageSize($imgData, &$imageinfo=array()) { - static $tempdir = ''; - if (empty($tempdir)) { - // yes this is ugly, feel free to suggest a better way - require_once(dirname(__FILE__).'/getid3.php'); - $getid3_temp = new getID3(); - $tempdir = $getid3_temp->tempdir; - unset($getid3_temp); - } - $GetDataImageSize = false; - if ($tempfilename = tempnam($tempdir, 'gI3')) { - if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) { - fwrite($tmp, $imgData); - fclose($tmp); - $GetDataImageSize = @getimagesize($tempfilename, $imageinfo); - } - unlink($tempfilename); - } - return $GetDataImageSize; - } - - public static function ImageExtFromMime($mime_type) { - // temporary way, works OK for now, but should be reworked in the future - return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type); - } - - public static function ImageTypesLookup($imagetypeid) { - static $ImageTypesLookup = array(); - if (empty($ImageTypesLookup)) { - $ImageTypesLookup[1] = 'gif'; - $ImageTypesLookup[2] = 'jpeg'; - $ImageTypesLookup[3] = 'png'; - $ImageTypesLookup[4] = 'swf'; - $ImageTypesLookup[5] = 'psd'; - $ImageTypesLookup[6] = 'bmp'; - $ImageTypesLookup[7] = 'tiff (little-endian)'; - $ImageTypesLookup[8] = 'tiff (big-endian)'; - $ImageTypesLookup[9] = 'jpc'; - $ImageTypesLookup[10] = 'jp2'; - $ImageTypesLookup[11] = 'jpx'; - $ImageTypesLookup[12] = 'jb2'; - $ImageTypesLookup[13] = 'swc'; - $ImageTypesLookup[14] = 'iff'; - } - return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : ''); - } - - public static function CopyTagsToComments(&$ThisFileInfo) { - - // Copy all entries from ['tags'] into common ['comments'] - if (!empty($ThisFileInfo['tags'])) { - foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { - foreach ($tagarray as $tagname => $tagdata) { - foreach ($tagdata as $key => $value) { - if (!empty($value)) { - if (empty($ThisFileInfo['comments'][$tagname])) { - - // fall through and append value - - } elseif ($tagtype == 'id3v1') { - - $newvaluelength = strlen(trim($value)); - foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { - $oldvaluelength = strlen(trim($existingvalue)); - if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) { - // new value is identical but shorter-than (or equal-length to) one already in comments - skip - break 2; - } - } - - } elseif (!is_array($value)) { - - $newvaluelength = strlen(trim($value)); - foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { - $oldvaluelength = strlen(trim($existingvalue)); - if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { - $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); - break 2; - } - } - - } - if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { - $value = (is_string($value) ? trim($value) : $value); - $ThisFileInfo['comments'][$tagname][] = $value; - } - } - } - } - } - - // Copy to ['comments_html'] - foreach ($ThisFileInfo['comments'] as $field => $values) { - if ($field == 'picture') { - // pictures can take up a lot of space, and we don't need multiple copies of them - // let there be a single copy in [comments][picture], and not elsewhere - continue; - } - foreach ($values as $index => $value) { - if (is_array($value)) { - $ThisFileInfo['comments_html'][$field][$index] = $value; - } else { - $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); - } - } - } - } - return true; - } - - - public static function EmbeddedLookup($key, $begin, $end, $file, $name) { - - // Cached - static $cache; - if (isset($cache[$file][$name])) { - return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); - } - - // Init - $keylength = strlen($key); - $line_count = $end - $begin - 7; - - // Open php file - $fp = fopen($file, 'r'); - - // Discard $begin lines - for ($i = 0; $i < ($begin + 3); $i++) { - fgets($fp, 1024); - } - - // Loop thru line - while (0 < $line_count--) { - - // Read line - $line = ltrim(fgets($fp, 1024), "\t "); - - // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key - //$keycheck = substr($line, 0, $keylength); - //if ($key == $keycheck) { - // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1); - // break; - //} - - // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key - //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1)); - $explodedLine = explode("\t", $line, 2); - $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : ''); - $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : ''); - $cache[$file][$name][$ThisKey] = trim($ThisValue); - } - - // Close and return - fclose($fp); - return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); - } - - public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) { - global $GETID3_ERRORARRAY; - - if (file_exists($filename)) { - if (include_once($filename)) { - return true; - } else { - $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors'; - } - } else { - $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing'; - } - if ($DieOnFailure) { - throw new Exception($diemessage); - } else { - $GETID3_ERRORARRAY[] = $diemessage; - } - return false; - } - - public static function trimNullByte($string) { - return trim($string, "\x00"); - } - - public static function getFileSizeSyscall($path) { - $filesize = false; - - if (GETID3_OS_ISWINDOWS) { - if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini: - $filesystem = new COM('Scripting.FileSystemObject'); - $file = $filesystem->GetFile($path); - $filesize = $file->Size(); - unset($filesystem, $file); - } else { - $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI'; - } - } else { - $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\''; - } - if (isset($commandline)) { - $output = trim(`$commandline`); - if (ctype_digit($output)) { - $filesize = (float) $output; - } - } - return $filesize; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// getid3.lib.php - part of getID3() // +// See readme.txt for more details // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_lib +{ + + public static function PrintHexBytes($string, $hex=true, $spaces=true, $htmlencoding='UTF-8') { + $returnstring = ''; + for ($i = 0; $i < strlen($string); $i++) { + if ($hex) { + $returnstring .= str_pad(dechex(ord($string{$i})), 2, '0', STR_PAD_LEFT); + } else { + $returnstring .= ' '.(preg_match("#[\x20-\x7E]#", $string{$i}) ? $string{$i} : '¤'); + } + if ($spaces) { + $returnstring .= ' '; + } + } + if (!empty($htmlencoding)) { + if ($htmlencoding === true) { + $htmlencoding = 'UTF-8'; // prior to getID3 v1.9.0 the function's 4th parameter was boolean + } + $returnstring = htmlentities($returnstring, ENT_QUOTES, $htmlencoding); + } + return $returnstring; + } + + public static function trunc($floatnumber) { + // truncates a floating-point number at the decimal point + // returns int (if possible, otherwise float) + if ($floatnumber >= 1) { + $truncatednumber = floor($floatnumber); + } elseif ($floatnumber <= -1) { + $truncatednumber = ceil($floatnumber); + } else { + $truncatednumber = 0; + } + if (self::intValueSupported($truncatednumber)) { + $truncatednumber = (int) $truncatednumber; + } + return $truncatednumber; + } + + + public static function safe_inc(&$variable, $increment=1) { + if (isset($variable)) { + $variable += $increment; + } else { + $variable = $increment; + } + return true; + } + + public static function CastAsInt($floatnum) { + // convert to float if not already + $floatnum = (float) $floatnum; + + // convert a float to type int, only if possible + if (self::trunc($floatnum) == $floatnum) { + // it's not floating point + if (self::intValueSupported($floatnum)) { + // it's within int range + $floatnum = (int) $floatnum; + } + } + return $floatnum; + } + + public static function intValueSupported($num) { + // check if integers are 64-bit + static $hasINT64 = null; + if ($hasINT64 === null) { // 10x faster than is_null() + $hasINT64 = is_int(pow(2, 31)); // 32-bit int are limited to (2^31)-1 + if (!$hasINT64 && !defined('PHP_INT_MIN')) { + define('PHP_INT_MIN', ~PHP_INT_MAX); + } + } + // if integers are 64-bit - no other check required + if ($hasINT64 || (($num <= PHP_INT_MAX) && ($num >= PHP_INT_MIN))) { + return true; + } + return false; + } + + public static function DecimalizeFraction($fraction) { + list($numerator, $denominator) = explode('/', $fraction); + return $numerator / ($denominator ? $denominator : 1); + } + + + public static function DecimalBinary2Float($binarynumerator) { + $numerator = self::Bin2Dec($binarynumerator); + $denominator = self::Bin2Dec('1'.str_repeat('0', strlen($binarynumerator))); + return ($numerator / $denominator); + } + + + public static function NormalizeBinaryPoint($binarypointnumber, $maxbits=52) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html + if (strpos($binarypointnumber, '.') === false) { + $binarypointnumber = '0.'.$binarypointnumber; + } elseif ($binarypointnumber{0} == '.') { + $binarypointnumber = '0'.$binarypointnumber; + } + $exponent = 0; + while (($binarypointnumber{0} != '1') || (substr($binarypointnumber, 1, 1) != '.')) { + if (substr($binarypointnumber, 1, 1) == '.') { + $exponent--; + $binarypointnumber = substr($binarypointnumber, 2, 1).'.'.substr($binarypointnumber, 3); + } else { + $pointpos = strpos($binarypointnumber, '.'); + $exponent += ($pointpos - 1); + $binarypointnumber = str_replace('.', '', $binarypointnumber); + $binarypointnumber = $binarypointnumber{0}.'.'.substr($binarypointnumber, 1); + } + } + $binarypointnumber = str_pad(substr($binarypointnumber, 0, $maxbits + 2), $maxbits + 2, '0', STR_PAD_RIGHT); + return array('normalized'=>$binarypointnumber, 'exponent'=>(int) $exponent); + } + + + public static function Float2BinaryDecimal($floatvalue) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/binary.html + $maxbits = 128; // to how many bits of precision should the calculations be taken? + $intpart = self::trunc($floatvalue); + $floatpart = abs($floatvalue - $intpart); + $pointbitstring = ''; + while (($floatpart != 0) && (strlen($pointbitstring) < $maxbits)) { + $floatpart *= 2; + $pointbitstring .= (string) self::trunc($floatpart); + $floatpart -= self::trunc($floatpart); + } + $binarypointnumber = decbin($intpart).'.'.$pointbitstring; + return $binarypointnumber; + } + + + public static function Float2String($floatvalue, $bits) { + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee-expl.html + switch ($bits) { + case 32: + $exponentbits = 8; + $fractionbits = 23; + break; + + case 64: + $exponentbits = 11; + $fractionbits = 52; + break; + + default: + return false; + break; + } + if ($floatvalue >= 0) { + $signbit = '0'; + } else { + $signbit = '1'; + } + $normalizedbinary = self::NormalizeBinaryPoint(self::Float2BinaryDecimal($floatvalue), $fractionbits); + $biasedexponent = pow(2, $exponentbits - 1) - 1 + $normalizedbinary['exponent']; // (127 or 1023) +/- exponent + $exponentbitstring = str_pad(decbin($biasedexponent), $exponentbits, '0', STR_PAD_LEFT); + $fractionbitstring = str_pad(substr($normalizedbinary['normalized'], 2), $fractionbits, '0', STR_PAD_RIGHT); + + return self::BigEndian2String(self::Bin2Dec($signbit.$exponentbitstring.$fractionbitstring), $bits % 8, false); + } + + + public static function LittleEndian2Float($byteword) { + return self::BigEndian2Float(strrev($byteword)); + } + + + public static function BigEndian2Float($byteword) { + // ANSI/IEEE Standard 754-1985, Standard for Binary Floating Point Arithmetic + // http://www.psc.edu/general/software/packages/ieee/ieee.html + // http://www.scri.fsu.edu/~jac/MAD3401/Backgrnd/ieee.html + + $bitword = self::BigEndian2Bin($byteword); + if (!$bitword) { + return 0; + } + $signbit = $bitword{0}; + + switch (strlen($byteword) * 8) { + case 32: + $exponentbits = 8; + $fractionbits = 23; + break; + + case 64: + $exponentbits = 11; + $fractionbits = 52; + break; + + case 80: + // 80-bit Apple SANE format + // http://www.mactech.com/articles/mactech/Vol.06/06.01/SANENormalized/ + $exponentstring = substr($bitword, 1, 15); + $isnormalized = intval($bitword{16}); + $fractionstring = substr($bitword, 17, 63); + $exponent = pow(2, self::Bin2Dec($exponentstring) - 16383); + $fraction = $isnormalized + self::DecimalBinary2Float($fractionstring); + $floatvalue = $exponent * $fraction; + if ($signbit == '1') { + $floatvalue *= -1; + } + return $floatvalue; + break; + + default: + return false; + break; + } + $exponentstring = substr($bitword, 1, $exponentbits); + $fractionstring = substr($bitword, $exponentbits + 1, $fractionbits); + $exponent = self::Bin2Dec($exponentstring); + $fraction = self::Bin2Dec($fractionstring); + + if (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction != 0)) { + // Not a Number + $floatvalue = false; + } elseif (($exponent == (pow(2, $exponentbits) - 1)) && ($fraction == 0)) { + if ($signbit == '1') { + $floatvalue = '-infinity'; + } else { + $floatvalue = '+infinity'; + } + } elseif (($exponent == 0) && ($fraction == 0)) { + if ($signbit == '1') { + $floatvalue = -0; + } else { + $floatvalue = 0; + } + $floatvalue = ($signbit ? 0 : -0); + } elseif (($exponent == 0) && ($fraction != 0)) { + // These are 'unnormalized' values + $floatvalue = pow(2, (-1 * (pow(2, $exponentbits - 1) - 2))) * self::DecimalBinary2Float($fractionstring); + if ($signbit == '1') { + $floatvalue *= -1; + } + } elseif ($exponent != 0) { + $floatvalue = pow(2, ($exponent - (pow(2, $exponentbits - 1) - 1))) * (1 + self::DecimalBinary2Float($fractionstring)); + if ($signbit == '1') { + $floatvalue *= -1; + } + } + return (float) $floatvalue; + } + + + public static function BigEndian2Int($byteword, $synchsafe=false, $signed=false) { + $intvalue = 0; + $bytewordlen = strlen($byteword); + if ($bytewordlen == 0) { + return false; + } + for ($i = 0; $i < $bytewordlen; $i++) { + if ($synchsafe) { // disregard MSB, effectively 7-bit bytes + //$intvalue = $intvalue | (ord($byteword{$i}) & 0x7F) << (($bytewordlen - 1 - $i) * 7); // faster, but runs into problems past 2^31 on 32-bit systems + $intvalue += (ord($byteword{$i}) & 0x7F) * pow(2, ($bytewordlen - 1 - $i) * 7); + } else { + $intvalue += ord($byteword{$i}) * pow(256, ($bytewordlen - 1 - $i)); + } + } + if ($signed && !$synchsafe) { + // synchsafe ints are not allowed to be signed + if ($bytewordlen <= PHP_INT_SIZE) { + $signMaskBit = 0x80 << (8 * ($bytewordlen - 1)); + if ($intvalue & $signMaskBit) { + $intvalue = 0 - ($intvalue & ($signMaskBit - 1)); + } + } else { + throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits ('.strlen($byteword).') in self::BigEndian2Int()'); + break; + } + } + return self::CastAsInt($intvalue); + } + + + public static function LittleEndian2Int($byteword, $signed=false) { + return self::BigEndian2Int(strrev($byteword), false, $signed); + } + + + public static function BigEndian2Bin($byteword) { + $binvalue = ''; + $bytewordlen = strlen($byteword); + for ($i = 0; $i < $bytewordlen; $i++) { + $binvalue .= str_pad(decbin(ord($byteword{$i})), 8, '0', STR_PAD_LEFT); + } + return $binvalue; + } + + + public static function BigEndian2String($number, $minbytes=1, $synchsafe=false, $signed=false) { + if ($number < 0) { + throw new Exception('ERROR: self::BigEndian2String() does not support negative numbers'); + } + $maskbyte = (($synchsafe || $signed) ? 0x7F : 0xFF); + $intstring = ''; + if ($signed) { + if ($minbytes > PHP_INT_SIZE) { + throw new Exception('ERROR: Cannot have signed integers larger than '.(8 * PHP_INT_SIZE).'-bits in self::BigEndian2String()'); + } + $number = $number & (0x80 << (8 * ($minbytes - 1))); + } + while ($number != 0) { + $quotient = ($number / ($maskbyte + 1)); + $intstring = chr(ceil(($quotient - floor($quotient)) * $maskbyte)).$intstring; + $number = floor($quotient); + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_LEFT); + } + + + public static function Dec2Bin($number) { + while ($number >= 256) { + $bytes[] = (($number / 256) - (floor($number / 256))) * 256; + $number = floor($number / 256); + } + $bytes[] = $number; + $binstring = ''; + for ($i = 0; $i < count($bytes); $i++) { + $binstring = (($i == count($bytes) - 1) ? decbin($bytes[$i]) : str_pad(decbin($bytes[$i]), 8, '0', STR_PAD_LEFT)).$binstring; + } + return $binstring; + } + + + public static function Bin2Dec($binstring, $signed=false) { + $signmult = 1; + if ($signed) { + if ($binstring{0} == '1') { + $signmult = -1; + } + $binstring = substr($binstring, 1); + } + $decvalue = 0; + for ($i = 0; $i < strlen($binstring); $i++) { + $decvalue += ((int) substr($binstring, strlen($binstring) - $i - 1, 1)) * pow(2, $i); + } + return self::CastAsInt($decvalue * $signmult); + } + + + public static function Bin2String($binstring) { + // return 'hi' for input of '0110100001101001' + $string = ''; + $binstringreversed = strrev($binstring); + for ($i = 0; $i < strlen($binstringreversed); $i += 8) { + $string = chr(self::Bin2Dec(strrev(substr($binstringreversed, $i, 8)))).$string; + } + return $string; + } + + + public static function LittleEndian2String($number, $minbytes=1, $synchsafe=false) { + $intstring = ''; + while ($number > 0) { + if ($synchsafe) { + $intstring = $intstring.chr($number & 127); + $number >>= 7; + } else { + $intstring = $intstring.chr($number & 255); + $number >>= 8; + } + } + return str_pad($intstring, $minbytes, "\x00", STR_PAD_RIGHT); + } + + + public static function array_merge_clobber($array1, $array2) { + // written by kcØhireability*com + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = self::array_merge_clobber($newarray[$key], $val); + } else { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + public static function array_merge_noclobber($array1, $array2) { + if (!is_array($array1) || !is_array($array2)) { + return false; + } + $newarray = $array1; + foreach ($array2 as $key => $val) { + if (is_array($val) && isset($newarray[$key]) && is_array($newarray[$key])) { + $newarray[$key] = self::array_merge_noclobber($newarray[$key], $val); + } elseif (!isset($newarray[$key])) { + $newarray[$key] = $val; + } + } + return $newarray; + } + + + public static function ksort_recursive(&$theArray) { + ksort($theArray); + foreach ($theArray as $key => $value) { + if (is_array($value)) { + self::ksort_recursive($theArray[$key]); + } + } + return true; + } + + public static function fileextension($filename, $numextensions=1) { + if (strstr($filename, '.')) { + $reversedfilename = strrev($filename); + $offset = 0; + for ($i = 0; $i < $numextensions; $i++) { + $offset = strpos($reversedfilename, '.', $offset + 1); + if ($offset === false) { + return ''; + } + } + return strrev(substr($reversedfilename, 0, $offset)); + } + return ''; + } + + + public static function PlaytimeString($seconds) { + $sign = (($seconds < 0) ? '-' : ''); + $seconds = round(abs($seconds)); + $H = (int) floor( $seconds / 3600); + $M = (int) floor(($seconds - (3600 * $H) ) / 60); + $S = (int) round( $seconds - (3600 * $H) - (60 * $M) ); + return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT); + } + + + public static function DateMac2Unix($macdate) { + // Macintosh timestamp: seconds since 00:00h January 1, 1904 + // UNIX timestamp: seconds since 00:00h January 1, 1970 + return self::CastAsInt($macdate - 2082844800); + } + + + public static function FixedPoint8_8($rawdata) { + return self::BigEndian2Int(substr($rawdata, 0, 1)) + (float) (self::BigEndian2Int(substr($rawdata, 1, 1)) / pow(2, 8)); + } + + + public static function FixedPoint16_16($rawdata) { + return self::BigEndian2Int(substr($rawdata, 0, 2)) + (float) (self::BigEndian2Int(substr($rawdata, 2, 2)) / pow(2, 16)); + } + + + public static function FixedPoint2_30($rawdata) { + $binarystring = self::BigEndian2Bin($rawdata); + return self::Bin2Dec(substr($binarystring, 0, 2)) + (float) (self::Bin2Dec(substr($binarystring, 2, 30)) / pow(2, 30)); + } + + + public static function CreateDeepArray($ArrayPath, $Separator, $Value) { + // assigns $Value to a nested array path: + // $foo = self::CreateDeepArray('/path/to/my', '/', 'file.txt') + // is the same as: + // $foo = array('path'=>array('to'=>'array('my'=>array('file.txt')))); + // or + // $foo['path']['to']['my'] = 'file.txt'; + $ArrayPath = ltrim($ArrayPath, $Separator); + if (($pos = strpos($ArrayPath, $Separator)) !== false) { + $ReturnedArray[substr($ArrayPath, 0, $pos)] = self::CreateDeepArray(substr($ArrayPath, $pos + 1), $Separator, $Value); + } else { + $ReturnedArray[$ArrayPath] = $Value; + } + return $ReturnedArray; + } + + public static function array_max($arraydata, $returnkey=false) { + $maxvalue = false; + $maxkey = false; + foreach ($arraydata as $key => $value) { + if (!is_array($value)) { + if ($value > $maxvalue) { + $maxvalue = $value; + $maxkey = $key; + } + } + } + return ($returnkey ? $maxkey : $maxvalue); + } + + public static function array_min($arraydata, $returnkey=false) { + $minvalue = false; + $minkey = false; + foreach ($arraydata as $key => $value) { + if (!is_array($value)) { + if ($value > $minvalue) { + $minvalue = $value; + $minkey = $key; + } + } + } + return ($returnkey ? $minkey : $minvalue); + } + + public static function XML2array($XMLstring) { + if (function_exists('simplexml_load_string')) { + if (function_exists('get_object_vars')) { + $XMLobject = simplexml_load_string($XMLstring); + return self::SimpleXMLelement2array($XMLobject); + } + } + return false; + } + + public static function SimpleXMLelement2array($XMLobject) { + if (!is_object($XMLobject) && !is_array($XMLobject)) { + return $XMLobject; + } + $XMLarray = (is_object($XMLobject) ? get_object_vars($XMLobject) : $XMLobject); + foreach ($XMLarray as $key => $value) { + $XMLarray[$key] = self::SimpleXMLelement2array($value); + } + return $XMLarray; + } + + + // Allan Hansen + // self::md5_data() - returns md5sum for a file from startuing position to absolute end position + public static function hash_data($file, $offset, $end, $algorithm) { + static $tempdir = ''; + if (!self::intValueSupported($end)) { + return false; + } + switch ($algorithm) { + case 'md5': + $hash_function = 'md5_file'; + $unix_call = 'md5sum'; + $windows_call = 'md5sum.exe'; + $hash_length = 32; + break; + + case 'sha1': + $hash_function = 'sha1_file'; + $unix_call = 'sha1sum'; + $windows_call = 'sha1sum.exe'; + $hash_length = 40; + break; + + default: + throw new Exception('Invalid algorithm ('.$algorithm.') in self::hash_data()'); + break; + } + $size = $end - $offset; + while (true) { + if (GETID3_OS_ISWINDOWS) { + + // It seems that sha1sum.exe for Windows only works on physical files, does not accept piped data + // Fall back to create-temp-file method: + if ($algorithm == 'sha1') { + break; + } + + $RequiredFiles = array('cygwin1.dll', 'head.exe', 'tail.exe', $windows_call); + foreach ($RequiredFiles as $required_file) { + if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { + // helper apps not available - fall back to old method + break 2; + } + } + $commandline = GETID3_HELPERAPPSDIR.'head.exe -c '.$end.' '.escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $file)).' | '; + $commandline .= GETID3_HELPERAPPSDIR.'tail.exe -c '.$size.' | '; + $commandline .= GETID3_HELPERAPPSDIR.$windows_call; + + } else { + + $commandline = 'head -c'.$end.' '.escapeshellarg($file).' | '; + $commandline .= 'tail -c'.$size.' | '; + $commandline .= $unix_call; + + } + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + //throw new Exception('PHP running in Safe Mode - backtick operator not available, using slower non-system-call '.$algorithm.' algorithm'); + break; + } + return substr(`$commandline`, 0, $hash_length); + } + + if (empty($tempdir)) { + // yes this is ugly, feel free to suggest a better way + require_once(dirname(__FILE__).'/getid3.php'); + $getid3_temp = new getID3(); + $tempdir = $getid3_temp->tempdir; + unset($getid3_temp); + } + // try to create a temporary file in the system temp directory - invalid dirname should force to system temp dir + if (($data_filename = tempnam($tempdir, 'gI3')) === false) { + // can't find anywhere to create a temp file, just fail + return false; + } + + // Init + $result = false; + + // copy parts of file + try { + self::CopyFileParts($file, $data_filename, $offset, $end - $offset); + $result = $hash_function($data_filename); + } catch (Exception $e) { + throw new Exception('self::CopyFileParts() failed in getid_lib::hash_data(): '.$e->getMessage()); + } + unlink($data_filename); + return $result; + } + + public static function CopyFileParts($filename_source, $filename_dest, $offset, $length) { + if (!self::intValueSupported($offset + $length)) { + throw new Exception('cannot copy file portion, it extends beyond the '.round(PHP_INT_MAX / 1073741824).'GB limit'); + } + if (is_readable($filename_source) && is_file($filename_source) && ($fp_src = fopen($filename_source, 'rb'))) { + if (($fp_dest = fopen($filename_dest, 'wb'))) { + if (fseek($fp_src, $offset, SEEK_SET) == 0) { + $byteslefttowrite = $length; + while (($byteslefttowrite > 0) && ($buffer = fread($fp_src, min($byteslefttowrite, getID3::FREAD_BUFFER_SIZE)))) { + $byteswritten = fwrite($fp_dest, $buffer, $byteslefttowrite); + $byteslefttowrite -= $byteswritten; + } + return true; + } else { + throw new Exception('failed to seek to offset '.$offset.' in '.$filename_source); + } + fclose($fp_dest); + } else { + throw new Exception('failed to create file for writing '.$filename_dest); + } + fclose($fp_src); + } else { + throw new Exception('failed to open file for reading '.$filename_source); + } + return false; + } + + public static function iconv_fallback_int_utf8($charval) { + if ($charval < 128) { + // 0bbbbbbb + $newcharstring = chr($charval); + } elseif ($charval < 2048) { + // 110bbbbb 10bbbbbb + $newcharstring = chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } elseif ($charval < 65536) { + // 1110bbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 12) | 0xE0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } else { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $newcharstring = chr(($charval >> 18) | 0xF0); + $newcharstring .= chr(($charval >> 12) | 0xC0); + $newcharstring .= chr(($charval >> 6) | 0xC0); + $newcharstring .= chr(($charval & 0x3F) | 0x80); + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-8 + public static function iconv_fallback_iso88591_utf8($string, $bom=false) { + if (function_exists('utf8_encode')) { + return utf8_encode($string); + } + // utf8_encode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xEF\xBB\xBF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $charval = ord($string{$i}); + $newcharstring .= self::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16BE + public static function iconv_fallback_iso88591_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= "\x00".$string{$i}; + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16LE + public static function iconv_fallback_iso88591_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + for ($i = 0; $i < strlen($string); $i++) { + $newcharstring .= $string{$i}."\x00"; + } + return $newcharstring; + } + + // ISO-8859-1 => UTF-16LE (BOM) + public static function iconv_fallback_iso88591_utf16($string) { + return self::iconv_fallback_iso88591_utf16le($string, true); + } + + // UTF-8 => ISO-8859-1 + public static function iconv_fallback_utf8_iso88591($string) { + if (function_exists('utf8_decode')) { + return utf8_decode($string); + } + // utf8_decode() unavailable, use getID3()'s iconv_fallback() conversions (possibly PHP is compiled without XML support) + $newcharstring = ''; + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16BE + public static function iconv_fallback_utf8_utf16be($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFE\xFF"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? throw some kind of warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? self::BigEndian2String($charval, 2) : "\x00".'?'); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16LE + public static function iconv_fallback_utf8_utf16le($string, $bom=false) { + $newcharstring = ''; + if ($bom) { + $newcharstring .= "\xFF\xFE"; + } + $offset = 0; + $stringlength = strlen($string); + while ($offset < $stringlength) { + if ((ord($string{$offset}) | 0x07) == 0xF7) { + // 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x07) << 18) & + ((ord($string{($offset + 1)}) & 0x3F) << 12) & + ((ord($string{($offset + 2)}) & 0x3F) << 6) & + (ord($string{($offset + 3)}) & 0x3F); + $offset += 4; + } elseif ((ord($string{$offset}) | 0x0F) == 0xEF) { + // 1110bbbb 10bbbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x0F) << 12) & + ((ord($string{($offset + 1)}) & 0x3F) << 6) & + (ord($string{($offset + 2)}) & 0x3F); + $offset += 3; + } elseif ((ord($string{$offset}) | 0x1F) == 0xDF) { + // 110bbbbb 10bbbbbb + $charval = ((ord($string{($offset + 0)}) & 0x1F) << 6) & + (ord($string{($offset + 1)}) & 0x3F); + $offset += 2; + } elseif ((ord($string{$offset}) | 0x7F) == 0x7F) { + // 0bbbbbbb + $charval = ord($string{$offset}); + $offset += 1; + } else { + // error? maybe throw some warning here? + $charval = false; + $offset += 1; + } + if ($charval !== false) { + $newcharstring .= (($charval < 65536) ? self::LittleEndian2String($charval, 2) : '?'."\x00"); + } + } + return $newcharstring; + } + + // UTF-8 => UTF-16LE (BOM) + public static function iconv_fallback_utf8_utf16($string) { + return self::iconv_fallback_utf8_utf16le($string, true); + } + + // UTF-16BE => UTF-8 + public static function iconv_fallback_utf16be_utf8($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= self::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // UTF-16LE => UTF-8 + public static function iconv_fallback_utf16le_utf8($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= self::iconv_fallback_int_utf8($charval); + } + return $newcharstring; + } + + // UTF-16BE => ISO-8859-1 + public static function iconv_fallback_utf16be_iso88591($string) { + if (substr($string, 0, 2) == "\xFE\xFF") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::BigEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + // UTF-16LE => ISO-8859-1 + public static function iconv_fallback_utf16le_iso88591($string) { + if (substr($string, 0, 2) == "\xFF\xFE") { + // strip BOM + $string = substr($string, 2); + } + $newcharstring = ''; + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::LittleEndian2Int(substr($string, $i, 2)); + $newcharstring .= (($charval < 256) ? chr($charval) : '?'); + } + return $newcharstring; + } + + // UTF-16 (BOM) => ISO-8859-1 + public static function iconv_fallback_utf16_iso88591($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return self::iconv_fallback_utf16be_iso88591(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return self::iconv_fallback_utf16le_iso88591(substr($string, 2)); + } + return $string; + } + + // UTF-16 (BOM) => UTF-8 + public static function iconv_fallback_utf16_utf8($string) { + $bom = substr($string, 0, 2); + if ($bom == "\xFE\xFF") { + return self::iconv_fallback_utf16be_utf8(substr($string, 2)); + } elseif ($bom == "\xFF\xFE") { + return self::iconv_fallback_utf16le_utf8(substr($string, 2)); + } + return $string; + } + + public static function iconv_fallback($in_charset, $out_charset, $string) { + + if ($in_charset == $out_charset) { + return $string; + } + + // iconv() availble + if (function_exists('iconv')) { + if ($converted_string = @iconv($in_charset, $out_charset.'//TRANSLIT', $string)) { + switch ($out_charset) { + case 'ISO-8859-1': + $converted_string = rtrim($converted_string, "\x00"); + break; + } + return $converted_string; + } + + // iconv() may sometimes fail with "illegal character in input string" error message + // and return an empty string, but returning the unconverted string is more useful + return $string; + } + + + // iconv() not available + static $ConversionFunctionList = array(); + if (empty($ConversionFunctionList)) { + $ConversionFunctionList['ISO-8859-1']['UTF-8'] = 'iconv_fallback_iso88591_utf8'; + $ConversionFunctionList['ISO-8859-1']['UTF-16'] = 'iconv_fallback_iso88591_utf16'; + $ConversionFunctionList['ISO-8859-1']['UTF-16BE'] = 'iconv_fallback_iso88591_utf16be'; + $ConversionFunctionList['ISO-8859-1']['UTF-16LE'] = 'iconv_fallback_iso88591_utf16le'; + $ConversionFunctionList['UTF-8']['ISO-8859-1'] = 'iconv_fallback_utf8_iso88591'; + $ConversionFunctionList['UTF-8']['UTF-16'] = 'iconv_fallback_utf8_utf16'; + $ConversionFunctionList['UTF-8']['UTF-16BE'] = 'iconv_fallback_utf8_utf16be'; + $ConversionFunctionList['UTF-8']['UTF-16LE'] = 'iconv_fallback_utf8_utf16le'; + $ConversionFunctionList['UTF-16']['ISO-8859-1'] = 'iconv_fallback_utf16_iso88591'; + $ConversionFunctionList['UTF-16']['UTF-8'] = 'iconv_fallback_utf16_utf8'; + $ConversionFunctionList['UTF-16LE']['ISO-8859-1'] = 'iconv_fallback_utf16le_iso88591'; + $ConversionFunctionList['UTF-16LE']['UTF-8'] = 'iconv_fallback_utf16le_utf8'; + $ConversionFunctionList['UTF-16BE']['ISO-8859-1'] = 'iconv_fallback_utf16be_iso88591'; + $ConversionFunctionList['UTF-16BE']['UTF-8'] = 'iconv_fallback_utf16be_utf8'; + } + if (isset($ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)])) { + $ConversionFunction = $ConversionFunctionList[strtoupper($in_charset)][strtoupper($out_charset)]; + return self::$ConversionFunction($string); + } + throw new Exception('PHP does not have iconv() support - cannot convert from '.$in_charset.' to '.$out_charset); + } + + + public static function MultiByteCharString2HTML($string, $charset='ISO-8859-1') { + $string = (string) $string; // in case trying to pass a numeric (float, int) string, would otherwise return an empty string + $HTMLstring = ''; + + switch ($charset) { + case '1251': + case '1252': + case '866': + case '932': + case '936': + case '950': + case 'BIG5': + case 'BIG5-HKSCS': + case 'cp1251': + case 'cp1252': + case 'cp866': + case 'EUC-JP': + case 'EUCJP': + case 'GB2312': + case 'ibm866': + case 'ISO-8859-1': + case 'ISO-8859-15': + case 'ISO8859-1': + case 'ISO8859-15': + case 'KOI8-R': + case 'koi8-ru': + case 'koi8r': + case 'Shift_JIS': + case 'SJIS': + case 'win-1251': + case 'Windows-1251': + case 'Windows-1252': + $HTMLstring = htmlentities($string, ENT_COMPAT, $charset); + break; + + case 'UTF-8': + $strlen = strlen($string); + for ($i = 0; $i < $strlen; $i++) { + $char_ord_val = ord($string{$i}); + $charval = 0; + if ($char_ord_val < 0x80) { + $charval = $char_ord_val; + } elseif ((($char_ord_val & 0xF0) >> 4) == 0x0F && $i+3 < $strlen) { + $charval = (($char_ord_val & 0x07) << 18); + $charval += ((ord($string{++$i}) & 0x3F) << 12); + $charval += ((ord($string{++$i}) & 0x3F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } elseif ((($char_ord_val & 0xE0) >> 5) == 0x07 && $i+2 < $strlen) { + $charval = (($char_ord_val & 0x0F) << 12); + $charval += ((ord($string{++$i}) & 0x3F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } elseif ((($char_ord_val & 0xC0) >> 6) == 0x03 && $i+1 < $strlen) { + $charval = (($char_ord_val & 0x1F) << 6); + $charval += (ord($string{++$i}) & 0x3F); + } + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= htmlentities(chr($charval)); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + case 'UTF-16LE': + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::LittleEndian2Int(substr($string, $i, 2)); + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= chr($charval); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + case 'UTF-16BE': + for ($i = 0; $i < strlen($string); $i += 2) { + $charval = self::BigEndian2Int(substr($string, $i, 2)); + if (($charval >= 32) && ($charval <= 127)) { + $HTMLstring .= chr($charval); + } else { + $HTMLstring .= '&#'.$charval.';'; + } + } + break; + + default: + $HTMLstring = 'ERROR: Character set "'.$charset.'" not supported in MultiByteCharString2HTML()'; + break; + } + return $HTMLstring; + } + + + + public static function RGADnameLookup($namecode) { + static $RGADname = array(); + if (empty($RGADname)) { + $RGADname[0] = 'not set'; + $RGADname[1] = 'Track Gain Adjustment'; + $RGADname[2] = 'Album Gain Adjustment'; + } + + return (isset($RGADname[$namecode]) ? $RGADname[$namecode] : ''); + } + + + public static function RGADoriginatorLookup($originatorcode) { + static $RGADoriginator = array(); + if (empty($RGADoriginator)) { + $RGADoriginator[0] = 'unspecified'; + $RGADoriginator[1] = 'pre-set by artist/producer/mastering engineer'; + $RGADoriginator[2] = 'set by user'; + $RGADoriginator[3] = 'determined automatically'; + } + + return (isset($RGADoriginator[$originatorcode]) ? $RGADoriginator[$originatorcode] : ''); + } + + + public static function RGADadjustmentLookup($rawadjustment, $signbit) { + $adjustment = $rawadjustment / 10; + if ($signbit == 1) { + $adjustment *= -1; + } + return (float) $adjustment; + } + + + public static function RGADgainString($namecode, $originatorcode, $replaygain) { + if ($replaygain < 0) { + $signbit = '1'; + } else { + $signbit = '0'; + } + $storedreplaygain = intval(round($replaygain * 10)); + $gainstring = str_pad(decbin($namecode), 3, '0', STR_PAD_LEFT); + $gainstring .= str_pad(decbin($originatorcode), 3, '0', STR_PAD_LEFT); + $gainstring .= $signbit; + $gainstring .= str_pad(decbin($storedreplaygain), 9, '0', STR_PAD_LEFT); + + return $gainstring; + } + + public static function RGADamplitude2dB($amplitude) { + return 20 * log10($amplitude); + } + + + public static function GetDataImageSize($imgData, &$imageinfo=array()) { + static $tempdir = ''; + if (empty($tempdir)) { + // yes this is ugly, feel free to suggest a better way + require_once(dirname(__FILE__).'/getid3.php'); + $getid3_temp = new getID3(); + $tempdir = $getid3_temp->tempdir; + unset($getid3_temp); + } + $GetDataImageSize = false; + if ($tempfilename = tempnam($tempdir, 'gI3')) { + if (is_writable($tempfilename) && is_file($tempfilename) && ($tmp = fopen($tempfilename, 'wb'))) { + fwrite($tmp, $imgData); + fclose($tmp); + $GetDataImageSize = @getimagesize($tempfilename, $imageinfo); + } + unlink($tempfilename); + } + return $GetDataImageSize; + } + + public static function ImageExtFromMime($mime_type) { + // temporary way, works OK for now, but should be reworked in the future + return str_replace(array('image/', 'x-', 'jpeg'), array('', '', 'jpg'), $mime_type); + } + + public static function ImageTypesLookup($imagetypeid) { + static $ImageTypesLookup = array(); + if (empty($ImageTypesLookup)) { + $ImageTypesLookup[1] = 'gif'; + $ImageTypesLookup[2] = 'jpeg'; + $ImageTypesLookup[3] = 'png'; + $ImageTypesLookup[4] = 'swf'; + $ImageTypesLookup[5] = 'psd'; + $ImageTypesLookup[6] = 'bmp'; + $ImageTypesLookup[7] = 'tiff (little-endian)'; + $ImageTypesLookup[8] = 'tiff (big-endian)'; + $ImageTypesLookup[9] = 'jpc'; + $ImageTypesLookup[10] = 'jp2'; + $ImageTypesLookup[11] = 'jpx'; + $ImageTypesLookup[12] = 'jb2'; + $ImageTypesLookup[13] = 'swc'; + $ImageTypesLookup[14] = 'iff'; + } + return (isset($ImageTypesLookup[$imagetypeid]) ? $ImageTypesLookup[$imagetypeid] : ''); + } + + public static function CopyTagsToComments(&$ThisFileInfo) { + + // Copy all entries from ['tags'] into common ['comments'] + if (!empty($ThisFileInfo['tags'])) { + foreach ($ThisFileInfo['tags'] as $tagtype => $tagarray) { + foreach ($tagarray as $tagname => $tagdata) { + foreach ($tagdata as $key => $value) { + if (!empty($value)) { + if (empty($ThisFileInfo['comments'][$tagname])) { + + // fall through and append value + + } elseif ($tagtype == 'id3v1') { + + $newvaluelength = strlen(trim($value)); + foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { + $oldvaluelength = strlen(trim($existingvalue)); + if (($newvaluelength <= $oldvaluelength) && (substr($existingvalue, 0, $newvaluelength) == trim($value))) { + // new value is identical but shorter-than (or equal-length to) one already in comments - skip + break 2; + } + } + + } elseif (!is_array($value)) { + + $newvaluelength = strlen(trim($value)); + foreach ($ThisFileInfo['comments'][$tagname] as $existingkey => $existingvalue) { + $oldvaluelength = strlen(trim($existingvalue)); + if (($newvaluelength > $oldvaluelength) && (substr(trim($value), 0, strlen($existingvalue)) == $existingvalue)) { + $ThisFileInfo['comments'][$tagname][$existingkey] = trim($value); + break 2; + } + } + + } + if (is_array($value) || empty($ThisFileInfo['comments'][$tagname]) || !in_array(trim($value), $ThisFileInfo['comments'][$tagname])) { + $value = (is_string($value) ? trim($value) : $value); + $ThisFileInfo['comments'][$tagname][] = $value; + } + } + } + } + } + + // Copy to ['comments_html'] + foreach ($ThisFileInfo['comments'] as $field => $values) { + if ($field == 'picture') { + // pictures can take up a lot of space, and we don't need multiple copies of them + // let there be a single copy in [comments][picture], and not elsewhere + continue; + } + foreach ($values as $index => $value) { + if (is_array($value)) { + $ThisFileInfo['comments_html'][$field][$index] = $value; + } else { + $ThisFileInfo['comments_html'][$field][$index] = str_replace('�', '', self::MultiByteCharString2HTML($value, $ThisFileInfo['encoding'])); + } + } + } + } + return true; + } + + + public static function EmbeddedLookup($key, $begin, $end, $file, $name) { + + // Cached + static $cache; + if (isset($cache[$file][$name])) { + return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); + } + + // Init + $keylength = strlen($key); + $line_count = $end - $begin - 7; + + // Open php file + $fp = fopen($file, 'r'); + + // Discard $begin lines + for ($i = 0; $i < ($begin + 3); $i++) { + fgets($fp, 1024); + } + + // Loop thru line + while (0 < $line_count--) { + + // Read line + $line = ltrim(fgets($fp, 1024), "\t "); + + // METHOD A: only cache the matching key - less memory but slower on next lookup of not-previously-looked-up key + //$keycheck = substr($line, 0, $keylength); + //if ($key == $keycheck) { + // $cache[$file][$name][$keycheck] = substr($line, $keylength + 1); + // break; + //} + + // METHOD B: cache all keys in this lookup - more memory but faster on next lookup of not-previously-looked-up key + //$cache[$file][$name][substr($line, 0, $keylength)] = trim(substr($line, $keylength + 1)); + $explodedLine = explode("\t", $line, 2); + $ThisKey = (isset($explodedLine[0]) ? $explodedLine[0] : ''); + $ThisValue = (isset($explodedLine[1]) ? $explodedLine[1] : ''); + $cache[$file][$name][$ThisKey] = trim($ThisValue); + } + + // Close and return + fclose($fp); + return (isset($cache[$file][$name][$key]) ? $cache[$file][$name][$key] : ''); + } + + public static function IncludeDependency($filename, $sourcefile, $DieOnFailure=false) { + global $GETID3_ERRORARRAY; + + if (file_exists($filename)) { + if (include_once($filename)) { + return true; + } else { + $diemessage = basename($sourcefile).' depends on '.$filename.', which has errors'; + } + } else { + $diemessage = basename($sourcefile).' depends on '.$filename.', which is missing'; + } + if ($DieOnFailure) { + throw new Exception($diemessage); + } else { + $GETID3_ERRORARRAY[] = $diemessage; + } + return false; + } + + public static function trimNullByte($string) { + return trim($string, "\x00"); + } + + public static function getFileSizeSyscall($path) { + $filesize = false; + + if (GETID3_OS_ISWINDOWS) { + if (class_exists('COM')) { // From PHP 5.3.15 and 5.4.5, COM and DOTNET is no longer built into the php core.you have to add COM support in php.ini: + $filesystem = new COM('Scripting.FileSystemObject'); + $file = $filesystem->GetFile($path); + $filesize = $file->Size(); + unset($filesystem, $file); + } else { + $commandline = 'for %I in ('.escapeshellarg($path).') do @echo %~zI'; + } + } else { + $commandline = 'ls -l '.escapeshellarg($path).' | awk \'{print $5}\''; + } + if (isset($commandline)) { + $output = trim(`$commandline`); + if (ctype_digit($output)) { + $filesize = (float) $output; + } + } + return $filesize; + } + +} diff --git a/app/libs/vendor/getid3/getid3.php b/app/libs/vendor/getid3/getid3.php index 1699966d..454829ce 100644 --- a/app/libs/vendor/getid3/getid3.php +++ b/app/libs/vendor/getid3/getid3.php @@ -1,1776 +1,1776 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// // -// Please see readme.txt for more information // -// /// -///////////////////////////////////////////////////////////////// - -// define a constant rather than looking up every time it is needed -if (!defined('GETID3_OS_ISWINDOWS')) { - define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0)); -} -// Get base path of getID3() - ONCE -if (!defined('GETID3_INCLUDEPATH')) { - define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); -} - -// attempt to define temp dir as something flexible but reliable -$temp_dir = ini_get('upload_tmp_dir'); -if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { - $temp_dir = ''; -} -if (!$temp_dir && function_exists('sys_get_temp_dir')) { - // PHP v5.2.1+ - // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts - $temp_dir = sys_get_temp_dir(); -} -$temp_dir = realpath($temp_dir); -$open_basedir = ini_get('open_basedir'); -if ($open_basedir) { - // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/" - $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir); - $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir); - if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) { - $temp_dir .= DIRECTORY_SEPARATOR; - } - $found_valid_tempdir = false; - $open_basedirs = explode(PATH_SEPARATOR, $open_basedir); - foreach ($open_basedirs as $basedir) { - if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) { - $basedir .= DIRECTORY_SEPARATOR; - } - if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) { - $found_valid_tempdir = true; - break; - } - } - if (!$found_valid_tempdir) { - $temp_dir = ''; - } - unset($open_basedirs, $found_valid_tempdir, $basedir); -} -if (!$temp_dir) { - $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir -} -// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system -define('GETID3_TEMP_DIR', $temp_dir); -unset($open_basedir, $temp_dir); - -// End: Defines - - -class getID3 -{ - // public: Settings - public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE - public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252' - - // public: Optional tag checks - disable for speed. - public $option_tag_id3v1 = true; // Read and process ID3v1 tags - public $option_tag_id3v2 = true; // Read and process ID3v2 tags - public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags - public $option_tag_apetag = true; // Read and process APE tags - public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding - public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities - - // public: Optional tag/comment calucations - public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc - - // public: Optional handling of embedded attachments (e.g. images) - public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility - - // public: Optional calculations - public $option_md5_data = false; // Get MD5 sum of data part - slow - public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG - public $option_sha1_data = false; // Get SHA1 sum of data part - slow - public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX) - - // public: Read buffer size in bytes - public $option_fread_buffer_size = 32768; - - // Public variables - public $filename; // Filename of file being analysed. - public $fp; // Filepointer to file being analysed. - public $info; // Result array. - public $tempdir = GETID3_TEMP_DIR; - - // Protected variables - protected $startup_error = ''; - protected $startup_warning = ''; - protected $memory_limit = 0; - - const VERSION = '1.9.7-20130705'; - const FREAD_BUFFER_SIZE = 32768; - - const ATTACHMENTS_NONE = false; - const ATTACHMENTS_INLINE = true; - - // public: constructor - public function __construct() { - - // Check for PHP version - $required_php_version = '5.0.5'; - if (version_compare(PHP_VERSION, $required_php_version, '<')) { - $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION; - return false; - } - - // Check memory - $this->memory_limit = ini_get('memory_limit'); - if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) { - // could be stored as "16M" rather than 16777216 for example - $this->memory_limit = $matches[1] * 1048576; - } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0 - // could be stored as "2G" rather than 2147483648 for example - $this->memory_limit = $matches[1] * 1073741824; - } - if ($this->memory_limit <= 0) { - // memory limits probably disabled - } elseif ($this->memory_limit <= 4194304) { - $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'; - } elseif ($this->memory_limit <= 12582912) { - $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'; - } - - // Check safe_mode off - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); - } - - if (intval(ini_get('mbstring.func_overload')) > 0) { - $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.'); - } - - // Check for magic_quotes_runtime - if (function_exists('get_magic_quotes_runtime')) { - if (get_magic_quotes_runtime()) { - return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'); - } - } - - // Check for magic_quotes_gpc - if (function_exists('magic_quotes_gpc')) { - if (get_magic_quotes_gpc()) { - return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'); - } - } - - // Load support library - if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { - $this->startup_error .= 'getid3.lib.php is missing or corrupt'; - } - - if ($this->option_max_2gb_check === null) { - $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647); - } - - - // Needed for Windows only: - // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC - // as well as other helper functions such as head, tail, md5sum, etc - // This path cannot contain spaces, but the below code will attempt to get the - // 8.3-equivalent path automatically - // IMPORTANT: This path must include the trailing slash - if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) { - - $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path - - if (!is_dir($helperappsdir)) { - $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'; - } elseif (strpos(realpath($helperappsdir), ' ') !== false) { - $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); - $path_so_far = array(); - foreach ($DirPieces as $key => $value) { - if (strpos($value, ' ') !== false) { - if (!empty($path_so_far)) { - $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far)); - $dir_listing = `$commandline`; - $lines = explode("\n", $dir_listing); - foreach ($lines as $line) { - $line = trim($line); - if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) { - list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches; - if ((strtoupper($filesize) == '') && (strtolower($filename) == strtolower($value))) { - $value = $shortname; - } - } - } - } else { - $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.'; - } - } - $path_so_far[] = $value; - } - $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far); - } - define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR); - } - - return true; - } - - public function version() { - return self::VERSION; - } - - public function fread_buffer_size() { - return $this->option_fread_buffer_size; - } - - - // public: setOption - public function setOption($optArray) { - if (!is_array($optArray) || empty($optArray)) { - return false; - } - foreach ($optArray as $opt => $val) { - if (isset($this->$opt) === false) { - continue; - } - $this->$opt = $val; - } - return true; - } - - - public function openfile($filename) { - try { - if (!empty($this->startup_error)) { - throw new getid3_exception($this->startup_error); - } - if (!empty($this->startup_warning)) { - $this->warning($this->startup_warning); - } - - // init result array and set parameters - $this->filename = $filename; - $this->info = array(); - $this->info['GETID3_VERSION'] = $this->version(); - $this->info['php_memory_limit'] = $this->memory_limit; - - // remote files not supported - if (preg_match('/^(ht|f)tp:\/\//', $filename)) { - throw new getid3_exception('Remote files are not supported - please copy the file locally first'); - } - - $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); - $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename); - - // open local file - if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { - // great - } else { - throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)'); - } - - $this->info['filesize'] = filesize($filename); - // set redundant parameters - might be needed in some include file - $this->info['filename'] = basename($filename); - $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); - $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; - - - // option_max_2gb_check - if ($this->option_max_2gb_check) { - // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB) - // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize - // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer - $fseek = fseek($this->fp, 0, SEEK_END); - if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) || - ($this->info['filesize'] < 0) || - (ftell($this->fp) < 0)) { - $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']); - - if ($real_filesize === false) { - unset($this->info['filesize']); - fclose($this->fp); - throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.'); - } elseif (getid3_lib::intValueSupported($real_filesize)) { - unset($this->info['filesize']); - fclose($this->fp); - throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org'); - } - $this->info['filesize'] = $real_filesize; - $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.'); - } - } - - // set more parameters - $this->info['avdataoffset'] = 0; - $this->info['avdataend'] = $this->info['filesize']; - $this->info['fileformat'] = ''; // filled in later - $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used - $this->info['video']['dataformat'] = ''; // filled in later, unset if not used - $this->info['tags'] = array(); // filled in later, unset if not used - $this->info['error'] = array(); // filled in later, unset if not used - $this->info['warning'] = array(); // filled in later, unset if not used - $this->info['comments'] = array(); // filled in later, unset if not used - $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired - - return true; - - } catch (Exception $e) { - $this->error($e->getMessage()); - } - return false; - } - - // public: analyze file - public function analyze($filename) { - try { - if (!$this->openfile($filename)) { - return $this->info; - } - - // Handle tags - foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) { - $option_tag = 'option_tag_'.$tag_name; - if ($this->$option_tag) { - $this->include_module('tag.'.$tag_name); - try { - $tag_class = 'getid3_'.$tag_name; - $tag = new $tag_class($this); - $tag->Analyze(); - } - catch (getid3_exception $e) { - throw $e; - } - } - } - if (isset($this->info['id3v2']['tag_offset_start'])) { - $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']); - } - foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) { - if (isset($this->info[$tag_key]['tag_offset_start'])) { - $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']); - } - } - - // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier - if (!$this->option_tag_id3v2) { - fseek($this->fp, 0, SEEK_SET); - $header = fread($this->fp, 10); - if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { - $this->info['id3v2']['header'] = true; - $this->info['id3v2']['majorversion'] = ord($header{3}); - $this->info['id3v2']['minorversion'] = ord($header{4}); - $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length - } - } - - // read 32 kb file data - fseek($this->fp, $this->info['avdataoffset'], SEEK_SET); - $formattest = fread($this->fp, 32774); - - // determine format - $determined_format = $this->GetFileFormat($formattest, $filename); - - // unable to determine file format - if (!$determined_format) { - fclose($this->fp); - return $this->error('unable to determine file format'); - } - - // check for illegal ID3 tags - if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) { - if ($determined_format['fail_id3'] === 'ERROR') { - fclose($this->fp); - return $this->error('ID3 tags not allowed on this file type.'); - } elseif ($determined_format['fail_id3'] === 'WARNING') { - $this->warning('ID3 tags not allowed on this file type.'); - } - } - - // check for illegal APE tags - if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) { - if ($determined_format['fail_ape'] === 'ERROR') { - fclose($this->fp); - return $this->error('APE tags not allowed on this file type.'); - } elseif ($determined_format['fail_ape'] === 'WARNING') { - $this->warning('APE tags not allowed on this file type.'); - } - } - - // set mime type - $this->info['mime_type'] = $determined_format['mime_type']; - - // supported format signature pattern detected, but module deleted - if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) { - fclose($this->fp); - return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.'); - } - - // module requires iconv support - // Check encoding/iconv support - if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { - $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; - if (GETID3_OS_ISWINDOWS) { - $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32'; - } else { - $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch'; - } - return $this->error($errormessage); - } - - // include module - include_once(GETID3_INCLUDEPATH.$determined_format['include']); - - // instantiate module class - $class_name = 'getid3_'.$determined_format['module']; - if (!class_exists($class_name)) { - return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.'); - } - $class = new $class_name($this); - $class->Analyze(); - unset($class); - - // close file - fclose($this->fp); - - // process all tags - copy to 'tags' and convert charsets - if ($this->option_tags_process) { - $this->HandleAllTags(); - } - - // perform more calculations - if ($this->option_extra_info) { - $this->ChannelsBitratePlaytimeCalculations(); - $this->CalculateCompressionRatioVideo(); - $this->CalculateCompressionRatioAudio(); - $this->CalculateReplayGain(); - $this->ProcessAudioStreams(); - } - - // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags - if ($this->option_md5_data) { - // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too - if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) { - $this->getHashdata('md5'); - } - } - - // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags - if ($this->option_sha1_data) { - $this->getHashdata('sha1'); - } - - // remove undesired keys - $this->CleanUp(); - - } catch (Exception $e) { - $this->error('Caught exception: '.$e->getMessage()); - } - - // return info array - return $this->info; - } - - - // private: error handling - public function error($message) { - $this->CleanUp(); - if (!isset($this->info['error'])) { - $this->info['error'] = array(); - } - $this->info['error'][] = $message; - return $this->info; - } - - - // private: warning handling - public function warning($message) { - $this->info['warning'][] = $message; - return true; - } - - - // private: CleanUp - private function CleanUp() { - - // remove possible empty keys - $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate'); - foreach ($AVpossibleEmptyKeys as $dummy => $key) { - if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) { - unset($this->info['audio'][$key]); - } - if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) { - unset($this->info['video'][$key]); - } - } - - // remove empty root keys - if (!empty($this->info)) { - foreach ($this->info as $key => $value) { - if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) { - unset($this->info[$key]); - } - } - } - - // remove meaningless entries from unknown-format files - if (empty($this->info['fileformat'])) { - if (isset($this->info['avdataoffset'])) { - unset($this->info['avdataoffset']); - } - if (isset($this->info['avdataend'])) { - unset($this->info['avdataend']); - } - } - - // remove possible duplicated identical entries - if (!empty($this->info['error'])) { - $this->info['error'] = array_values(array_unique($this->info['error'])); - } - if (!empty($this->info['warning'])) { - $this->info['warning'] = array_values(array_unique($this->info['warning'])); - } - - // remove "global variable" type keys - unset($this->info['php_memory_limit']); - - return true; - } - - - // return array containing information about all supported formats - public function GetFileFormatArray() { - static $format_info = array(); - if (empty($format_info)) { - $format_info = array( - - // Audio formats - - // AC-3 - audio - Dolby AC-3 / Dolby Digital - 'ac3' => array( - 'pattern' => '^\x0B\x77', - 'group' => 'audio', - 'module' => 'ac3', - 'mime_type' => 'audio/ac3', - ), - - // AAC - audio - Advanced Audio Coding (AAC) - ADIF format - 'adif' => array( - 'pattern' => '^ADIF', - 'group' => 'audio', - 'module' => 'aac', - 'mime_type' => 'application/octet-stream', - 'fail_ape' => 'WARNING', - ), - -/* - // AA - audio - Audible Audiobook - 'aa' => array( - 'pattern' => '^.{4}\x57\x90\x75\x36', - 'group' => 'audio', - 'module' => 'aa', - 'mime_type' => 'audio/audible', - ), -*/ - // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) - 'adts' => array( - 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', - 'group' => 'audio', - 'module' => 'aac', - 'mime_type' => 'application/octet-stream', - 'fail_ape' => 'WARNING', - ), - - - // AU - audio - NeXT/Sun AUdio (AU) - 'au' => array( - 'pattern' => '^\.snd', - 'group' => 'audio', - 'module' => 'au', - 'mime_type' => 'audio/basic', - ), - - // AVR - audio - Audio Visual Research - 'avr' => array( - 'pattern' => '^2BIT', - 'group' => 'audio', - 'module' => 'avr', - 'mime_type' => 'application/octet-stream', - ), - - // BONK - audio - Bonk v0.9+ - 'bonk' => array( - 'pattern' => '^\x00(BONK|INFO|META| ID3)', - 'group' => 'audio', - 'module' => 'bonk', - 'mime_type' => 'audio/xmms-bonk', - ), - - // DSS - audio - Digital Speech Standard - 'dss' => array( - 'pattern' => '^[\x02-\x03]ds[s2]', - 'group' => 'audio', - 'module' => 'dss', - 'mime_type' => 'application/octet-stream', - ), - - // DTS - audio - Dolby Theatre System - 'dts' => array( - 'pattern' => '^\x7F\xFE\x80\x01', - 'group' => 'audio', - 'module' => 'dts', - 'mime_type' => 'audio/dts', - ), - - // FLAC - audio - Free Lossless Audio Codec - 'flac' => array( - 'pattern' => '^fLaC', - 'group' => 'audio', - 'module' => 'flac', - 'mime_type' => 'audio/x-flac', - ), - - // LA - audio - Lossless Audio (LA) - 'la' => array( - 'pattern' => '^LA0[2-4]', - 'group' => 'audio', - 'module' => 'la', - 'mime_type' => 'application/octet-stream', - ), - - // LPAC - audio - Lossless Predictive Audio Compression (LPAC) - 'lpac' => array( - 'pattern' => '^LPAC', - 'group' => 'audio', - 'module' => 'lpac', - 'mime_type' => 'application/octet-stream', - ), - - // MIDI - audio - MIDI (Musical Instrument Digital Interface) - 'midi' => array( - 'pattern' => '^MThd', - 'group' => 'audio', - 'module' => 'midi', - 'mime_type' => 'audio/midi', - ), - - // MAC - audio - Monkey's Audio Compressor - 'mac' => array( - 'pattern' => '^MAC ', - 'group' => 'audio', - 'module' => 'monkey', - 'mime_type' => 'application/octet-stream', - ), - -// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available -// // MOD - audio - MODule (assorted sub-formats) -// 'mod' => array( -// 'pattern' => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)', -// 'group' => 'audio', -// 'module' => 'mod', -// 'option' => 'mod', -// 'mime_type' => 'audio/mod', -// ), - - // MOD - audio - MODule (Impulse Tracker) - 'it' => array( - 'pattern' => '^IMPM', - 'group' => 'audio', - 'module' => 'mod', - //'option' => 'it', - 'mime_type' => 'audio/it', - ), - - // MOD - audio - MODule (eXtended Module, various sub-formats) - 'xm' => array( - 'pattern' => '^Extended Module', - 'group' => 'audio', - 'module' => 'mod', - //'option' => 'xm', - 'mime_type' => 'audio/xm', - ), - - // MOD - audio - MODule (ScreamTracker) - 's3m' => array( - 'pattern' => '^.{44}SCRM', - 'group' => 'audio', - 'module' => 'mod', - //'option' => 's3m', - 'mime_type' => 'audio/s3m', - ), - - // MPC - audio - Musepack / MPEGplus - 'mpc' => array( - 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])', - 'group' => 'audio', - 'module' => 'mpc', - 'mime_type' => 'audio/x-musepack', - ), - - // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) - 'mp3' => array( - 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]', - 'group' => 'audio', - 'module' => 'mp3', - 'mime_type' => 'audio/mpeg', - ), - - // OFR - audio - OptimFROG - 'ofr' => array( - 'pattern' => '^(\*RIFF|OFR)', - 'group' => 'audio', - 'module' => 'optimfrog', - 'mime_type' => 'application/octet-stream', - ), - - // RKAU - audio - RKive AUdio compressor - 'rkau' => array( - 'pattern' => '^RKA', - 'group' => 'audio', - 'module' => 'rkau', - 'mime_type' => 'application/octet-stream', - ), - - // SHN - audio - Shorten - 'shn' => array( - 'pattern' => '^ajkg', - 'group' => 'audio', - 'module' => 'shorten', - 'mime_type' => 'audio/xmms-shn', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) - 'tta' => array( - 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' - 'group' => 'audio', - 'module' => 'tta', - 'mime_type' => 'application/octet-stream', - ), - - // VOC - audio - Creative Voice (VOC) - 'voc' => array( - 'pattern' => '^Creative Voice File', - 'group' => 'audio', - 'module' => 'voc', - 'mime_type' => 'audio/voc', - ), - - // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) - 'vqf' => array( - 'pattern' => '^TWIN', - 'group' => 'audio', - 'module' => 'vqf', - 'mime_type' => 'application/octet-stream', - ), - - // WV - audio - WavPack (v4.0+) - 'wv' => array( - 'pattern' => '^wvpk', - 'group' => 'audio', - 'module' => 'wavpack', - 'mime_type' => 'application/octet-stream', - ), - - - // Audio-Video formats - - // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio - 'asf' => array( - 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', - 'group' => 'audio-video', - 'module' => 'asf', - 'mime_type' => 'video/x-ms-asf', - 'iconv_req' => false, - ), - - // BINK - audio/video - Bink / Smacker - 'bink' => array( - 'pattern' => '^(BIK|SMK)', - 'group' => 'audio-video', - 'module' => 'bink', - 'mime_type' => 'application/octet-stream', - ), - - // FLV - audio/video - FLash Video - 'flv' => array( - 'pattern' => '^FLV\x01', - 'group' => 'audio-video', - 'module' => 'flv', - 'mime_type' => 'video/x-flv', - ), - - // MKAV - audio/video - Mastroka - 'matroska' => array( - 'pattern' => '^\x1A\x45\xDF\xA3', - 'group' => 'audio-video', - 'module' => 'matroska', - 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska - ), - - // MPEG - audio/video - MPEG (Moving Pictures Experts Group) - 'mpeg' => array( - 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', - 'group' => 'audio-video', - 'module' => 'mpeg', - 'mime_type' => 'video/mpeg', - ), - - // NSV - audio/video - Nullsoft Streaming Video (NSV) - 'nsv' => array( - 'pattern' => '^NSV[sf]', - 'group' => 'audio-video', - 'module' => 'nsv', - 'mime_type' => 'application/octet-stream', - ), - - // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*)) - 'ogg' => array( - 'pattern' => '^OggS', - 'group' => 'audio', - 'module' => 'ogg', - 'mime_type' => 'application/ogg', - 'fail_id3' => 'WARNING', - 'fail_ape' => 'WARNING', - ), - - // QT - audio/video - Quicktime - 'quicktime' => array( - 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', - 'group' => 'audio-video', - 'module' => 'quicktime', - 'mime_type' => 'video/quicktime', - ), - - // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF) - 'riff' => array( - 'pattern' => '^(RIFF|SDSS|FORM)', - 'group' => 'audio-video', - 'module' => 'riff', - 'mime_type' => 'audio/x-wave', - 'fail_ape' => 'WARNING', - ), - - // Real - audio/video - RealAudio, RealVideo - 'real' => array( - 'pattern' => '^(\\.RMF|\\.ra)', - 'group' => 'audio-video', - 'module' => 'real', - 'mime_type' => 'audio/x-realaudio', - ), - - // SWF - audio/video - ShockWave Flash - 'swf' => array( - 'pattern' => '^(F|C)WS', - 'group' => 'audio-video', - 'module' => 'swf', - 'mime_type' => 'application/x-shockwave-flash', - ), - - // TS - audio/video - MPEG-2 Transport Stream - 'ts' => array( - 'pattern' => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern - 'group' => 'audio-video', - 'module' => 'ts', - 'mime_type' => 'video/MP2T', - ), - - - // Still-Image formats - - // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) - 'bmp' => array( - 'pattern' => '^BM', - 'group' => 'graphic', - 'module' => 'bmp', - 'mime_type' => 'image/bmp', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // GIF - still image - Graphics Interchange Format - 'gif' => array( - 'pattern' => '^GIF', - 'group' => 'graphic', - 'module' => 'gif', - 'mime_type' => 'image/gif', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // JPEG - still image - Joint Photographic Experts Group (JPEG) - 'jpg' => array( - 'pattern' => '^\xFF\xD8\xFF', - 'group' => 'graphic', - 'module' => 'jpg', - 'mime_type' => 'image/jpeg', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // PCD - still image - Kodak Photo CD - 'pcd' => array( - 'pattern' => '^.{2048}PCD_IPI\x00', - 'group' => 'graphic', - 'module' => 'pcd', - 'mime_type' => 'image/x-photo-cd', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // PNG - still image - Portable Network Graphics (PNG) - 'png' => array( - 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', - 'group' => 'graphic', - 'module' => 'png', - 'mime_type' => 'image/png', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // SVG - still image - Scalable Vector Graphics (SVG) - 'svg' => array( - 'pattern' => '( 'graphic', - 'module' => 'svg', - 'mime_type' => 'image/svg+xml', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // TIFF - still image - Tagged Information File Format (TIFF) - 'tiff' => array( - 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', - 'group' => 'graphic', - 'module' => 'tiff', - 'mime_type' => 'image/tiff', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // EFAX - still image - eFax (TIFF derivative) - 'efax' => array( - 'pattern' => '^\xDC\xFE', - 'group' => 'graphic', - 'module' => 'efax', - 'mime_type' => 'image/efax', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // Data formats - - // ISO - data - International Standards Organization (ISO) CD-ROM Image - 'iso' => array( - 'pattern' => '^.{32769}CD001', - 'group' => 'misc', - 'module' => 'iso', - 'mime_type' => 'application/octet-stream', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - 'iconv_req' => false, - ), - - // RAR - data - RAR compressed data - 'rar' => array( - 'pattern' => '^Rar\!', - 'group' => 'archive', - 'module' => 'rar', - 'mime_type' => 'application/octet-stream', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // SZIP - audio/data - SZIP compressed data - 'szip' => array( - 'pattern' => '^SZ\x0A\x04', - 'group' => 'archive', - 'module' => 'szip', - 'mime_type' => 'application/octet-stream', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // TAR - data - TAR compressed data - 'tar' => array( - 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}', - 'group' => 'archive', - 'module' => 'tar', - 'mime_type' => 'application/x-tar', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // GZIP - data - GZIP compressed data - 'gz' => array( - 'pattern' => '^\x1F\x8B\x08', - 'group' => 'archive', - 'module' => 'gzip', - 'mime_type' => 'application/x-gzip', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // ZIP - data - ZIP compressed data - 'zip' => array( - 'pattern' => '^PK\x03\x04', - 'group' => 'archive', - 'module' => 'zip', - 'mime_type' => 'application/zip', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - - // Misc other formats - - // PAR2 - data - Parity Volume Set Specification 2.0 - 'par2' => array ( - 'pattern' => '^PAR2\x00PKT', - 'group' => 'misc', - 'module' => 'par2', - 'mime_type' => 'application/octet-stream', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // PDF - data - Portable Document Format - 'pdf' => array( - 'pattern' => '^\x25PDF', - 'group' => 'misc', - 'module' => 'pdf', - 'mime_type' => 'application/pdf', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // MSOFFICE - data - ZIP compressed data - 'msoffice' => array( - 'pattern' => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document - 'group' => 'misc', - 'module' => 'msoffice', - 'mime_type' => 'application/octet-stream', - 'fail_id3' => 'ERROR', - 'fail_ape' => 'ERROR', - ), - - // CUE - data - CUEsheet (index to single-file disc images) - 'cue' => array( - 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents - 'group' => 'misc', - 'module' => 'cue', - 'mime_type' => 'application/octet-stream', - ), - - ); - } - - return $format_info; - } - - - - public function GetFileFormat(&$filedata, $filename='') { - // this function will determine the format of a file based on usually - // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, - // and in the case of ISO CD image, 6 bytes offset 32kb from the start - // of the file). - - // Identify file format - loop through $format_info and detect with reg expr - foreach ($this->GetFileFormatArray() as $format_name => $info) { - // The /s switch on preg_match() forces preg_match() NOT to treat - // newline (0x0A) characters as special chars but do a binary match - if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) { - $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; - return $info; - } - } - - - if (preg_match('#\.mp[123a]$#i', $filename)) { - // Too many mp3 encoders on the market put gabage in front of mpeg files - // use assume format on these if format detection failed - $GetFileFormatArray = $this->GetFileFormatArray(); - $info = $GetFileFormatArray['mp3']; - $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; - return $info; - } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) { - // there's not really a useful consistent "magic" at the beginning of .cue files to identify them - // so until I think of something better, just go by filename if all other format checks fail - // and verify there's at least one instance of "TRACK xx AUDIO" in the file - $GetFileFormatArray = $this->GetFileFormatArray(); - $info = $GetFileFormatArray['cue']; - $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; - return $info; - } - - return false; - } - - - // converts array to $encoding charset from $this->encoding - public function CharConvert(&$array, $encoding) { - - // identical encoding - end here - if ($encoding == $this->encoding) { - return; - } - - // loop thru array - foreach ($array as $key => $value) { - - // go recursive - if (is_array($value)) { - $this->CharConvert($array[$key], $encoding); - } - - // convert string - elseif (is_string($value)) { - $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value)); - } - } - } - - - public function HandleAllTags() { - - // key name => array (tag name, character encoding) - static $tags; - if (empty($tags)) { - $tags = array( - 'asf' => array('asf' , 'UTF-16LE'), - 'midi' => array('midi' , 'ISO-8859-1'), - 'nsv' => array('nsv' , 'ISO-8859-1'), - 'ogg' => array('vorbiscomment' , 'UTF-8'), - 'png' => array('png' , 'UTF-8'), - 'tiff' => array('tiff' , 'ISO-8859-1'), - 'quicktime' => array('quicktime' , 'UTF-8'), - 'real' => array('real' , 'ISO-8859-1'), - 'vqf' => array('vqf' , 'ISO-8859-1'), - 'zip' => array('zip' , 'ISO-8859-1'), - 'riff' => array('riff' , 'ISO-8859-1'), - 'lyrics3' => array('lyrics3' , 'ISO-8859-1'), - 'id3v1' => array('id3v1' , $this->encoding_id3v1), - 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8 - 'ape' => array('ape' , 'UTF-8'), - 'cue' => array('cue' , 'ISO-8859-1'), - 'matroska' => array('matroska' , 'UTF-8'), - 'flac' => array('vorbiscomment' , 'UTF-8'), - 'divxtag' => array('divx' , 'ISO-8859-1'), - ); - } - - // loop through comments array - foreach ($tags as $comment_name => $tagname_encoding_array) { - list($tag_name, $encoding) = $tagname_encoding_array; - - // fill in default encoding type if not already present - if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) { - $this->info[$comment_name]['encoding'] = $encoding; - } - - // copy comments if key name set - if (!empty($this->info[$comment_name]['comments'])) { - foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) { - foreach ($valuearray as $key => $value) { - if (is_string($value)) { - $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! - } - if ($value) { - $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; - } - } - if ($tag_key == 'picture') { - unset($this->info[$comment_name]['comments'][$tag_key]); - } - } - - if (!isset($this->info['tags'][$tag_name])) { - // comments are set but contain nothing but empty strings, so skip - continue; - } - - if ($this->option_tags_html) { - foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { - foreach ($valuearray as $key => $value) { - if (is_string($value)) { - //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); - $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding))); - } else { - $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; - } - } - } - } - - $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! - } - - } - - // pictures can take up a lot of space, and we don't need multiple copies of them - // let there be a single copy in [comments][picture], and not elsewhere - if (!empty($this->info['tags'])) { - $unset_keys = array('tags', 'tags_html'); - foreach ($this->info['tags'] as $tagtype => $tagarray) { - foreach ($tagarray as $tagname => $tagdata) { - if ($tagname == 'picture') { - foreach ($tagdata as $key => $tagarray) { - $this->info['comments']['picture'][] = $tagarray; - if (isset($tagarray['data']) && isset($tagarray['image_mime'])) { - if (isset($this->info['tags'][$tagtype][$tagname][$key])) { - unset($this->info['tags'][$tagtype][$tagname][$key]); - } - if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) { - unset($this->info['tags_html'][$tagtype][$tagname][$key]); - } - } - } - } - } - foreach ($unset_keys as $unset_key) { - // remove possible empty keys from (e.g. [tags][id3v2][picture]) - if (empty($this->info[$unset_key][$tagtype]['picture'])) { - unset($this->info[$unset_key][$tagtype]['picture']); - } - if (empty($this->info[$unset_key][$tagtype])) { - unset($this->info[$unset_key][$tagtype]); - } - if (empty($this->info[$unset_key])) { - unset($this->info[$unset_key]); - } - } - // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture]) - if (isset($this->info[$tagtype]['comments']['picture'])) { - unset($this->info[$tagtype]['comments']['picture']); - } - if (empty($this->info[$tagtype]['comments'])) { - unset($this->info[$tagtype]['comments']); - } - if (empty($this->info[$tagtype])) { - unset($this->info[$tagtype]); - } - } - } - return true; - } - - - public function getHashdata($algorithm) { - switch ($algorithm) { - case 'md5': - case 'sha1': - break; - - default: - return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); - break; - } - - if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) { - - // We cannot get an identical md5_data value for Ogg files where the comments - // span more than 1 Ogg page (compared to the same audio data with smaller - // comments) using the normal getID3() method of MD5'ing the data between the - // end of the comments and the end of the file (minus any trailing tags), - // because the page sequence numbers of the pages that the audio data is on - // do not match. Under normal circumstances, where comments are smaller than - // the nominal 4-8kB page size, then this is not a problem, but if there are - // very large comments, the only way around it is to strip off the comment - // tags with vorbiscomment and MD5 that file. - // This procedure must be applied to ALL Ogg files, not just the ones with - // comments larger than 1 page, because the below method simply MD5's the - // whole file with the comments stripped, not just the portion after the - // comments block (which is the standard getID3() method. - - // The above-mentioned problem of comments spanning multiple pages and changing - // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but - // currently vorbiscomment only works on OggVorbis files. - - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - - $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'); - $this->info[$algorithm.'_data'] = false; - - } else { - - // Prevent user from aborting script - $old_abort = ignore_user_abort(true); - - // Create empty file - $empty = tempnam(GETID3_TEMP_DIR, 'getID3'); - touch($empty); - - // Use vorbiscomment to make temp file without comments - $temp = tempnam(GETID3_TEMP_DIR, 'getID3'); - $file = $this->info['filenamepath']; - - if (GETID3_OS_ISWINDOWS) { - - if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { - - $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; - $VorbisCommentError = `$commandline`; - - } else { - - $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; - - } - - } else { - - $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; - $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; - $VorbisCommentError = `$commandline`; - - } - - if (!empty($VorbisCommentError)) { - - $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; - $this->info[$algorithm.'_data'] = false; - - } else { - - // Get hash of newly created file - switch ($algorithm) { - case 'md5': - $this->info[$algorithm.'_data'] = md5_file($temp); - break; - - case 'sha1': - $this->info[$algorithm.'_data'] = sha1_file($temp); - break; - } - } - - // Clean up - unlink($empty); - unlink($temp); - - // Reset abort setting - ignore_user_abort($old_abort); - - } - - } else { - - if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) { - - // get hash from part of file - $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm); - - } else { - - // get hash from whole file - switch ($algorithm) { - case 'md5': - $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']); - break; - - case 'sha1': - $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']); - break; - } - } - - } - return true; - } - - - public function ChannelsBitratePlaytimeCalculations() { - - // set channelmode on audio - if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) { - // ignore - } elseif ($this->info['audio']['channels'] == 1) { - $this->info['audio']['channelmode'] = 'mono'; - } elseif ($this->info['audio']['channels'] == 2) { - $this->info['audio']['channelmode'] = 'stereo'; - } - - // Calculate combined bitrate - audio + video - $CombinedBitrate = 0; - $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); - $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); - if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { - $this->info['bitrate'] = $CombinedBitrate; - } - //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) { - // // for example, VBR MPEG video files cannot determine video bitrate: - // // should not set overall bitrate and playtime from audio bitrate only - // unset($this->info['bitrate']); - //} - - // video bitrate undetermined, but calculable - if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) { - // if video bitrate not set - if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) { - // AND if audio bitrate is set to same as overall bitrate - if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) { - // AND if playtime is set - if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) { - // AND if AV data offset start/end is known - // THEN we can calculate the video bitrate - $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']); - $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate']; - } - } - } - } - - if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) { - $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; - } - - if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) { - $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']; - } - if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) { - if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) { - // audio only - $this->info['audio']['bitrate'] = $this->info['bitrate']; - } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) { - // video only - $this->info['video']['bitrate'] = $this->info['bitrate']; - } - } - - // Set playtime string - if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { - $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); - } - } - - - public function CalculateCompressionRatioVideo() { - if (empty($this->info['video'])) { - return false; - } - if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) { - return false; - } - if (empty($this->info['video']['bits_per_sample'])) { - return false; - } - - switch ($this->info['video']['dataformat']) { - case 'bmp': - case 'gif': - case 'jpeg': - case 'jpg': - case 'png': - case 'tiff': - $FrameRate = 1; - $PlaytimeSeconds = 1; - $BitrateCompressed = $this->info['filesize'] * 8; - break; - - default: - if (!empty($this->info['video']['frame_rate'])) { - $FrameRate = $this->info['video']['frame_rate']; - } else { - return false; - } - if (!empty($this->info['playtime_seconds'])) { - $PlaytimeSeconds = $this->info['playtime_seconds']; - } else { - return false; - } - if (!empty($this->info['video']['bitrate'])) { - $BitrateCompressed = $this->info['video']['bitrate']; - } else { - return false; - } - break; - } - $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; - - $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; - return true; - } - - - public function CalculateCompressionRatioAudio() { - if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) { - return false; - } - $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); - - if (!empty($this->info['audio']['streams'])) { - foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { - if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) { - $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16)); - } - } - } - return true; - } - - - public function CalculateReplayGain() { - if (isset($this->info['replay_gain'])) { - if (!isset($this->info['replay_gain']['reference_volume'])) { - $this->info['replay_gain']['reference_volume'] = (double) 89.0; - } - if (isset($this->info['replay_gain']['track']['adjustment'])) { - $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; - } - if (isset($this->info['replay_gain']['album']['adjustment'])) { - $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; - } - - if (isset($this->info['replay_gain']['track']['peak'])) { - $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); - } - if (isset($this->info['replay_gain']['album']['peak'])) { - $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); - } - } - return true; - } - - public function ProcessAudioStreams() { - if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { - if (!isset($this->info['audio']['streams'])) { - foreach ($this->info['audio'] as $key => $value) { - if ($key != 'streams') { - $this->info['audio']['streams'][0][$key] = $value; - } - } - } - } - return true; - } - - public function getid3_tempnam() { - return tempnam($this->tempdir, 'gI3'); - } - - public function include_module($name) { - //if (!file_exists($this->include_path.'module.'.$name.'.php')) { - if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) { - throw new getid3_exception('Required module.'.$name.'.php is missing.'); - } - include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php'); - return true; - } - -} - - -abstract class getid3_handler -{ - protected $getid3; // pointer - - protected $data_string_flag = false; // analyzing filepointer or string - protected $data_string = ''; // string to analyze - protected $data_string_position = 0; // seek position in string - protected $data_string_length = 0; // string length - - private $dependency_to = null; - - - public function __construct(getID3 $getid3, $call_module=null) { - $this->getid3 = $getid3; - - if ($call_module) { - $this->dependency_to = str_replace('getid3_', '', $call_module); - } - } - - - // Analyze from file pointer - abstract public function Analyze(); - - - // Analyze from string instead - public function AnalyzeString($string) { - // Enter string mode - $this->setStringMode($string); - - // Save info - $saved_avdataoffset = $this->getid3->info['avdataoffset']; - $saved_avdataend = $this->getid3->info['avdataend']; - $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call - - // Reset some info - $this->getid3->info['avdataoffset'] = 0; - $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length; - - // Analyze - $this->Analyze(); - - // Restore some info - $this->getid3->info['avdataoffset'] = $saved_avdataoffset; - $this->getid3->info['avdataend'] = $saved_avdataend; - $this->getid3->info['filesize'] = $saved_filesize; - - // Exit string mode - $this->data_string_flag = false; - } - - public function setStringMode($string) { - $this->data_string_flag = true; - $this->data_string = $string; - $this->data_string_length = strlen($string); - } - - protected function ftell() { - if ($this->data_string_flag) { - return $this->data_string_position; - } - return ftell($this->getid3->fp); - } - - protected function fread($bytes) { - if ($this->data_string_flag) { - $this->data_string_position += $bytes; - return substr($this->data_string, $this->data_string_position - $bytes, $bytes); - } - $pos = $this->ftell() + $bytes; - if (!getid3_lib::intValueSupported($pos)) { - throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10); - } - return fread($this->getid3->fp, $bytes); - } - - protected function fseek($bytes, $whence=SEEK_SET) { - if ($this->data_string_flag) { - switch ($whence) { - case SEEK_SET: - $this->data_string_position = $bytes; - break; - - case SEEK_CUR: - $this->data_string_position += $bytes; - break; - - case SEEK_END: - $this->data_string_position = $this->data_string_length + $bytes; - break; - } - return 0; - } else { - $pos = $bytes; - if ($whence == SEEK_CUR) { - $pos = $this->ftell() + $bytes; - } elseif ($whence == SEEK_END) { - $pos = $this->info['filesize'] + $bytes; - } - if (!getid3_lib::intValueSupported($pos)) { - throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); - } - } - return fseek($this->getid3->fp, $bytes, $whence); - } - - protected function feof() { - if ($this->data_string_flag) { - return $this->data_string_position >= $this->data_string_length; - } - return feof($this->getid3->fp); - } - - final protected function isDependencyFor($module) { - return $this->dependency_to == $module; - } - - protected function error($text) - { - $this->getid3->info['error'][] = $text; - - return false; - } - - protected function warning($text) - { - return $this->getid3->warning($text); - } - - protected function notice($text) - { - // does nothing for now - } - - public function saveAttachment($name, $offset, $length, $image_mime=null) { - try { - - // do not extract at all - if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) { - - $attachment = null; // do not set any - - // extract to return array - } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) { - - $this->fseek($offset); - $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory - if ($attachment === false || strlen($attachment) != $length) { - throw new Exception('failed to read attachment data'); - } - - // assume directory path is given - } else { - - // set up destination path - $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); - if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory - throw new Exception('supplied path ('.$dir.') does not exist, or is not writable'); - } - $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : ''); - - // create dest file - if (($fp_dest = fopen($dest, 'wb')) == false) { - throw new Exception('failed to create file '.$dest); - } - - // copy data - $this->fseek($offset); - $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size()); - $bytesleft = $length; - while ($bytesleft > 0) { - if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) { - throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space'); - } - $bytesleft -= $byteswritten; - } - - fclose($fp_dest); - $attachment = $dest; - - } - - } catch (Exception $e) { - - // close and remove dest file if created - if (isset($fp_dest) && is_resource($fp_dest)) { - fclose($fp_dest); - unlink($dest); - } - - // do not set any is case of error - $attachment = null; - $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage()); - - } - - // seek to the end of attachment - $this->fseek($offset + $length); - - return $attachment; - } - -} - - -class getid3_exception extends Exception -{ - public $message; -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// // +// Please see readme.txt for more information // +// /// +///////////////////////////////////////////////////////////////// + +// define a constant rather than looking up every time it is needed +if (!defined('GETID3_OS_ISWINDOWS')) { + define('GETID3_OS_ISWINDOWS', (stripos(PHP_OS, 'WIN') === 0)); +} +// Get base path of getID3() - ONCE +if (!defined('GETID3_INCLUDEPATH')) { + define('GETID3_INCLUDEPATH', dirname(__FILE__).DIRECTORY_SEPARATOR); +} + +// attempt to define temp dir as something flexible but reliable +$temp_dir = ini_get('upload_tmp_dir'); +if ($temp_dir && (!is_dir($temp_dir) || !is_readable($temp_dir))) { + $temp_dir = ''; +} +if (!$temp_dir && function_exists('sys_get_temp_dir')) { + // PHP v5.2.1+ + // sys_get_temp_dir() may give inaccessible temp dir, e.g. with open_basedir on virtual hosts + $temp_dir = sys_get_temp_dir(); +} +$temp_dir = realpath($temp_dir); +$open_basedir = ini_get('open_basedir'); +if ($open_basedir) { + // e.g. "/var/www/vhosts/getid3.org/httpdocs/:/tmp/" + $temp_dir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $temp_dir); + $open_basedir = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $open_basedir); + if (substr($temp_dir, -1, 1) != DIRECTORY_SEPARATOR) { + $temp_dir .= DIRECTORY_SEPARATOR; + } + $found_valid_tempdir = false; + $open_basedirs = explode(PATH_SEPARATOR, $open_basedir); + foreach ($open_basedirs as $basedir) { + if (substr($basedir, -1, 1) != DIRECTORY_SEPARATOR) { + $basedir .= DIRECTORY_SEPARATOR; + } + if (preg_match('#^'.preg_quote($basedir).'#', $temp_dir)) { + $found_valid_tempdir = true; + break; + } + } + if (!$found_valid_tempdir) { + $temp_dir = ''; + } + unset($open_basedirs, $found_valid_tempdir, $basedir); +} +if (!$temp_dir) { + $temp_dir = '*'; // invalid directory name should force tempnam() to use system default temp dir +} +// $temp_dir = '/something/else/'; // feel free to override temp dir here if it works better for your system +define('GETID3_TEMP_DIR', $temp_dir); +unset($open_basedir, $temp_dir); + +// End: Defines + + +class getID3 +{ + // public: Settings + public $encoding = 'UTF-8'; // CASE SENSITIVE! - i.e. (must be supported by iconv()). Examples: ISO-8859-1 UTF-8 UTF-16 UTF-16BE + public $encoding_id3v1 = 'ISO-8859-1'; // Should always be 'ISO-8859-1', but some tags may be written in other encodings such as 'EUC-CN' or 'CP1252' + + // public: Optional tag checks - disable for speed. + public $option_tag_id3v1 = true; // Read and process ID3v1 tags + public $option_tag_id3v2 = true; // Read and process ID3v2 tags + public $option_tag_lyrics3 = true; // Read and process Lyrics3 tags + public $option_tag_apetag = true; // Read and process APE tags + public $option_tags_process = true; // Copy tags to root key 'tags' and encode to $this->encoding + public $option_tags_html = true; // Copy tags to root key 'tags_html' properly translated from various encodings to HTML entities + + // public: Optional tag/comment calucations + public $option_extra_info = true; // Calculate additional info such as bitrate, channelmode etc + + // public: Optional handling of embedded attachments (e.g. images) + public $option_save_attachments = true; // defaults to true (ATTACHMENTS_INLINE) for backward compatibility + + // public: Optional calculations + public $option_md5_data = false; // Get MD5 sum of data part - slow + public $option_md5_data_source = false; // Use MD5 of source file if availble - only FLAC and OptimFROG + public $option_sha1_data = false; // Get SHA1 sum of data part - slow + public $option_max_2gb_check = null; // Check whether file is larger than 2GB and thus not supported by 32-bit PHP (null: auto-detect based on PHP_INT_MAX) + + // public: Read buffer size in bytes + public $option_fread_buffer_size = 32768; + + // Public variables + public $filename; // Filename of file being analysed. + public $fp; // Filepointer to file being analysed. + public $info; // Result array. + public $tempdir = GETID3_TEMP_DIR; + + // Protected variables + protected $startup_error = ''; + protected $startup_warning = ''; + protected $memory_limit = 0; + + const VERSION = '1.9.7-20130705'; + const FREAD_BUFFER_SIZE = 32768; + + const ATTACHMENTS_NONE = false; + const ATTACHMENTS_INLINE = true; + + // public: constructor + public function __construct() { + + // Check for PHP version + $required_php_version = '5.0.5'; + if (version_compare(PHP_VERSION, $required_php_version, '<')) { + $this->startup_error .= 'getID3() requires PHP v'.$required_php_version.' or higher - you are running v'.PHP_VERSION; + return false; + } + + // Check memory + $this->memory_limit = ini_get('memory_limit'); + if (preg_match('#([0-9]+)M#i', $this->memory_limit, $matches)) { + // could be stored as "16M" rather than 16777216 for example + $this->memory_limit = $matches[1] * 1048576; + } elseif (preg_match('#([0-9]+)G#i', $this->memory_limit, $matches)) { // The 'G' modifier is available since PHP 5.1.0 + // could be stored as "2G" rather than 2147483648 for example + $this->memory_limit = $matches[1] * 1073741824; + } + if ($this->memory_limit <= 0) { + // memory limits probably disabled + } elseif ($this->memory_limit <= 4194304) { + $this->startup_error .= 'PHP has less than 4MB available memory and will very likely run out. Increase memory_limit in php.ini'; + } elseif ($this->memory_limit <= 12582912) { + $this->startup_warning .= 'PHP has less than 12MB available memory and might run out if all modules are loaded. Increase memory_limit in php.ini'; + } + + // Check safe_mode off + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + $this->warning('WARNING: Safe mode is on, shorten support disabled, md5data/sha1data for ogg vorbis disabled, ogg vorbos/flac tag writing disabled.'); + } + + if (intval(ini_get('mbstring.func_overload')) > 0) { + $this->warning('WARNING: php.ini contains "mbstring.func_overload = '.ini_get('mbstring.func_overload').'", this may break things.'); + } + + // Check for magic_quotes_runtime + if (function_exists('get_magic_quotes_runtime')) { + if (get_magic_quotes_runtime()) { + return $this->startup_error('magic_quotes_runtime must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_runtime(0) and set_magic_quotes_runtime(1).'); + } + } + + // Check for magic_quotes_gpc + if (function_exists('magic_quotes_gpc')) { + if (get_magic_quotes_gpc()) { + return $this->startup_error('magic_quotes_gpc must be disabled before running getID3(). Surround getid3 block by set_magic_quotes_gpc(0) and set_magic_quotes_gpc(1).'); + } + } + + // Load support library + if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { + $this->startup_error .= 'getid3.lib.php is missing or corrupt'; + } + + if ($this->option_max_2gb_check === null) { + $this->option_max_2gb_check = (PHP_INT_MAX <= 2147483647); + } + + + // Needed for Windows only: + // Define locations of helper applications for Shorten, VorbisComment, MetaFLAC + // as well as other helper functions such as head, tail, md5sum, etc + // This path cannot contain spaces, but the below code will attempt to get the + // 8.3-equivalent path automatically + // IMPORTANT: This path must include the trailing slash + if (GETID3_OS_ISWINDOWS && !defined('GETID3_HELPERAPPSDIR')) { + + $helperappsdir = GETID3_INCLUDEPATH.'..'.DIRECTORY_SEPARATOR.'helperapps'; // must not have any space in this path + + if (!is_dir($helperappsdir)) { + $this->startup_warning .= '"'.$helperappsdir.'" cannot be defined as GETID3_HELPERAPPSDIR because it does not exist'; + } elseif (strpos(realpath($helperappsdir), ' ') !== false) { + $DirPieces = explode(DIRECTORY_SEPARATOR, realpath($helperappsdir)); + $path_so_far = array(); + foreach ($DirPieces as $key => $value) { + if (strpos($value, ' ') !== false) { + if (!empty($path_so_far)) { + $commandline = 'dir /x '.escapeshellarg(implode(DIRECTORY_SEPARATOR, $path_so_far)); + $dir_listing = `$commandline`; + $lines = explode("\n", $dir_listing); + foreach ($lines as $line) { + $line = trim($line); + if (preg_match('#^([0-9/]{10}) +([0-9:]{4,5}( [AP]M)?) +(|[0-9,]+) +([^ ]{0,11}) +(.+)$#', $line, $matches)) { + list($dummy, $date, $time, $ampm, $filesize, $shortname, $filename) = $matches; + if ((strtoupper($filesize) == '') && (strtolower($filename) == strtolower($value))) { + $value = $shortname; + } + } + } + } else { + $this->startup_warning .= 'GETID3_HELPERAPPSDIR must not have any spaces in it - use 8dot3 naming convention if neccesary. You can run "dir /x" from the commandline to see the correct 8.3-style names.'; + } + } + $path_so_far[] = $value; + } + $helperappsdir = implode(DIRECTORY_SEPARATOR, $path_so_far); + } + define('GETID3_HELPERAPPSDIR', $helperappsdir.DIRECTORY_SEPARATOR); + } + + return true; + } + + public function version() { + return self::VERSION; + } + + public function fread_buffer_size() { + return $this->option_fread_buffer_size; + } + + + // public: setOption + public function setOption($optArray) { + if (!is_array($optArray) || empty($optArray)) { + return false; + } + foreach ($optArray as $opt => $val) { + if (isset($this->$opt) === false) { + continue; + } + $this->$opt = $val; + } + return true; + } + + + public function openfile($filename) { + try { + if (!empty($this->startup_error)) { + throw new getid3_exception($this->startup_error); + } + if (!empty($this->startup_warning)) { + $this->warning($this->startup_warning); + } + + // init result array and set parameters + $this->filename = $filename; + $this->info = array(); + $this->info['GETID3_VERSION'] = $this->version(); + $this->info['php_memory_limit'] = $this->memory_limit; + + // remote files not supported + if (preg_match('/^(ht|f)tp:\/\//', $filename)) { + throw new getid3_exception('Remote files are not supported - please copy the file locally first'); + } + + $filename = str_replace('/', DIRECTORY_SEPARATOR, $filename); + $filename = preg_replace('#(.+)'.preg_quote(DIRECTORY_SEPARATOR).'{2,}#U', '\1'.DIRECTORY_SEPARATOR, $filename); + + // open local file + if (is_readable($filename) && is_file($filename) && ($this->fp = fopen($filename, 'rb'))) { + // great + } else { + throw new getid3_exception('Could not open "'.$filename.'" (does not exist, or is not a file)'); + } + + $this->info['filesize'] = filesize($filename); + // set redundant parameters - might be needed in some include file + $this->info['filename'] = basename($filename); + $this->info['filepath'] = str_replace('\\', '/', realpath(dirname($filename))); + $this->info['filenamepath'] = $this->info['filepath'].'/'.$this->info['filename']; + + + // option_max_2gb_check + if ($this->option_max_2gb_check) { + // PHP (32-bit all, and 64-bit Windows) doesn't support integers larger than 2^31 (~2GB) + // filesize() simply returns (filesize % (pow(2, 32)), no matter the actual filesize + // ftell() returns 0 if seeking to the end is beyond the range of unsigned integer + $fseek = fseek($this->fp, 0, SEEK_END); + if (($fseek < 0) || (($this->info['filesize'] != 0) && (ftell($this->fp) == 0)) || + ($this->info['filesize'] < 0) || + (ftell($this->fp) < 0)) { + $real_filesize = getid3_lib::getFileSizeSyscall($this->info['filenamepath']); + + if ($real_filesize === false) { + unset($this->info['filesize']); + fclose($this->fp); + throw new getid3_exception('Unable to determine actual filesize. File is most likely larger than '.round(PHP_INT_MAX / 1073741824).'GB and is not supported by PHP.'); + } elseif (getid3_lib::intValueSupported($real_filesize)) { + unset($this->info['filesize']); + fclose($this->fp); + throw new getid3_exception('PHP seems to think the file is larger than '.round(PHP_INT_MAX / 1073741824).'GB, but filesystem reports it as '.number_format($real_filesize, 3).'GB, please report to info@getid3.org'); + } + $this->info['filesize'] = $real_filesize; + $this->warning('File is larger than '.round(PHP_INT_MAX / 1073741824).'GB (filesystem reports it as '.number_format($real_filesize, 3).'GB) and is not properly supported by PHP.'); + } + } + + // set more parameters + $this->info['avdataoffset'] = 0; + $this->info['avdataend'] = $this->info['filesize']; + $this->info['fileformat'] = ''; // filled in later + $this->info['audio']['dataformat'] = ''; // filled in later, unset if not used + $this->info['video']['dataformat'] = ''; // filled in later, unset if not used + $this->info['tags'] = array(); // filled in later, unset if not used + $this->info['error'] = array(); // filled in later, unset if not used + $this->info['warning'] = array(); // filled in later, unset if not used + $this->info['comments'] = array(); // filled in later, unset if not used + $this->info['encoding'] = $this->encoding; // required by id3v2 and iso modules - can be unset at the end if desired + + return true; + + } catch (Exception $e) { + $this->error($e->getMessage()); + } + return false; + } + + // public: analyze file + public function analyze($filename) { + try { + if (!$this->openfile($filename)) { + return $this->info; + } + + // Handle tags + foreach (array('id3v2'=>'id3v2', 'id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) { + $option_tag = 'option_tag_'.$tag_name; + if ($this->$option_tag) { + $this->include_module('tag.'.$tag_name); + try { + $tag_class = 'getid3_'.$tag_name; + $tag = new $tag_class($this); + $tag->Analyze(); + } + catch (getid3_exception $e) { + throw $e; + } + } + } + if (isset($this->info['id3v2']['tag_offset_start'])) { + $this->info['avdataoffset'] = max($this->info['avdataoffset'], $this->info['id3v2']['tag_offset_end']); + } + foreach (array('id3v1'=>'id3v1', 'apetag'=>'ape', 'lyrics3'=>'lyrics3') as $tag_name => $tag_key) { + if (isset($this->info[$tag_key]['tag_offset_start'])) { + $this->info['avdataend'] = min($this->info['avdataend'], $this->info[$tag_key]['tag_offset_start']); + } + } + + // ID3v2 detection (NOT parsing), even if ($this->option_tag_id3v2 == false) done to make fileformat easier + if (!$this->option_tag_id3v2) { + fseek($this->fp, 0, SEEK_SET); + $header = fread($this->fp, 10); + if ((substr($header, 0, 3) == 'ID3') && (strlen($header) == 10)) { + $this->info['id3v2']['header'] = true; + $this->info['id3v2']['majorversion'] = ord($header{3}); + $this->info['id3v2']['minorversion'] = ord($header{4}); + $this->info['avdataoffset'] += getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length + } + } + + // read 32 kb file data + fseek($this->fp, $this->info['avdataoffset'], SEEK_SET); + $formattest = fread($this->fp, 32774); + + // determine format + $determined_format = $this->GetFileFormat($formattest, $filename); + + // unable to determine file format + if (!$determined_format) { + fclose($this->fp); + return $this->error('unable to determine file format'); + } + + // check for illegal ID3 tags + if (isset($determined_format['fail_id3']) && (in_array('id3v1', $this->info['tags']) || in_array('id3v2', $this->info['tags']))) { + if ($determined_format['fail_id3'] === 'ERROR') { + fclose($this->fp); + return $this->error('ID3 tags not allowed on this file type.'); + } elseif ($determined_format['fail_id3'] === 'WARNING') { + $this->warning('ID3 tags not allowed on this file type.'); + } + } + + // check for illegal APE tags + if (isset($determined_format['fail_ape']) && in_array('ape', $this->info['tags'])) { + if ($determined_format['fail_ape'] === 'ERROR') { + fclose($this->fp); + return $this->error('APE tags not allowed on this file type.'); + } elseif ($determined_format['fail_ape'] === 'WARNING') { + $this->warning('APE tags not allowed on this file type.'); + } + } + + // set mime type + $this->info['mime_type'] = $determined_format['mime_type']; + + // supported format signature pattern detected, but module deleted + if (!file_exists(GETID3_INCLUDEPATH.$determined_format['include'])) { + fclose($this->fp); + return $this->error('Format not supported, module "'.$determined_format['include'].'" was removed.'); + } + + // module requires iconv support + // Check encoding/iconv support + if (!empty($determined_format['iconv_req']) && !function_exists('iconv') && !in_array($this->encoding, array('ISO-8859-1', 'UTF-8', 'UTF-16LE', 'UTF-16BE', 'UTF-16'))) { + $errormessage = 'iconv() support is required for this module ('.$determined_format['include'].') for encodings other than ISO-8859-1, UTF-8, UTF-16LE, UTF16-BE, UTF-16. '; + if (GETID3_OS_ISWINDOWS) { + $errormessage .= 'PHP does not have iconv() support. Please enable php_iconv.dll in php.ini, and copy iconv.dll from c:/php/dlls to c:/windows/system32'; + } else { + $errormessage .= 'PHP is not compiled with iconv() support. Please recompile with the --with-iconv switch'; + } + return $this->error($errormessage); + } + + // include module + include_once(GETID3_INCLUDEPATH.$determined_format['include']); + + // instantiate module class + $class_name = 'getid3_'.$determined_format['module']; + if (!class_exists($class_name)) { + return $this->error('Format not supported, module "'.$determined_format['include'].'" is corrupt.'); + } + $class = new $class_name($this); + $class->Analyze(); + unset($class); + + // close file + fclose($this->fp); + + // process all tags - copy to 'tags' and convert charsets + if ($this->option_tags_process) { + $this->HandleAllTags(); + } + + // perform more calculations + if ($this->option_extra_info) { + $this->ChannelsBitratePlaytimeCalculations(); + $this->CalculateCompressionRatioVideo(); + $this->CalculateCompressionRatioAudio(); + $this->CalculateReplayGain(); + $this->ProcessAudioStreams(); + } + + // get the MD5 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags + if ($this->option_md5_data) { + // do not calc md5_data if md5_data_source is present - set by flac only - future MPC/SV8 too + if (!$this->option_md5_data_source || empty($this->info['md5_data_source'])) { + $this->getHashdata('md5'); + } + } + + // get the SHA1 sum of the audio/video portion of the file - without ID3/APE/Lyrics3/etc header/footer tags + if ($this->option_sha1_data) { + $this->getHashdata('sha1'); + } + + // remove undesired keys + $this->CleanUp(); + + } catch (Exception $e) { + $this->error('Caught exception: '.$e->getMessage()); + } + + // return info array + return $this->info; + } + + + // private: error handling + public function error($message) { + $this->CleanUp(); + if (!isset($this->info['error'])) { + $this->info['error'] = array(); + } + $this->info['error'][] = $message; + return $this->info; + } + + + // private: warning handling + public function warning($message) { + $this->info['warning'][] = $message; + return true; + } + + + // private: CleanUp + private function CleanUp() { + + // remove possible empty keys + $AVpossibleEmptyKeys = array('dataformat', 'bits_per_sample', 'encoder_options', 'streams', 'bitrate'); + foreach ($AVpossibleEmptyKeys as $dummy => $key) { + if (empty($this->info['audio'][$key]) && isset($this->info['audio'][$key])) { + unset($this->info['audio'][$key]); + } + if (empty($this->info['video'][$key]) && isset($this->info['video'][$key])) { + unset($this->info['video'][$key]); + } + } + + // remove empty root keys + if (!empty($this->info)) { + foreach ($this->info as $key => $value) { + if (empty($this->info[$key]) && ($this->info[$key] !== 0) && ($this->info[$key] !== '0')) { + unset($this->info[$key]); + } + } + } + + // remove meaningless entries from unknown-format files + if (empty($this->info['fileformat'])) { + if (isset($this->info['avdataoffset'])) { + unset($this->info['avdataoffset']); + } + if (isset($this->info['avdataend'])) { + unset($this->info['avdataend']); + } + } + + // remove possible duplicated identical entries + if (!empty($this->info['error'])) { + $this->info['error'] = array_values(array_unique($this->info['error'])); + } + if (!empty($this->info['warning'])) { + $this->info['warning'] = array_values(array_unique($this->info['warning'])); + } + + // remove "global variable" type keys + unset($this->info['php_memory_limit']); + + return true; + } + + + // return array containing information about all supported formats + public function GetFileFormatArray() { + static $format_info = array(); + if (empty($format_info)) { + $format_info = array( + + // Audio formats + + // AC-3 - audio - Dolby AC-3 / Dolby Digital + 'ac3' => array( + 'pattern' => '^\x0B\x77', + 'group' => 'audio', + 'module' => 'ac3', + 'mime_type' => 'audio/ac3', + ), + + // AAC - audio - Advanced Audio Coding (AAC) - ADIF format + 'adif' => array( + 'pattern' => '^ADIF', + 'group' => 'audio', + 'module' => 'aac', + 'mime_type' => 'application/octet-stream', + 'fail_ape' => 'WARNING', + ), + +/* + // AA - audio - Audible Audiobook + 'aa' => array( + 'pattern' => '^.{4}\x57\x90\x75\x36', + 'group' => 'audio', + 'module' => 'aa', + 'mime_type' => 'audio/audible', + ), +*/ + // AAC - audio - Advanced Audio Coding (AAC) - ADTS format (very similar to MP3) + 'adts' => array( + 'pattern' => '^\xFF[\xF0-\xF1\xF8-\xF9]', + 'group' => 'audio', + 'module' => 'aac', + 'mime_type' => 'application/octet-stream', + 'fail_ape' => 'WARNING', + ), + + + // AU - audio - NeXT/Sun AUdio (AU) + 'au' => array( + 'pattern' => '^\.snd', + 'group' => 'audio', + 'module' => 'au', + 'mime_type' => 'audio/basic', + ), + + // AVR - audio - Audio Visual Research + 'avr' => array( + 'pattern' => '^2BIT', + 'group' => 'audio', + 'module' => 'avr', + 'mime_type' => 'application/octet-stream', + ), + + // BONK - audio - Bonk v0.9+ + 'bonk' => array( + 'pattern' => '^\x00(BONK|INFO|META| ID3)', + 'group' => 'audio', + 'module' => 'bonk', + 'mime_type' => 'audio/xmms-bonk', + ), + + // DSS - audio - Digital Speech Standard + 'dss' => array( + 'pattern' => '^[\x02-\x03]ds[s2]', + 'group' => 'audio', + 'module' => 'dss', + 'mime_type' => 'application/octet-stream', + ), + + // DTS - audio - Dolby Theatre System + 'dts' => array( + 'pattern' => '^\x7F\xFE\x80\x01', + 'group' => 'audio', + 'module' => 'dts', + 'mime_type' => 'audio/dts', + ), + + // FLAC - audio - Free Lossless Audio Codec + 'flac' => array( + 'pattern' => '^fLaC', + 'group' => 'audio', + 'module' => 'flac', + 'mime_type' => 'audio/x-flac', + ), + + // LA - audio - Lossless Audio (LA) + 'la' => array( + 'pattern' => '^LA0[2-4]', + 'group' => 'audio', + 'module' => 'la', + 'mime_type' => 'application/octet-stream', + ), + + // LPAC - audio - Lossless Predictive Audio Compression (LPAC) + 'lpac' => array( + 'pattern' => '^LPAC', + 'group' => 'audio', + 'module' => 'lpac', + 'mime_type' => 'application/octet-stream', + ), + + // MIDI - audio - MIDI (Musical Instrument Digital Interface) + 'midi' => array( + 'pattern' => '^MThd', + 'group' => 'audio', + 'module' => 'midi', + 'mime_type' => 'audio/midi', + ), + + // MAC - audio - Monkey's Audio Compressor + 'mac' => array( + 'pattern' => '^MAC ', + 'group' => 'audio', + 'module' => 'monkey', + 'mime_type' => 'application/octet-stream', + ), + +// has been known to produce false matches in random files (e.g. JPEGs), leave out until more precise matching available +// // MOD - audio - MODule (assorted sub-formats) +// 'mod' => array( +// 'pattern' => '^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)', +// 'group' => 'audio', +// 'module' => 'mod', +// 'option' => 'mod', +// 'mime_type' => 'audio/mod', +// ), + + // MOD - audio - MODule (Impulse Tracker) + 'it' => array( + 'pattern' => '^IMPM', + 'group' => 'audio', + 'module' => 'mod', + //'option' => 'it', + 'mime_type' => 'audio/it', + ), + + // MOD - audio - MODule (eXtended Module, various sub-formats) + 'xm' => array( + 'pattern' => '^Extended Module', + 'group' => 'audio', + 'module' => 'mod', + //'option' => 'xm', + 'mime_type' => 'audio/xm', + ), + + // MOD - audio - MODule (ScreamTracker) + 's3m' => array( + 'pattern' => '^.{44}SCRM', + 'group' => 'audio', + 'module' => 'mod', + //'option' => 's3m', + 'mime_type' => 'audio/s3m', + ), + + // MPC - audio - Musepack / MPEGplus + 'mpc' => array( + 'pattern' => '^(MPCK|MP\+|[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0])', + 'group' => 'audio', + 'module' => 'mpc', + 'mime_type' => 'audio/x-musepack', + ), + + // MP3 - audio - MPEG-audio Layer 3 (very similar to AAC-ADTS) + 'mp3' => array( + 'pattern' => '^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\x0B\x10-\x1B\x20-\x2B\x30-\x3B\x40-\x4B\x50-\x5B\x60-\x6B\x70-\x7B\x80-\x8B\x90-\x9B\xA0-\xAB\xB0-\xBB\xC0-\xCB\xD0-\xDB\xE0-\xEB\xF0-\xFB]', + 'group' => 'audio', + 'module' => 'mp3', + 'mime_type' => 'audio/mpeg', + ), + + // OFR - audio - OptimFROG + 'ofr' => array( + 'pattern' => '^(\*RIFF|OFR)', + 'group' => 'audio', + 'module' => 'optimfrog', + 'mime_type' => 'application/octet-stream', + ), + + // RKAU - audio - RKive AUdio compressor + 'rkau' => array( + 'pattern' => '^RKA', + 'group' => 'audio', + 'module' => 'rkau', + 'mime_type' => 'application/octet-stream', + ), + + // SHN - audio - Shorten + 'shn' => array( + 'pattern' => '^ajkg', + 'group' => 'audio', + 'module' => 'shorten', + 'mime_type' => 'audio/xmms-shn', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // TTA - audio - TTA Lossless Audio Compressor (http://tta.corecodec.org) + 'tta' => array( + 'pattern' => '^TTA', // could also be '^TTA(\x01|\x02|\x03|2|1)' + 'group' => 'audio', + 'module' => 'tta', + 'mime_type' => 'application/octet-stream', + ), + + // VOC - audio - Creative Voice (VOC) + 'voc' => array( + 'pattern' => '^Creative Voice File', + 'group' => 'audio', + 'module' => 'voc', + 'mime_type' => 'audio/voc', + ), + + // VQF - audio - transform-domain weighted interleave Vector Quantization Format (VQF) + 'vqf' => array( + 'pattern' => '^TWIN', + 'group' => 'audio', + 'module' => 'vqf', + 'mime_type' => 'application/octet-stream', + ), + + // WV - audio - WavPack (v4.0+) + 'wv' => array( + 'pattern' => '^wvpk', + 'group' => 'audio', + 'module' => 'wavpack', + 'mime_type' => 'application/octet-stream', + ), + + + // Audio-Video formats + + // ASF - audio/video - Advanced Streaming Format, Windows Media Video, Windows Media Audio + 'asf' => array( + 'pattern' => '^\x30\x26\xB2\x75\x8E\x66\xCF\x11\xA6\xD9\x00\xAA\x00\x62\xCE\x6C', + 'group' => 'audio-video', + 'module' => 'asf', + 'mime_type' => 'video/x-ms-asf', + 'iconv_req' => false, + ), + + // BINK - audio/video - Bink / Smacker + 'bink' => array( + 'pattern' => '^(BIK|SMK)', + 'group' => 'audio-video', + 'module' => 'bink', + 'mime_type' => 'application/octet-stream', + ), + + // FLV - audio/video - FLash Video + 'flv' => array( + 'pattern' => '^FLV\x01', + 'group' => 'audio-video', + 'module' => 'flv', + 'mime_type' => 'video/x-flv', + ), + + // MKAV - audio/video - Mastroka + 'matroska' => array( + 'pattern' => '^\x1A\x45\xDF\xA3', + 'group' => 'audio-video', + 'module' => 'matroska', + 'mime_type' => 'video/x-matroska', // may also be audio/x-matroska + ), + + // MPEG - audio/video - MPEG (Moving Pictures Experts Group) + 'mpeg' => array( + 'pattern' => '^\x00\x00\x01(\xBA|\xB3)', + 'group' => 'audio-video', + 'module' => 'mpeg', + 'mime_type' => 'video/mpeg', + ), + + // NSV - audio/video - Nullsoft Streaming Video (NSV) + 'nsv' => array( + 'pattern' => '^NSV[sf]', + 'group' => 'audio-video', + 'module' => 'nsv', + 'mime_type' => 'application/octet-stream', + ), + + // Ogg - audio/video - Ogg (Ogg-Vorbis, Ogg-FLAC, Speex, Ogg-Theora(*), Ogg-Tarkin(*)) + 'ogg' => array( + 'pattern' => '^OggS', + 'group' => 'audio', + 'module' => 'ogg', + 'mime_type' => 'application/ogg', + 'fail_id3' => 'WARNING', + 'fail_ape' => 'WARNING', + ), + + // QT - audio/video - Quicktime + 'quicktime' => array( + 'pattern' => '^.{4}(cmov|free|ftyp|mdat|moov|pnot|skip|wide)', + 'group' => 'audio-video', + 'module' => 'quicktime', + 'mime_type' => 'video/quicktime', + ), + + // RIFF - audio/video - Resource Interchange File Format (RIFF) / WAV / AVI / CD-audio / SDSS = renamed variant used by SmartSound QuickTracks (www.smartsound.com) / FORM = Audio Interchange File Format (AIFF) + 'riff' => array( + 'pattern' => '^(RIFF|SDSS|FORM)', + 'group' => 'audio-video', + 'module' => 'riff', + 'mime_type' => 'audio/x-wave', + 'fail_ape' => 'WARNING', + ), + + // Real - audio/video - RealAudio, RealVideo + 'real' => array( + 'pattern' => '^(\\.RMF|\\.ra)', + 'group' => 'audio-video', + 'module' => 'real', + 'mime_type' => 'audio/x-realaudio', + ), + + // SWF - audio/video - ShockWave Flash + 'swf' => array( + 'pattern' => '^(F|C)WS', + 'group' => 'audio-video', + 'module' => 'swf', + 'mime_type' => 'application/x-shockwave-flash', + ), + + // TS - audio/video - MPEG-2 Transport Stream + 'ts' => array( + 'pattern' => '^(\x47.{187}){10,}', // packets are 188 bytes long and start with 0x47 "G". Check for at least 10 packets matching this pattern + 'group' => 'audio-video', + 'module' => 'ts', + 'mime_type' => 'video/MP2T', + ), + + + // Still-Image formats + + // BMP - still image - Bitmap (Windows, OS/2; uncompressed, RLE8, RLE4) + 'bmp' => array( + 'pattern' => '^BM', + 'group' => 'graphic', + 'module' => 'bmp', + 'mime_type' => 'image/bmp', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // GIF - still image - Graphics Interchange Format + 'gif' => array( + 'pattern' => '^GIF', + 'group' => 'graphic', + 'module' => 'gif', + 'mime_type' => 'image/gif', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // JPEG - still image - Joint Photographic Experts Group (JPEG) + 'jpg' => array( + 'pattern' => '^\xFF\xD8\xFF', + 'group' => 'graphic', + 'module' => 'jpg', + 'mime_type' => 'image/jpeg', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // PCD - still image - Kodak Photo CD + 'pcd' => array( + 'pattern' => '^.{2048}PCD_IPI\x00', + 'group' => 'graphic', + 'module' => 'pcd', + 'mime_type' => 'image/x-photo-cd', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // PNG - still image - Portable Network Graphics (PNG) + 'png' => array( + 'pattern' => '^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A', + 'group' => 'graphic', + 'module' => 'png', + 'mime_type' => 'image/png', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // SVG - still image - Scalable Vector Graphics (SVG) + 'svg' => array( + 'pattern' => '( 'graphic', + 'module' => 'svg', + 'mime_type' => 'image/svg+xml', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // TIFF - still image - Tagged Information File Format (TIFF) + 'tiff' => array( + 'pattern' => '^(II\x2A\x00|MM\x00\x2A)', + 'group' => 'graphic', + 'module' => 'tiff', + 'mime_type' => 'image/tiff', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // EFAX - still image - eFax (TIFF derivative) + 'efax' => array( + 'pattern' => '^\xDC\xFE', + 'group' => 'graphic', + 'module' => 'efax', + 'mime_type' => 'image/efax', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // Data formats + + // ISO - data - International Standards Organization (ISO) CD-ROM Image + 'iso' => array( + 'pattern' => '^.{32769}CD001', + 'group' => 'misc', + 'module' => 'iso', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + 'iconv_req' => false, + ), + + // RAR - data - RAR compressed data + 'rar' => array( + 'pattern' => '^Rar\!', + 'group' => 'archive', + 'module' => 'rar', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // SZIP - audio/data - SZIP compressed data + 'szip' => array( + 'pattern' => '^SZ\x0A\x04', + 'group' => 'archive', + 'module' => 'szip', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // TAR - data - TAR compressed data + 'tar' => array( + 'pattern' => '^.{100}[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20]{7}\x00[0-9\x20\x00]{12}[0-9\x20\x00]{12}', + 'group' => 'archive', + 'module' => 'tar', + 'mime_type' => 'application/x-tar', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // GZIP - data - GZIP compressed data + 'gz' => array( + 'pattern' => '^\x1F\x8B\x08', + 'group' => 'archive', + 'module' => 'gzip', + 'mime_type' => 'application/x-gzip', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // ZIP - data - ZIP compressed data + 'zip' => array( + 'pattern' => '^PK\x03\x04', + 'group' => 'archive', + 'module' => 'zip', + 'mime_type' => 'application/zip', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + + // Misc other formats + + // PAR2 - data - Parity Volume Set Specification 2.0 + 'par2' => array ( + 'pattern' => '^PAR2\x00PKT', + 'group' => 'misc', + 'module' => 'par2', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // PDF - data - Portable Document Format + 'pdf' => array( + 'pattern' => '^\x25PDF', + 'group' => 'misc', + 'module' => 'pdf', + 'mime_type' => 'application/pdf', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // MSOFFICE - data - ZIP compressed data + 'msoffice' => array( + 'pattern' => '^\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1', // D0CF11E == DOCFILE == Microsoft Office Document + 'group' => 'misc', + 'module' => 'msoffice', + 'mime_type' => 'application/octet-stream', + 'fail_id3' => 'ERROR', + 'fail_ape' => 'ERROR', + ), + + // CUE - data - CUEsheet (index to single-file disc images) + 'cue' => array( + 'pattern' => '', // empty pattern means cannot be automatically detected, will fall through all other formats and match based on filename and very basic file contents + 'group' => 'misc', + 'module' => 'cue', + 'mime_type' => 'application/octet-stream', + ), + + ); + } + + return $format_info; + } + + + + public function GetFileFormat(&$filedata, $filename='') { + // this function will determine the format of a file based on usually + // the first 2-4 bytes of the file (8 bytes for PNG, 16 bytes for JPG, + // and in the case of ISO CD image, 6 bytes offset 32kb from the start + // of the file). + + // Identify file format - loop through $format_info and detect with reg expr + foreach ($this->GetFileFormatArray() as $format_name => $info) { + // The /s switch on preg_match() forces preg_match() NOT to treat + // newline (0x0A) characters as special chars but do a binary match + if (!empty($info['pattern']) && preg_match('#'.$info['pattern'].'#s', $filedata)) { + $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; + return $info; + } + } + + + if (preg_match('#\.mp[123a]$#i', $filename)) { + // Too many mp3 encoders on the market put gabage in front of mpeg files + // use assume format on these if format detection failed + $GetFileFormatArray = $this->GetFileFormatArray(); + $info = $GetFileFormatArray['mp3']; + $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; + return $info; + } elseif (preg_match('/\.cue$/i', $filename) && preg_match('#FILE "[^"]+" (BINARY|MOTOROLA|AIFF|WAVE|MP3)#', $filedata)) { + // there's not really a useful consistent "magic" at the beginning of .cue files to identify them + // so until I think of something better, just go by filename if all other format checks fail + // and verify there's at least one instance of "TRACK xx AUDIO" in the file + $GetFileFormatArray = $this->GetFileFormatArray(); + $info = $GetFileFormatArray['cue']; + $info['include'] = 'module.'.$info['group'].'.'.$info['module'].'.php'; + return $info; + } + + return false; + } + + + // converts array to $encoding charset from $this->encoding + public function CharConvert(&$array, $encoding) { + + // identical encoding - end here + if ($encoding == $this->encoding) { + return; + } + + // loop thru array + foreach ($array as $key => $value) { + + // go recursive + if (is_array($value)) { + $this->CharConvert($array[$key], $encoding); + } + + // convert string + elseif (is_string($value)) { + $array[$key] = trim(getid3_lib::iconv_fallback($encoding, $this->encoding, $value)); + } + } + } + + + public function HandleAllTags() { + + // key name => array (tag name, character encoding) + static $tags; + if (empty($tags)) { + $tags = array( + 'asf' => array('asf' , 'UTF-16LE'), + 'midi' => array('midi' , 'ISO-8859-1'), + 'nsv' => array('nsv' , 'ISO-8859-1'), + 'ogg' => array('vorbiscomment' , 'UTF-8'), + 'png' => array('png' , 'UTF-8'), + 'tiff' => array('tiff' , 'ISO-8859-1'), + 'quicktime' => array('quicktime' , 'UTF-8'), + 'real' => array('real' , 'ISO-8859-1'), + 'vqf' => array('vqf' , 'ISO-8859-1'), + 'zip' => array('zip' , 'ISO-8859-1'), + 'riff' => array('riff' , 'ISO-8859-1'), + 'lyrics3' => array('lyrics3' , 'ISO-8859-1'), + 'id3v1' => array('id3v1' , $this->encoding_id3v1), + 'id3v2' => array('id3v2' , 'UTF-8'), // not according to the specs (every frame can have a different encoding), but getID3() force-converts all encodings to UTF-8 + 'ape' => array('ape' , 'UTF-8'), + 'cue' => array('cue' , 'ISO-8859-1'), + 'matroska' => array('matroska' , 'UTF-8'), + 'flac' => array('vorbiscomment' , 'UTF-8'), + 'divxtag' => array('divx' , 'ISO-8859-1'), + ); + } + + // loop through comments array + foreach ($tags as $comment_name => $tagname_encoding_array) { + list($tag_name, $encoding) = $tagname_encoding_array; + + // fill in default encoding type if not already present + if (isset($this->info[$comment_name]) && !isset($this->info[$comment_name]['encoding'])) { + $this->info[$comment_name]['encoding'] = $encoding; + } + + // copy comments if key name set + if (!empty($this->info[$comment_name]['comments'])) { + foreach ($this->info[$comment_name]['comments'] as $tag_key => $valuearray) { + foreach ($valuearray as $key => $value) { + if (is_string($value)) { + $value = trim($value, " \r\n\t"); // do not trim nulls from $value!! Unicode characters will get mangled if trailing nulls are removed! + } + if ($value) { + $this->info['tags'][trim($tag_name)][trim($tag_key)][] = $value; + } + } + if ($tag_key == 'picture') { + unset($this->info[$comment_name]['comments'][$tag_key]); + } + } + + if (!isset($this->info['tags'][$tag_name])) { + // comments are set but contain nothing but empty strings, so skip + continue; + } + + if ($this->option_tags_html) { + foreach ($this->info['tags'][$tag_name] as $tag_key => $valuearray) { + foreach ($valuearray as $key => $value) { + if (is_string($value)) { + //$this->info['tags_html'][$tag_name][$tag_key][$key] = getid3_lib::MultiByteCharString2HTML($value, $encoding); + $this->info['tags_html'][$tag_name][$tag_key][$key] = str_replace('�', '', trim(getid3_lib::MultiByteCharString2HTML($value, $encoding))); + } else { + $this->info['tags_html'][$tag_name][$tag_key][$key] = $value; + } + } + } + } + + $this->CharConvert($this->info['tags'][$tag_name], $encoding); // only copy gets converted! + } + + } + + // pictures can take up a lot of space, and we don't need multiple copies of them + // let there be a single copy in [comments][picture], and not elsewhere + if (!empty($this->info['tags'])) { + $unset_keys = array('tags', 'tags_html'); + foreach ($this->info['tags'] as $tagtype => $tagarray) { + foreach ($tagarray as $tagname => $tagdata) { + if ($tagname == 'picture') { + foreach ($tagdata as $key => $tagarray) { + $this->info['comments']['picture'][] = $tagarray; + if (isset($tagarray['data']) && isset($tagarray['image_mime'])) { + if (isset($this->info['tags'][$tagtype][$tagname][$key])) { + unset($this->info['tags'][$tagtype][$tagname][$key]); + } + if (isset($this->info['tags_html'][$tagtype][$tagname][$key])) { + unset($this->info['tags_html'][$tagtype][$tagname][$key]); + } + } + } + } + } + foreach ($unset_keys as $unset_key) { + // remove possible empty keys from (e.g. [tags][id3v2][picture]) + if (empty($this->info[$unset_key][$tagtype]['picture'])) { + unset($this->info[$unset_key][$tagtype]['picture']); + } + if (empty($this->info[$unset_key][$tagtype])) { + unset($this->info[$unset_key][$tagtype]); + } + if (empty($this->info[$unset_key])) { + unset($this->info[$unset_key]); + } + } + // remove duplicate copy of picture data from (e.g. [id3v2][comments][picture]) + if (isset($this->info[$tagtype]['comments']['picture'])) { + unset($this->info[$tagtype]['comments']['picture']); + } + if (empty($this->info[$tagtype]['comments'])) { + unset($this->info[$tagtype]['comments']); + } + if (empty($this->info[$tagtype])) { + unset($this->info[$tagtype]); + } + } + } + return true; + } + + + public function getHashdata($algorithm) { + switch ($algorithm) { + case 'md5': + case 'sha1': + break; + + default: + return $this->error('bad algorithm "'.$algorithm.'" in getHashdata()'); + break; + } + + if (!empty($this->info['fileformat']) && !empty($this->info['dataformat']) && ($this->info['fileformat'] == 'ogg') && ($this->info['audio']['dataformat'] == 'vorbis')) { + + // We cannot get an identical md5_data value for Ogg files where the comments + // span more than 1 Ogg page (compared to the same audio data with smaller + // comments) using the normal getID3() method of MD5'ing the data between the + // end of the comments and the end of the file (minus any trailing tags), + // because the page sequence numbers of the pages that the audio data is on + // do not match. Under normal circumstances, where comments are smaller than + // the nominal 4-8kB page size, then this is not a problem, but if there are + // very large comments, the only way around it is to strip off the comment + // tags with vorbiscomment and MD5 that file. + // This procedure must be applied to ALL Ogg files, not just the ones with + // comments larger than 1 page, because the below method simply MD5's the + // whole file with the comments stripped, not just the portion after the + // comments block (which is the standard getID3() method. + + // The above-mentioned problem of comments spanning multiple pages and changing + // page sequence numbers likely happens for OggSpeex and OggFLAC as well, but + // currently vorbiscomment only works on OggVorbis files. + + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + + $this->warning('Failed making system call to vorbiscomment.exe - '.$algorithm.'_data is incorrect - error returned: PHP running in Safe Mode (backtick operator not available)'); + $this->info[$algorithm.'_data'] = false; + + } else { + + // Prevent user from aborting script + $old_abort = ignore_user_abort(true); + + // Create empty file + $empty = tempnam(GETID3_TEMP_DIR, 'getID3'); + touch($empty); + + // Use vorbiscomment to make temp file without comments + $temp = tempnam(GETID3_TEMP_DIR, 'getID3'); + $file = $this->info['filenamepath']; + + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { + + $commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w -c "'.$empty.'" "'.$file.'" "'.$temp.'"'; + $VorbisCommentError = `$commandline`; + + } else { + + $VorbisCommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; + + } + + } else { + + $commandline = 'vorbiscomment -w -c "'.$empty.'" "'.$file.'" "'.$temp.'" 2>&1'; + $commandline = 'vorbiscomment -w -c '.escapeshellarg($empty).' '.escapeshellarg($file).' '.escapeshellarg($temp).' 2>&1'; + $VorbisCommentError = `$commandline`; + + } + + if (!empty($VorbisCommentError)) { + + $this->info['warning'][] = 'Failed making system call to vorbiscomment(.exe) - '.$algorithm.'_data will be incorrect. If vorbiscomment is unavailable, please download from http://www.vorbis.com/download.psp and put in the getID3() directory. Error returned: '.$VorbisCommentError; + $this->info[$algorithm.'_data'] = false; + + } else { + + // Get hash of newly created file + switch ($algorithm) { + case 'md5': + $this->info[$algorithm.'_data'] = md5_file($temp); + break; + + case 'sha1': + $this->info[$algorithm.'_data'] = sha1_file($temp); + break; + } + } + + // Clean up + unlink($empty); + unlink($temp); + + // Reset abort setting + ignore_user_abort($old_abort); + + } + + } else { + + if (!empty($this->info['avdataoffset']) || (isset($this->info['avdataend']) && ($this->info['avdataend'] < $this->info['filesize']))) { + + // get hash from part of file + $this->info[$algorithm.'_data'] = getid3_lib::hash_data($this->info['filenamepath'], $this->info['avdataoffset'], $this->info['avdataend'], $algorithm); + + } else { + + // get hash from whole file + switch ($algorithm) { + case 'md5': + $this->info[$algorithm.'_data'] = md5_file($this->info['filenamepath']); + break; + + case 'sha1': + $this->info[$algorithm.'_data'] = sha1_file($this->info['filenamepath']); + break; + } + } + + } + return true; + } + + + public function ChannelsBitratePlaytimeCalculations() { + + // set channelmode on audio + if (!empty($this->info['audio']['channelmode']) || !isset($this->info['audio']['channels'])) { + // ignore + } elseif ($this->info['audio']['channels'] == 1) { + $this->info['audio']['channelmode'] = 'mono'; + } elseif ($this->info['audio']['channels'] == 2) { + $this->info['audio']['channelmode'] = 'stereo'; + } + + // Calculate combined bitrate - audio + video + $CombinedBitrate = 0; + $CombinedBitrate += (isset($this->info['audio']['bitrate']) ? $this->info['audio']['bitrate'] : 0); + $CombinedBitrate += (isset($this->info['video']['bitrate']) ? $this->info['video']['bitrate'] : 0); + if (($CombinedBitrate > 0) && empty($this->info['bitrate'])) { + $this->info['bitrate'] = $CombinedBitrate; + } + //if ((isset($this->info['video']) && !isset($this->info['video']['bitrate'])) || (isset($this->info['audio']) && !isset($this->info['audio']['bitrate']))) { + // // for example, VBR MPEG video files cannot determine video bitrate: + // // should not set overall bitrate and playtime from audio bitrate only + // unset($this->info['bitrate']); + //} + + // video bitrate undetermined, but calculable + if (isset($this->info['video']['dataformat']) && $this->info['video']['dataformat'] && (!isset($this->info['video']['bitrate']) || ($this->info['video']['bitrate'] == 0))) { + // if video bitrate not set + if (isset($this->info['audio']['bitrate']) && ($this->info['audio']['bitrate'] > 0) && ($this->info['audio']['bitrate'] == $this->info['bitrate'])) { + // AND if audio bitrate is set to same as overall bitrate + if (isset($this->info['playtime_seconds']) && ($this->info['playtime_seconds'] > 0)) { + // AND if playtime is set + if (isset($this->info['avdataend']) && isset($this->info['avdataoffset'])) { + // AND if AV data offset start/end is known + // THEN we can calculate the video bitrate + $this->info['bitrate'] = round((($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']); + $this->info['video']['bitrate'] = $this->info['bitrate'] - $this->info['audio']['bitrate']; + } + } + } + } + + if ((!isset($this->info['playtime_seconds']) || ($this->info['playtime_seconds'] <= 0)) && !empty($this->info['bitrate'])) { + $this->info['playtime_seconds'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['bitrate']; + } + + if (!isset($this->info['bitrate']) && !empty($this->info['playtime_seconds'])) { + $this->info['bitrate'] = (($this->info['avdataend'] - $this->info['avdataoffset']) * 8) / $this->info['playtime_seconds']; + } + if (isset($this->info['bitrate']) && empty($this->info['audio']['bitrate']) && empty($this->info['video']['bitrate'])) { + if (isset($this->info['audio']['dataformat']) && empty($this->info['video']['resolution_x'])) { + // audio only + $this->info['audio']['bitrate'] = $this->info['bitrate']; + } elseif (isset($this->info['video']['resolution_x']) && empty($this->info['audio']['dataformat'])) { + // video only + $this->info['video']['bitrate'] = $this->info['bitrate']; + } + } + + // Set playtime string + if (!empty($this->info['playtime_seconds']) && empty($this->info['playtime_string'])) { + $this->info['playtime_string'] = getid3_lib::PlaytimeString($this->info['playtime_seconds']); + } + } + + + public function CalculateCompressionRatioVideo() { + if (empty($this->info['video'])) { + return false; + } + if (empty($this->info['video']['resolution_x']) || empty($this->info['video']['resolution_y'])) { + return false; + } + if (empty($this->info['video']['bits_per_sample'])) { + return false; + } + + switch ($this->info['video']['dataformat']) { + case 'bmp': + case 'gif': + case 'jpeg': + case 'jpg': + case 'png': + case 'tiff': + $FrameRate = 1; + $PlaytimeSeconds = 1; + $BitrateCompressed = $this->info['filesize'] * 8; + break; + + default: + if (!empty($this->info['video']['frame_rate'])) { + $FrameRate = $this->info['video']['frame_rate']; + } else { + return false; + } + if (!empty($this->info['playtime_seconds'])) { + $PlaytimeSeconds = $this->info['playtime_seconds']; + } else { + return false; + } + if (!empty($this->info['video']['bitrate'])) { + $BitrateCompressed = $this->info['video']['bitrate']; + } else { + return false; + } + break; + } + $BitrateUncompressed = $this->info['video']['resolution_x'] * $this->info['video']['resolution_y'] * $this->info['video']['bits_per_sample'] * $FrameRate; + + $this->info['video']['compression_ratio'] = $BitrateCompressed / $BitrateUncompressed; + return true; + } + + + public function CalculateCompressionRatioAudio() { + if (empty($this->info['audio']['bitrate']) || empty($this->info['audio']['channels']) || empty($this->info['audio']['sample_rate']) || !is_numeric($this->info['audio']['sample_rate'])) { + return false; + } + $this->info['audio']['compression_ratio'] = $this->info['audio']['bitrate'] / ($this->info['audio']['channels'] * $this->info['audio']['sample_rate'] * (!empty($this->info['audio']['bits_per_sample']) ? $this->info['audio']['bits_per_sample'] : 16)); + + if (!empty($this->info['audio']['streams'])) { + foreach ($this->info['audio']['streams'] as $streamnumber => $streamdata) { + if (!empty($streamdata['bitrate']) && !empty($streamdata['channels']) && !empty($streamdata['sample_rate'])) { + $this->info['audio']['streams'][$streamnumber]['compression_ratio'] = $streamdata['bitrate'] / ($streamdata['channels'] * $streamdata['sample_rate'] * (!empty($streamdata['bits_per_sample']) ? $streamdata['bits_per_sample'] : 16)); + } + } + } + return true; + } + + + public function CalculateReplayGain() { + if (isset($this->info['replay_gain'])) { + if (!isset($this->info['replay_gain']['reference_volume'])) { + $this->info['replay_gain']['reference_volume'] = (double) 89.0; + } + if (isset($this->info['replay_gain']['track']['adjustment'])) { + $this->info['replay_gain']['track']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['track']['adjustment']; + } + if (isset($this->info['replay_gain']['album']['adjustment'])) { + $this->info['replay_gain']['album']['volume'] = $this->info['replay_gain']['reference_volume'] - $this->info['replay_gain']['album']['adjustment']; + } + + if (isset($this->info['replay_gain']['track']['peak'])) { + $this->info['replay_gain']['track']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['track']['peak']); + } + if (isset($this->info['replay_gain']['album']['peak'])) { + $this->info['replay_gain']['album']['max_noclip_gain'] = 0 - getid3_lib::RGADamplitude2dB($this->info['replay_gain']['album']['peak']); + } + } + return true; + } + + public function ProcessAudioStreams() { + if (!empty($this->info['audio']['bitrate']) || !empty($this->info['audio']['channels']) || !empty($this->info['audio']['sample_rate'])) { + if (!isset($this->info['audio']['streams'])) { + foreach ($this->info['audio'] as $key => $value) { + if ($key != 'streams') { + $this->info['audio']['streams'][0][$key] = $value; + } + } + } + } + return true; + } + + public function getid3_tempnam() { + return tempnam($this->tempdir, 'gI3'); + } + + public function include_module($name) { + //if (!file_exists($this->include_path.'module.'.$name.'.php')) { + if (!file_exists(GETID3_INCLUDEPATH.'module.'.$name.'.php')) { + throw new getid3_exception('Required module.'.$name.'.php is missing.'); + } + include_once(GETID3_INCLUDEPATH.'module.'.$name.'.php'); + return true; + } + +} + + +abstract class getid3_handler +{ + protected $getid3; // pointer + + protected $data_string_flag = false; // analyzing filepointer or string + protected $data_string = ''; // string to analyze + protected $data_string_position = 0; // seek position in string + protected $data_string_length = 0; // string length + + private $dependency_to = null; + + + public function __construct(getID3 $getid3, $call_module=null) { + $this->getid3 = $getid3; + + if ($call_module) { + $this->dependency_to = str_replace('getid3_', '', $call_module); + } + } + + + // Analyze from file pointer + abstract public function Analyze(); + + + // Analyze from string instead + public function AnalyzeString($string) { + // Enter string mode + $this->setStringMode($string); + + // Save info + $saved_avdataoffset = $this->getid3->info['avdataoffset']; + $saved_avdataend = $this->getid3->info['avdataend']; + $saved_filesize = (isset($this->getid3->info['filesize']) ? $this->getid3->info['filesize'] : null); // may be not set if called as dependency without openfile() call + + // Reset some info + $this->getid3->info['avdataoffset'] = 0; + $this->getid3->info['avdataend'] = $this->getid3->info['filesize'] = $this->data_string_length; + + // Analyze + $this->Analyze(); + + // Restore some info + $this->getid3->info['avdataoffset'] = $saved_avdataoffset; + $this->getid3->info['avdataend'] = $saved_avdataend; + $this->getid3->info['filesize'] = $saved_filesize; + + // Exit string mode + $this->data_string_flag = false; + } + + public function setStringMode($string) { + $this->data_string_flag = true; + $this->data_string = $string; + $this->data_string_length = strlen($string); + } + + protected function ftell() { + if ($this->data_string_flag) { + return $this->data_string_position; + } + return ftell($this->getid3->fp); + } + + protected function fread($bytes) { + if ($this->data_string_flag) { + $this->data_string_position += $bytes; + return substr($this->data_string, $this->data_string_position - $bytes, $bytes); + } + $pos = $this->ftell() + $bytes; + if (!getid3_lib::intValueSupported($pos)) { + throw new getid3_exception('cannot fread('.$bytes.' from '.$this->ftell().') because beyond PHP filesystem limit', 10); + } + return fread($this->getid3->fp, $bytes); + } + + protected function fseek($bytes, $whence=SEEK_SET) { + if ($this->data_string_flag) { + switch ($whence) { + case SEEK_SET: + $this->data_string_position = $bytes; + break; + + case SEEK_CUR: + $this->data_string_position += $bytes; + break; + + case SEEK_END: + $this->data_string_position = $this->data_string_length + $bytes; + break; + } + return 0; + } else { + $pos = $bytes; + if ($whence == SEEK_CUR) { + $pos = $this->ftell() + $bytes; + } elseif ($whence == SEEK_END) { + $pos = $this->info['filesize'] + $bytes; + } + if (!getid3_lib::intValueSupported($pos)) { + throw new getid3_exception('cannot fseek('.$pos.') because beyond PHP filesystem limit', 10); + } + } + return fseek($this->getid3->fp, $bytes, $whence); + } + + protected function feof() { + if ($this->data_string_flag) { + return $this->data_string_position >= $this->data_string_length; + } + return feof($this->getid3->fp); + } + + final protected function isDependencyFor($module) { + return $this->dependency_to == $module; + } + + protected function error($text) + { + $this->getid3->info['error'][] = $text; + + return false; + } + + protected function warning($text) + { + return $this->getid3->warning($text); + } + + protected function notice($text) + { + // does nothing for now + } + + public function saveAttachment($name, $offset, $length, $image_mime=null) { + try { + + // do not extract at all + if ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_NONE) { + + $attachment = null; // do not set any + + // extract to return array + } elseif ($this->getid3->option_save_attachments === getID3::ATTACHMENTS_INLINE) { + + $this->fseek($offset); + $attachment = $this->fread($length); // get whole data in one pass, till it is anyway stored in memory + if ($attachment === false || strlen($attachment) != $length) { + throw new Exception('failed to read attachment data'); + } + + // assume directory path is given + } else { + + // set up destination path + $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); + if (!is_dir($dir) || !is_writable($dir)) { // check supplied directory + throw new Exception('supplied path ('.$dir.') does not exist, or is not writable'); + } + $dest = $dir.DIRECTORY_SEPARATOR.$name.($image_mime ? '.'.getid3_lib::ImageExtFromMime($image_mime) : ''); + + // create dest file + if (($fp_dest = fopen($dest, 'wb')) == false) { + throw new Exception('failed to create file '.$dest); + } + + // copy data + $this->fseek($offset); + $buffersize = ($this->data_string_flag ? $length : $this->getid3->fread_buffer_size()); + $bytesleft = $length; + while ($bytesleft > 0) { + if (($buffer = $this->fread(min($buffersize, $bytesleft))) === false || ($byteswritten = fwrite($fp_dest, $buffer)) === false || ($byteswritten === 0)) { + throw new Exception($buffer === false ? 'not enough data to read' : 'failed to write to destination file, may be not enough disk space'); + } + $bytesleft -= $byteswritten; + } + + fclose($fp_dest); + $attachment = $dest; + + } + + } catch (Exception $e) { + + // close and remove dest file if created + if (isset($fp_dest) && is_resource($fp_dest)) { + fclose($fp_dest); + unlink($dest); + } + + // do not set any is case of error + $attachment = null; + $this->warning('Failed to extract attachment '.$name.': '.$e->getMessage()); + + } + + // seek to the end of attachment + $this->fseek($offset + $length); + + return $attachment; + } + +} + + +class getid3_exception extends Exception +{ + public $message; +} diff --git a/app/libs/vendor/getid3/module.archive.gzip.php b/app/libs/vendor/getid3/module.archive.gzip.php index 3f5036ad..0631d128 100644 --- a/app/libs/vendor/getid3/module.archive.gzip.php +++ b/app/libs/vendor/getid3/module.archive.gzip.php @@ -1,280 +1,280 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.gzip.php // -// module for analyzing GZIP files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// -// // -// Module originally written by // -// Mike Mozolin // -// // -///////////////////////////////////////////////////////////////// - - -class getid3_gzip extends getid3_handler { - - // public: Optional file list - disable for speed. - public $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example) - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'gzip'; - - $start_length = 10; - $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os'; - //+---+---+---+---+---+---+---+---+---+---+ - //|ID1|ID2|CM |FLG| MTIME |XFL|OS | - //+---+---+---+---+---+---+---+---+---+---+ - - if ($info['filesize'] > $info['php_memory_limit']) { - $info['error'][] = 'File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)'; - return false; - } - fseek($this->getid3->fp, 0); - $buffer = fread($this->getid3->fp, $info['filesize']); - - $arr_members = explode("\x1F\x8B\x08", $buffer); - while (true) { - $is_wrong_members = false; - $num_members = intval(count($arr_members)); - for ($i = 0; $i < $num_members; $i++) { - if (strlen($arr_members[$i]) == 0) { - continue; - } - $buf = "\x1F\x8B\x08".$arr_members[$i]; - - $attr = unpack($unpack_header, substr($buf, 0, $start_length)); - if (!$this->get_os_type(ord($attr['os']))) { - // Merge member with previous if wrong OS type - $arr_members[$i - 1] .= $buf; - $arr_members[$i] = ''; - $is_wrong_members = true; - continue; - } - } - if (!$is_wrong_members) { - break; - } - } - - $info['gzip']['files'] = array(); - - $fpointer = 0; - $idx = 0; - for ($i = 0; $i < $num_members; $i++) { - if (strlen($arr_members[$i]) == 0) { - continue; - } - $thisInfo = &$info['gzip']['member_header'][++$idx]; - - $buff = "\x1F\x8B\x08".$arr_members[$i]; - - $attr = unpack($unpack_header, substr($buff, 0, $start_length)); - $thisInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']); - $thisInfo['raw']['id1'] = ord($attr['cmethod']); - $thisInfo['raw']['id2'] = ord($attr['cmethod']); - $thisInfo['raw']['cmethod'] = ord($attr['cmethod']); - $thisInfo['raw']['os'] = ord($attr['os']); - $thisInfo['raw']['xflags'] = ord($attr['xflags']); - $thisInfo['raw']['flags'] = ord($attr['flags']); - - $thisInfo['flags']['crc16'] = (bool) ($thisInfo['raw']['flags'] & 0x02); - $thisInfo['flags']['extra'] = (bool) ($thisInfo['raw']['flags'] & 0x04); - $thisInfo['flags']['filename'] = (bool) ($thisInfo['raw']['flags'] & 0x08); - $thisInfo['flags']['comment'] = (bool) ($thisInfo['raw']['flags'] & 0x10); - - $thisInfo['compression'] = $this->get_xflag_type($thisInfo['raw']['xflags']); - - $thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']); - if (!$thisInfo['os']) { - $info['error'][] = 'Read error on gzip file'; - return false; - } - - $fpointer = 10; - $arr_xsubfield = array(); - // bit 2 - FLG.FEXTRA - //+---+---+=================================+ - //| XLEN |...XLEN bytes of "extra field"...| - //+---+---+=================================+ - if ($thisInfo['flags']['extra']) { - $w_xlen = substr($buff, $fpointer, 2); - $xlen = getid3_lib::LittleEndian2Int($w_xlen); - $fpointer += 2; - - $thisInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen); - // Extra SubFields - //+---+---+---+---+==================================+ - //|SI1|SI2| LEN |... LEN bytes of subfield data ...| - //+---+---+---+---+==================================+ - $idx = 0; - while (true) { - if ($idx >= $xlen) { - break; - } - $si1 = ord(substr($buff, $fpointer + $idx++, 1)); - $si2 = ord(substr($buff, $fpointer + $idx++, 1)); - if (($si1 == 0x41) && ($si2 == 0x70)) { - $w_xsublen = substr($buff, $fpointer + $idx, 2); - $xsublen = getid3_lib::LittleEndian2Int($w_xsublen); - $idx += 2; - $arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen); - $idx += $xsublen; - } else { - break; - } - } - $fpointer += $xlen; - } - // bit 3 - FLG.FNAME - //+=========================================+ - //|...original file name, zero-terminated...| - //+=========================================+ - // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz - $thisInfo['filename'] = preg_replace('#\\.gz$#i', '', $info['filename']); - if ($thisInfo['flags']['filename']) { - $thisInfo['filename'] = ''; - while (true) { - if (ord($buff[$fpointer]) == 0) { - $fpointer++; - break; - } - $thisInfo['filename'] .= $buff[$fpointer]; - $fpointer++; - } - } - // bit 4 - FLG.FCOMMENT - //+===================================+ - //|...file comment, zero-terminated...| - //+===================================+ - if ($thisInfo['flags']['comment']) { - while (true) { - if (ord($buff[$fpointer]) == 0) { - $fpointer++; - break; - } - $thisInfo['comment'] .= $buff[$fpointer]; - $fpointer++; - } - } - // bit 1 - FLG.FHCRC - //+---+---+ - //| CRC16 | - //+---+---+ - if ($thisInfo['flags']['crc16']) { - $w_crc = substr($buff, $fpointer, 2); - $thisInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc); - $fpointer += 2; - } - // bit 0 - FLG.FTEXT - //if ($thisInfo['raw']['flags'] & 0x01) { - // Ignored... - //} - // bits 5, 6, 7 - reserved - - $thisInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4)); - $thisInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4)); - - $info['gzip']['files'] = getid3_lib::array_merge_clobber($info['gzip']['files'], getid3_lib::CreateDeepArray($thisInfo['filename'], '/', $thisInfo['filesize'])); - - if ($this->option_gzip_parse_contents) { - // Try to inflate GZip - $csize = 0; - $inflated = ''; - $chkcrc32 = ''; - if (function_exists('gzinflate')) { - $cdata = substr($buff, $fpointer); - $cdata = substr($cdata, 0, strlen($cdata) - 8); - $csize = strlen($cdata); - $inflated = gzinflate($cdata); - - // Calculate CRC32 for inflated content - $thisInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisInfo['crc32']); - - // determine format - $formattest = substr($inflated, 0, 32774); - $getid3_temp = new getID3(); - $determined_format = $getid3_temp->GetFileFormat($formattest); - unset($getid3_temp); - - // file format is determined - $determined_format['module'] = (isset($determined_format['module']) ? $determined_format['module'] : ''); - switch ($determined_format['module']) { - case 'tar': - // view TAR-file info - if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) { - if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) { - // can't find anywhere to create a temp file, abort - $info['error'][] = 'Unable to create temp file to parse TAR inside GZIP file'; - break; - } - if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) { - fwrite($fp_temp_tar, $inflated); - fclose($fp_temp_tar); - $getid3_temp = new getID3(); - $getid3_temp->openfile($temp_tar_filename); - $getid3_tar = new getid3_tar($getid3_temp); - $getid3_tar->Analyze(); - $info['gzip']['member_header'][$idx]['tar'] = $getid3_temp->info['tar']; - unset($getid3_temp, $getid3_tar); - unlink($temp_tar_filename); - } else { - $info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file'; - break; - } - } - break; - - case '': - default: - // unknown or unhandled format - break; - } - } - } - } - return true; - } - - // Converts the OS type - public function get_os_type($key) { - static $os_type = array( - '0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)', - '1' => 'Amiga', - '2' => 'VMS (or OpenVMS)', - '3' => 'Unix', - '4' => 'VM/CMS', - '5' => 'Atari TOS', - '6' => 'HPFS filesystem (OS/2, NT)', - '7' => 'Macintosh', - '8' => 'Z-System', - '9' => 'CP/M', - '10' => 'TOPS-20', - '11' => 'NTFS filesystem (NT)', - '12' => 'QDOS', - '13' => 'Acorn RISCOS', - '255' => 'unknown' - ); - return (isset($os_type[$key]) ? $os_type[$key] : ''); - } - - // Converts the eXtra FLags - public function get_xflag_type($key) { - static $xflag_type = array( - '0' => 'unknown', - '2' => 'maximum compression', - '4' => 'fastest algorithm' - ); - return (isset($xflag_type[$key]) ? $xflag_type[$key] : ''); - } -} - + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.gzip.php // +// module for analyzing GZIP files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// +// // +// Module originally written by // +// Mike Mozolin // +// // +///////////////////////////////////////////////////////////////// + + +class getid3_gzip extends getid3_handler { + + // public: Optional file list - disable for speed. + public $option_gzip_parse_contents = false; // decode gzipped files, if possible, and parse recursively (.tar.gz for example) + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'gzip'; + + $start_length = 10; + $unpack_header = 'a1id1/a1id2/a1cmethod/a1flags/a4mtime/a1xflags/a1os'; + //+---+---+---+---+---+---+---+---+---+---+ + //|ID1|ID2|CM |FLG| MTIME |XFL|OS | + //+---+---+---+---+---+---+---+---+---+---+ + + if ($info['filesize'] > $info['php_memory_limit']) { + $info['error'][] = 'File is too large ('.number_format($info['filesize']).' bytes) to read into memory (limit: '.number_format($info['php_memory_limit'] / 1048576).'MB)'; + return false; + } + fseek($this->getid3->fp, 0); + $buffer = fread($this->getid3->fp, $info['filesize']); + + $arr_members = explode("\x1F\x8B\x08", $buffer); + while (true) { + $is_wrong_members = false; + $num_members = intval(count($arr_members)); + for ($i = 0; $i < $num_members; $i++) { + if (strlen($arr_members[$i]) == 0) { + continue; + } + $buf = "\x1F\x8B\x08".$arr_members[$i]; + + $attr = unpack($unpack_header, substr($buf, 0, $start_length)); + if (!$this->get_os_type(ord($attr['os']))) { + // Merge member with previous if wrong OS type + $arr_members[$i - 1] .= $buf; + $arr_members[$i] = ''; + $is_wrong_members = true; + continue; + } + } + if (!$is_wrong_members) { + break; + } + } + + $info['gzip']['files'] = array(); + + $fpointer = 0; + $idx = 0; + for ($i = 0; $i < $num_members; $i++) { + if (strlen($arr_members[$i]) == 0) { + continue; + } + $thisInfo = &$info['gzip']['member_header'][++$idx]; + + $buff = "\x1F\x8B\x08".$arr_members[$i]; + + $attr = unpack($unpack_header, substr($buff, 0, $start_length)); + $thisInfo['filemtime'] = getid3_lib::LittleEndian2Int($attr['mtime']); + $thisInfo['raw']['id1'] = ord($attr['cmethod']); + $thisInfo['raw']['id2'] = ord($attr['cmethod']); + $thisInfo['raw']['cmethod'] = ord($attr['cmethod']); + $thisInfo['raw']['os'] = ord($attr['os']); + $thisInfo['raw']['xflags'] = ord($attr['xflags']); + $thisInfo['raw']['flags'] = ord($attr['flags']); + + $thisInfo['flags']['crc16'] = (bool) ($thisInfo['raw']['flags'] & 0x02); + $thisInfo['flags']['extra'] = (bool) ($thisInfo['raw']['flags'] & 0x04); + $thisInfo['flags']['filename'] = (bool) ($thisInfo['raw']['flags'] & 0x08); + $thisInfo['flags']['comment'] = (bool) ($thisInfo['raw']['flags'] & 0x10); + + $thisInfo['compression'] = $this->get_xflag_type($thisInfo['raw']['xflags']); + + $thisInfo['os'] = $this->get_os_type($thisInfo['raw']['os']); + if (!$thisInfo['os']) { + $info['error'][] = 'Read error on gzip file'; + return false; + } + + $fpointer = 10; + $arr_xsubfield = array(); + // bit 2 - FLG.FEXTRA + //+---+---+=================================+ + //| XLEN |...XLEN bytes of "extra field"...| + //+---+---+=================================+ + if ($thisInfo['flags']['extra']) { + $w_xlen = substr($buff, $fpointer, 2); + $xlen = getid3_lib::LittleEndian2Int($w_xlen); + $fpointer += 2; + + $thisInfo['raw']['xfield'] = substr($buff, $fpointer, $xlen); + // Extra SubFields + //+---+---+---+---+==================================+ + //|SI1|SI2| LEN |... LEN bytes of subfield data ...| + //+---+---+---+---+==================================+ + $idx = 0; + while (true) { + if ($idx >= $xlen) { + break; + } + $si1 = ord(substr($buff, $fpointer + $idx++, 1)); + $si2 = ord(substr($buff, $fpointer + $idx++, 1)); + if (($si1 == 0x41) && ($si2 == 0x70)) { + $w_xsublen = substr($buff, $fpointer + $idx, 2); + $xsublen = getid3_lib::LittleEndian2Int($w_xsublen); + $idx += 2; + $arr_xsubfield[] = substr($buff, $fpointer + $idx, $xsublen); + $idx += $xsublen; + } else { + break; + } + } + $fpointer += $xlen; + } + // bit 3 - FLG.FNAME + //+=========================================+ + //|...original file name, zero-terminated...| + //+=========================================+ + // GZIP files may have only one file, with no filename, so assume original filename is current filename without .gz + $thisInfo['filename'] = preg_replace('#\\.gz$#i', '', $info['filename']); + if ($thisInfo['flags']['filename']) { + $thisInfo['filename'] = ''; + while (true) { + if (ord($buff[$fpointer]) == 0) { + $fpointer++; + break; + } + $thisInfo['filename'] .= $buff[$fpointer]; + $fpointer++; + } + } + // bit 4 - FLG.FCOMMENT + //+===================================+ + //|...file comment, zero-terminated...| + //+===================================+ + if ($thisInfo['flags']['comment']) { + while (true) { + if (ord($buff[$fpointer]) == 0) { + $fpointer++; + break; + } + $thisInfo['comment'] .= $buff[$fpointer]; + $fpointer++; + } + } + // bit 1 - FLG.FHCRC + //+---+---+ + //| CRC16 | + //+---+---+ + if ($thisInfo['flags']['crc16']) { + $w_crc = substr($buff, $fpointer, 2); + $thisInfo['crc16'] = getid3_lib::LittleEndian2Int($w_crc); + $fpointer += 2; + } + // bit 0 - FLG.FTEXT + //if ($thisInfo['raw']['flags'] & 0x01) { + // Ignored... + //} + // bits 5, 6, 7 - reserved + + $thisInfo['crc32'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 8, 4)); + $thisInfo['filesize'] = getid3_lib::LittleEndian2Int(substr($buff, strlen($buff) - 4)); + + $info['gzip']['files'] = getid3_lib::array_merge_clobber($info['gzip']['files'], getid3_lib::CreateDeepArray($thisInfo['filename'], '/', $thisInfo['filesize'])); + + if ($this->option_gzip_parse_contents) { + // Try to inflate GZip + $csize = 0; + $inflated = ''; + $chkcrc32 = ''; + if (function_exists('gzinflate')) { + $cdata = substr($buff, $fpointer); + $cdata = substr($cdata, 0, strlen($cdata) - 8); + $csize = strlen($cdata); + $inflated = gzinflate($cdata); + + // Calculate CRC32 for inflated content + $thisInfo['crc32_valid'] = (bool) (sprintf('%u', crc32($inflated)) == $thisInfo['crc32']); + + // determine format + $formattest = substr($inflated, 0, 32774); + $getid3_temp = new getID3(); + $determined_format = $getid3_temp->GetFileFormat($formattest); + unset($getid3_temp); + + // file format is determined + $determined_format['module'] = (isset($determined_format['module']) ? $determined_format['module'] : ''); + switch ($determined_format['module']) { + case 'tar': + // view TAR-file info + if (file_exists(GETID3_INCLUDEPATH.$determined_format['include']) && include_once(GETID3_INCLUDEPATH.$determined_format['include'])) { + if (($temp_tar_filename = tempnam(GETID3_TEMP_DIR, 'getID3')) === false) { + // can't find anywhere to create a temp file, abort + $info['error'][] = 'Unable to create temp file to parse TAR inside GZIP file'; + break; + } + if ($fp_temp_tar = fopen($temp_tar_filename, 'w+b')) { + fwrite($fp_temp_tar, $inflated); + fclose($fp_temp_tar); + $getid3_temp = new getID3(); + $getid3_temp->openfile($temp_tar_filename); + $getid3_tar = new getid3_tar($getid3_temp); + $getid3_tar->Analyze(); + $info['gzip']['member_header'][$idx]['tar'] = $getid3_temp->info['tar']; + unset($getid3_temp, $getid3_tar); + unlink($temp_tar_filename); + } else { + $info['error'][] = 'Unable to fopen() temp file to parse TAR inside GZIP file'; + break; + } + } + break; + + case '': + default: + // unknown or unhandled format + break; + } + } + } + } + return true; + } + + // Converts the OS type + public function get_os_type($key) { + static $os_type = array( + '0' => 'FAT filesystem (MS-DOS, OS/2, NT/Win32)', + '1' => 'Amiga', + '2' => 'VMS (or OpenVMS)', + '3' => 'Unix', + '4' => 'VM/CMS', + '5' => 'Atari TOS', + '6' => 'HPFS filesystem (OS/2, NT)', + '7' => 'Macintosh', + '8' => 'Z-System', + '9' => 'CP/M', + '10' => 'TOPS-20', + '11' => 'NTFS filesystem (NT)', + '12' => 'QDOS', + '13' => 'Acorn RISCOS', + '255' => 'unknown' + ); + return (isset($os_type[$key]) ? $os_type[$key] : ''); + } + + // Converts the eXtra FLags + public function get_xflag_type($key) { + static $xflag_type = array( + '0' => 'unknown', + '2' => 'maximum compression', + '4' => 'fastest algorithm' + ); + return (isset($xflag_type[$key]) ? $xflag_type[$key] : ''); + } +} + diff --git a/app/libs/vendor/getid3/module.archive.rar.php b/app/libs/vendor/getid3/module.archive.rar.php index 0b777eae..e3155e40 100644 --- a/app/libs/vendor/getid3/module.archive.rar.php +++ b/app/libs/vendor/getid3/module.archive.rar.php @@ -1,50 +1,50 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.rar.php // -// module for analyzing RAR files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_rar extends getid3_handler -{ - - public $option_use_rar_extension = false; - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'rar'; - - if ($this->option_use_rar_extension === true) { - if (function_exists('rar_open')) { - if ($rp = rar_open($info['filenamepath'])) { - $info['rar']['files'] = array(); - $entries = rar_list($rp); - foreach ($entries as $entry) { - $info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize())); - } - rar_close($rp); - return true; - } else { - $info['error'][] = 'failed to rar_open('.$info['filename'].')'; - } - } else { - $info['error'][] = 'RAR support does not appear to be available in this PHP installation'; - } - } else { - $info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)'; - } - return false; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.rar.php // +// module for analyzing RAR files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_rar extends getid3_handler +{ + + public $option_use_rar_extension = false; + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'rar'; + + if ($this->option_use_rar_extension === true) { + if (function_exists('rar_open')) { + if ($rp = rar_open($info['filenamepath'])) { + $info['rar']['files'] = array(); + $entries = rar_list($rp); + foreach ($entries as $entry) { + $info['rar']['files'] = getid3_lib::array_merge_clobber($info['rar']['files'], getid3_lib::CreateDeepArray($entry->getName(), '/', $entry->getUnpackedSize())); + } + rar_close($rp); + return true; + } else { + $info['error'][] = 'failed to rar_open('.$info['filename'].')'; + } + } else { + $info['error'][] = 'RAR support does not appear to be available in this PHP installation'; + } + } else { + $info['error'][] = 'PHP-RAR processing has been disabled (set $getid3_rar->option_use_rar_extension=true to enable)'; + } + return false; + + } + +} diff --git a/app/libs/vendor/getid3/module.archive.szip.php b/app/libs/vendor/getid3/module.archive.szip.php index 56a5034d..6f41d2f3 100644 --- a/app/libs/vendor/getid3/module.archive.szip.php +++ b/app/libs/vendor/getid3/module.archive.szip.php @@ -1,96 +1,96 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.szip.php // -// module for analyzing SZIP compressed files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_szip extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $this->fseek($info['avdataoffset']); - $SZIPHeader = $this->fread(6); - if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") { - $info['error'][] = 'Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"'; - return false; - } - $info['fileformat'] = 'szip'; - $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1)); - $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1)); -$info['error'][] = 'SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - - while (!$this->feof()) { - $NextBlockID = $this->fread(2); - switch ($NextBlockID) { - case 'SZ': - // Note that szip files can be concatenated, this has the same effect as - // concatenating the files. this also means that global header blocks - // might be present between directory/data blocks. - $this->fseek(4, SEEK_CUR); - break; - - case 'BH': - $BHheaderbytes = getid3_lib::BigEndian2Int($this->fread(3)); - $BHheaderdata = $this->fread($BHheaderbytes); - $BHheaderoffset = 0; - while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) { - //filename as \0 terminated string (empty string indicates end) - //owner as \0 terminated string (empty is same as last file) - //group as \0 terminated string (empty is same as last file) - //3 byte filelength in this block - //2 byte access flags - //4 byte creation time (like in unix) - //4 byte modification time (like in unix) - //4 byte access time (like in unix) - - $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); - $BHheaderoffset += (strlen($BHdataArray['filename']) + 1); - - $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); - $BHheaderoffset += (strlen($BHdataArray['owner']) + 1); - - $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); - $BHheaderoffset += (strlen($BHdataArray['group']) + 1); - - $BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3)); - $BHheaderoffset += 3; - - $BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2)); - $BHheaderoffset += 2; - - $BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); - $BHheaderoffset += 4; - - $BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); - $BHheaderoffset += 4; - - $BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); - $BHheaderoffset += 4; - - $info['szip']['BH'][] = $BHdataArray; - } - break; - - default: - break 2; - } - } - - return true; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.szip.php // +// module for analyzing SZIP compressed files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_szip extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $this->fseek($info['avdataoffset']); + $SZIPHeader = $this->fread(6); + if (substr($SZIPHeader, 0, 4) != "SZ\x0A\x04") { + $info['error'][] = 'Expecting "53 5A 0A 04" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($SZIPHeader, 0, 4)).'"'; + return false; + } + $info['fileformat'] = 'szip'; + $info['szip']['major_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 4, 1)); + $info['szip']['minor_version'] = getid3_lib::BigEndian2Int(substr($SZIPHeader, 5, 1)); +$info['error'][] = 'SZIP parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + + while (!$this->feof()) { + $NextBlockID = $this->fread(2); + switch ($NextBlockID) { + case 'SZ': + // Note that szip files can be concatenated, this has the same effect as + // concatenating the files. this also means that global header blocks + // might be present between directory/data blocks. + $this->fseek(4, SEEK_CUR); + break; + + case 'BH': + $BHheaderbytes = getid3_lib::BigEndian2Int($this->fread(3)); + $BHheaderdata = $this->fread($BHheaderbytes); + $BHheaderoffset = 0; + while (strpos($BHheaderdata, "\x00", $BHheaderoffset) > 0) { + //filename as \0 terminated string (empty string indicates end) + //owner as \0 terminated string (empty is same as last file) + //group as \0 terminated string (empty is same as last file) + //3 byte filelength in this block + //2 byte access flags + //4 byte creation time (like in unix) + //4 byte modification time (like in unix) + //4 byte access time (like in unix) + + $BHdataArray['filename'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); + $BHheaderoffset += (strlen($BHdataArray['filename']) + 1); + + $BHdataArray['owner'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); + $BHheaderoffset += (strlen($BHdataArray['owner']) + 1); + + $BHdataArray['group'] = substr($BHheaderdata, $BHheaderoffset, strcspn($BHheaderdata, "\x00")); + $BHheaderoffset += (strlen($BHdataArray['group']) + 1); + + $BHdataArray['filelength'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 3)); + $BHheaderoffset += 3; + + $BHdataArray['access_flags'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 2)); + $BHheaderoffset += 2; + + $BHdataArray['creation_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); + $BHheaderoffset += 4; + + $BHdataArray['modification_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); + $BHheaderoffset += 4; + + $BHdataArray['access_time'] = getid3_lib::BigEndian2Int(substr($BHheaderdata, $BHheaderoffset, 4)); + $BHheaderoffset += 4; + + $info['szip']['BH'][] = $BHdataArray; + } + break; + + default: + break 2; + } + } + + return true; + + } + +} diff --git a/app/libs/vendor/getid3/module.archive.tar.php b/app/libs/vendor/getid3/module.archive.tar.php index 93d6124b..0851aa1e 100644 --- a/app/libs/vendor/getid3/module.archive.tar.php +++ b/app/libs/vendor/getid3/module.archive.tar.php @@ -1,176 +1,176 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.tar.php // -// module for analyzing TAR files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// -// // -// Module originally written by // -// Mike Mozolin // -// // -///////////////////////////////////////////////////////////////// - - -class getid3_tar extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'tar'; - $info['tar']['files'] = array(); - - $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix'; - $null_512k = str_repeat("\x00", 512); // end-of-file marker - - fseek($this->getid3->fp, 0); - while (!feof($this->getid3->fp)) { - $buffer = fread($this->getid3->fp, 512); - if (strlen($buffer) < 512) { - break; - } - - // check the block - $checksum = 0; - for ($i = 0; $i < 148; $i++) { - $checksum += ord($buffer{$i}); - } - for ($i = 148; $i < 156; $i++) { - $checksum += ord(' '); - } - for ($i = 156; $i < 512; $i++) { - $checksum += ord($buffer{$i}); - } - $attr = unpack($unpack_header, $buffer); - $name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : ''); - $mode = octdec(isset($attr['mode'] ) ? trim($attr['mode'] ) : ''); - $uid = octdec(isset($attr['uid'] ) ? trim($attr['uid'] ) : ''); - $gid = octdec(isset($attr['gid'] ) ? trim($attr['gid'] ) : ''); - $size = octdec(isset($attr['size'] ) ? trim($attr['size'] ) : ''); - $mtime = octdec(isset($attr['mtime'] ) ? trim($attr['mtime'] ) : ''); - $chksum = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : ''); - $typflag = (isset($attr['typflag']) ? trim($attr['typflag']) : ''); - $lnkname = (isset($attr['lnkname']) ? trim($attr['lnkname']) : ''); - $magic = (isset($attr['magic'] ) ? trim($attr['magic'] ) : ''); - $ver = (isset($attr['ver'] ) ? trim($attr['ver'] ) : ''); - $uname = (isset($attr['uname'] ) ? trim($attr['uname'] ) : ''); - $gname = (isset($attr['gname'] ) ? trim($attr['gname'] ) : ''); - $devmaj = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : ''); - $devmin = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : ''); - $prefix = (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : ''); - if (($checksum == 256) && ($chksum == 0)) { - // EOF Found - break; - } - if ($prefix) { - $name = $prefix.'/'.$name; - } - if ((preg_match('#/$#', $name)) && !$name) { - $typeflag = 5; - } - if ($buffer == $null_512k) { - // it's the end of the tar-file... - break; - } - - // Read to the next chunk - fseek($this->getid3->fp, $size, SEEK_CUR); - - $diff = $size % 512; - if ($diff != 0) { - // Padding, throw away - fseek($this->getid3->fp, (512 - $diff), SEEK_CUR); - } - // Protect against tar-files with garbage at the end - if ($name == '') { - break; - } - $info['tar']['file_details'][$name] = array ( - 'name' => $name, - 'mode_raw' => $mode, - 'mode' => self::display_perms($mode), - 'uid' => $uid, - 'gid' => $gid, - 'size' => $size, - 'mtime' => $mtime, - 'chksum' => $chksum, - 'typeflag' => self::get_flag_type($typflag), - 'linkname' => $lnkname, - 'magic' => $magic, - 'version' => $ver, - 'uname' => $uname, - 'gname' => $gname, - 'devmajor' => $devmaj, - 'devminor' => $devmin - ); - $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size)); - } - return true; - } - - // Parses the file mode to file permissions - public function display_perms($mode) { - // Determine Type - if ($mode & 0x1000) $type='p'; // FIFO pipe - elseif ($mode & 0x2000) $type='c'; // Character special - elseif ($mode & 0x4000) $type='d'; // Directory - elseif ($mode & 0x6000) $type='b'; // Block special - elseif ($mode & 0x8000) $type='-'; // Regular - elseif ($mode & 0xA000) $type='l'; // Symbolic Link - elseif ($mode & 0xC000) $type='s'; // Socket - else $type='u'; // UNKNOWN - - // Determine permissions - $owner['read'] = (($mode & 00400) ? 'r' : '-'); - $owner['write'] = (($mode & 00200) ? 'w' : '-'); - $owner['execute'] = (($mode & 00100) ? 'x' : '-'); - $group['read'] = (($mode & 00040) ? 'r' : '-'); - $group['write'] = (($mode & 00020) ? 'w' : '-'); - $group['execute'] = (($mode & 00010) ? 'x' : '-'); - $world['read'] = (($mode & 00004) ? 'r' : '-'); - $world['write'] = (($mode & 00002) ? 'w' : '-'); - $world['execute'] = (($mode & 00001) ? 'x' : '-'); - - // Adjust for SUID, SGID and sticky bit - if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S'; - if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S'; - if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T'; - - $s = sprintf('%1s', $type); - $s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']); - $s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']); - $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']); - return $s; - } - - // Converts the file type - public function get_flag_type($typflag) { - static $flag_types = array( - '0' => 'LF_NORMAL', - '1' => 'LF_LINK', - '2' => 'LF_SYNLINK', - '3' => 'LF_CHR', - '4' => 'LF_BLK', - '5' => 'LF_DIR', - '6' => 'LF_FIFO', - '7' => 'LF_CONFIG', - 'D' => 'LF_DUMPDIR', - 'K' => 'LF_LONGLINK', - 'L' => 'LF_LONGNAME', - 'M' => 'LF_MULTIVOL', - 'N' => 'LF_NAMES', - 'S' => 'LF_SPARSE', - 'V' => 'LF_VOLHDR' - ); - return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : ''); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.tar.php // +// module for analyzing TAR files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// +// // +// Module originally written by // +// Mike Mozolin // +// // +///////////////////////////////////////////////////////////////// + + +class getid3_tar extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'tar'; + $info['tar']['files'] = array(); + + $unpack_header = 'a100fname/a8mode/a8uid/a8gid/a12size/a12mtime/a8chksum/a1typflag/a100lnkname/a6magic/a2ver/a32uname/a32gname/a8devmaj/a8devmin/a155prefix'; + $null_512k = str_repeat("\x00", 512); // end-of-file marker + + fseek($this->getid3->fp, 0); + while (!feof($this->getid3->fp)) { + $buffer = fread($this->getid3->fp, 512); + if (strlen($buffer) < 512) { + break; + } + + // check the block + $checksum = 0; + for ($i = 0; $i < 148; $i++) { + $checksum += ord($buffer{$i}); + } + for ($i = 148; $i < 156; $i++) { + $checksum += ord(' '); + } + for ($i = 156; $i < 512; $i++) { + $checksum += ord($buffer{$i}); + } + $attr = unpack($unpack_header, $buffer); + $name = (isset($attr['fname'] ) ? trim($attr['fname'] ) : ''); + $mode = octdec(isset($attr['mode'] ) ? trim($attr['mode'] ) : ''); + $uid = octdec(isset($attr['uid'] ) ? trim($attr['uid'] ) : ''); + $gid = octdec(isset($attr['gid'] ) ? trim($attr['gid'] ) : ''); + $size = octdec(isset($attr['size'] ) ? trim($attr['size'] ) : ''); + $mtime = octdec(isset($attr['mtime'] ) ? trim($attr['mtime'] ) : ''); + $chksum = octdec(isset($attr['chksum'] ) ? trim($attr['chksum'] ) : ''); + $typflag = (isset($attr['typflag']) ? trim($attr['typflag']) : ''); + $lnkname = (isset($attr['lnkname']) ? trim($attr['lnkname']) : ''); + $magic = (isset($attr['magic'] ) ? trim($attr['magic'] ) : ''); + $ver = (isset($attr['ver'] ) ? trim($attr['ver'] ) : ''); + $uname = (isset($attr['uname'] ) ? trim($attr['uname'] ) : ''); + $gname = (isset($attr['gname'] ) ? trim($attr['gname'] ) : ''); + $devmaj = octdec(isset($attr['devmaj'] ) ? trim($attr['devmaj'] ) : ''); + $devmin = octdec(isset($attr['devmin'] ) ? trim($attr['devmin'] ) : ''); + $prefix = (isset($attr['prefix'] ) ? trim($attr['prefix'] ) : ''); + if (($checksum == 256) && ($chksum == 0)) { + // EOF Found + break; + } + if ($prefix) { + $name = $prefix.'/'.$name; + } + if ((preg_match('#/$#', $name)) && !$name) { + $typeflag = 5; + } + if ($buffer == $null_512k) { + // it's the end of the tar-file... + break; + } + + // Read to the next chunk + fseek($this->getid3->fp, $size, SEEK_CUR); + + $diff = $size % 512; + if ($diff != 0) { + // Padding, throw away + fseek($this->getid3->fp, (512 - $diff), SEEK_CUR); + } + // Protect against tar-files with garbage at the end + if ($name == '') { + break; + } + $info['tar']['file_details'][$name] = array ( + 'name' => $name, + 'mode_raw' => $mode, + 'mode' => self::display_perms($mode), + 'uid' => $uid, + 'gid' => $gid, + 'size' => $size, + 'mtime' => $mtime, + 'chksum' => $chksum, + 'typeflag' => self::get_flag_type($typflag), + 'linkname' => $lnkname, + 'magic' => $magic, + 'version' => $ver, + 'uname' => $uname, + 'gname' => $gname, + 'devmajor' => $devmaj, + 'devminor' => $devmin + ); + $info['tar']['files'] = getid3_lib::array_merge_clobber($info['tar']['files'], getid3_lib::CreateDeepArray($info['tar']['file_details'][$name]['name'], '/', $size)); + } + return true; + } + + // Parses the file mode to file permissions + public function display_perms($mode) { + // Determine Type + if ($mode & 0x1000) $type='p'; // FIFO pipe + elseif ($mode & 0x2000) $type='c'; // Character special + elseif ($mode & 0x4000) $type='d'; // Directory + elseif ($mode & 0x6000) $type='b'; // Block special + elseif ($mode & 0x8000) $type='-'; // Regular + elseif ($mode & 0xA000) $type='l'; // Symbolic Link + elseif ($mode & 0xC000) $type='s'; // Socket + else $type='u'; // UNKNOWN + + // Determine permissions + $owner['read'] = (($mode & 00400) ? 'r' : '-'); + $owner['write'] = (($mode & 00200) ? 'w' : '-'); + $owner['execute'] = (($mode & 00100) ? 'x' : '-'); + $group['read'] = (($mode & 00040) ? 'r' : '-'); + $group['write'] = (($mode & 00020) ? 'w' : '-'); + $group['execute'] = (($mode & 00010) ? 'x' : '-'); + $world['read'] = (($mode & 00004) ? 'r' : '-'); + $world['write'] = (($mode & 00002) ? 'w' : '-'); + $world['execute'] = (($mode & 00001) ? 'x' : '-'); + + // Adjust for SUID, SGID and sticky bit + if ($mode & 0x800) $owner['execute'] = ($owner['execute'] == 'x') ? 's' : 'S'; + if ($mode & 0x400) $group['execute'] = ($group['execute'] == 'x') ? 's' : 'S'; + if ($mode & 0x200) $world['execute'] = ($world['execute'] == 'x') ? 't' : 'T'; + + $s = sprintf('%1s', $type); + $s .= sprintf('%1s%1s%1s', $owner['read'], $owner['write'], $owner['execute']); + $s .= sprintf('%1s%1s%1s', $group['read'], $group['write'], $group['execute']); + $s .= sprintf('%1s%1s%1s'."\n", $world['read'], $world['write'], $world['execute']); + return $s; + } + + // Converts the file type + public function get_flag_type($typflag) { + static $flag_types = array( + '0' => 'LF_NORMAL', + '1' => 'LF_LINK', + '2' => 'LF_SYNLINK', + '3' => 'LF_CHR', + '4' => 'LF_BLK', + '5' => 'LF_DIR', + '6' => 'LF_FIFO', + '7' => 'LF_CONFIG', + 'D' => 'LF_DUMPDIR', + 'K' => 'LF_LONGLINK', + 'L' => 'LF_LONGNAME', + 'M' => 'LF_MULTIVOL', + 'N' => 'LF_NAMES', + 'S' => 'LF_SPARSE', + 'V' => 'LF_VOLHDR' + ); + return (isset($flag_types[$typflag]) ? $flag_types[$typflag] : ''); + } + +} diff --git a/app/libs/vendor/getid3/module.archive.zip.php b/app/libs/vendor/getid3/module.archive.zip.php index 9fc05616..296a7490 100644 --- a/app/libs/vendor/getid3/module.archive.zip.php +++ b/app/libs/vendor/getid3/module.archive.zip.php @@ -1,512 +1,512 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.zip.php // -// module for analyzing pkZip files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_zip extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'zip'; - $info['zip']['encoding'] = 'ISO-8859-1'; - $info['zip']['files'] = array(); - - $info['zip']['compressed_size'] = 0; - $info['zip']['uncompressed_size'] = 0; - $info['zip']['entries_count'] = 0; - - if (!getid3_lib::intValueSupported($info['filesize'])) { - $info['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP'; - return false; - } else { - $EOCDsearchData = ''; - $EOCDsearchCounter = 0; - while ($EOCDsearchCounter++ < 512) { - - fseek($this->getid3->fp, -128 * $EOCDsearchCounter, SEEK_END); - $EOCDsearchData = fread($this->getid3->fp, 128).$EOCDsearchData; - - if (strstr($EOCDsearchData, 'PK'."\x05\x06")) { - - $EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06"); - fseek($this->getid3->fp, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END); - $info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory(); - - fseek($this->getid3->fp, $info['zip']['end_central_directory']['directory_offset'], SEEK_SET); - $info['zip']['entries_count'] = 0; - while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) { - $info['zip']['central_directory'][] = $centraldirectoryentry; - $info['zip']['entries_count']++; - $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size']; - $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size']; - - //if ($centraldirectoryentry['uncompressed_size'] > 0) { zero-byte files are valid - if (!empty($centraldirectoryentry['filename'])) { - $info['zip']['files'] = getid3_lib::array_merge_clobber($info['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size'])); - } - } - - if ($info['zip']['entries_count'] == 0) { - $info['error'][] = 'No Central Directory entries found (truncated file?)'; - return false; - } - - if (!empty($info['zip']['end_central_directory']['comment'])) { - $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment']; - } - - if (isset($info['zip']['central_directory'][0]['compression_method'])) { - $info['zip']['compression_method'] = $info['zip']['central_directory'][0]['compression_method']; - } - if (isset($info['zip']['central_directory'][0]['flags']['compression_speed'])) { - $info['zip']['compression_speed'] = $info['zip']['central_directory'][0]['flags']['compression_speed']; - } - if (isset($info['zip']['compression_method']) && ($info['zip']['compression_method'] == 'store') && !isset($info['zip']['compression_speed'])) { - $info['zip']['compression_speed'] = 'store'; - } - - // secondary check - we (should) already have all the info we NEED from the Central Directory above, but scanning each - // Local File Header entry will - foreach ($info['zip']['central_directory'] as $central_directory_entry) { - fseek($this->getid3->fp, $central_directory_entry['entry_offset'], SEEK_SET); - if ($fileentry = $this->ZIPparseLocalFileHeader()) { - $info['zip']['entries'][] = $fileentry; - } else { - $info['warning'][] = 'Error parsing Local File Header at offset '.$central_directory_entry['entry_offset']; - } - } - - if (!empty($info['zip']['files']['[Content_Types].xml']) && - !empty($info['zip']['files']['_rels']['.rels']) && - !empty($info['zip']['files']['docProps']['app.xml']) && - !empty($info['zip']['files']['docProps']['core.xml'])) { - // http://technet.microsoft.com/en-us/library/cc179224.aspx - $info['fileformat'] = 'zip.msoffice'; - if (!empty($ThisFileInfo['zip']['files']['ppt'])) { - $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; - } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) { - $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; - } elseif (!empty($ThisFileInfo['zip']['files']['word'])) { - $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; - } - } - - return true; - } - } - } - - if (!$this->getZIPentriesFilepointer()) { - unset($info['zip']); - $info['fileformat'] = ''; - $info['error'][] = 'Cannot find End Of Central Directory (truncated file?)'; - return false; - } - - // central directory couldn't be found and/or parsed - // scan through actual file data entries, recover as much as possible from probable trucated file - if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) { - $info['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)'; - } - $info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete'; - foreach ($info['zip']['entries'] as $key => $valuearray) { - $info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size']; - } - return true; - } - - - public function getZIPHeaderFilepointerTopDown() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'zip'; - - $info['zip']['compressed_size'] = 0; - $info['zip']['uncompressed_size'] = 0; - $info['zip']['entries_count'] = 0; - - rewind($this->getid3->fp); - while ($fileentry = $this->ZIPparseLocalFileHeader()) { - $info['zip']['entries'][] = $fileentry; - $info['zip']['entries_count']++; - } - if ($info['zip']['entries_count'] == 0) { - $info['error'][] = 'No Local File Header entries found'; - return false; - } - - $info['zip']['entries_count'] = 0; - while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) { - $info['zip']['central_directory'][] = $centraldirectoryentry; - $info['zip']['entries_count']++; - $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size']; - $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size']; - } - if ($info['zip']['entries_count'] == 0) { - $info['error'][] = 'No Central Directory entries found (truncated file?)'; - return false; - } - - if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) { - $info['zip']['end_central_directory'] = $EOCD; - } else { - $info['error'][] = 'No End Of Central Directory entry found (truncated file?)'; - return false; - } - - if (!empty($info['zip']['end_central_directory']['comment'])) { - $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment']; - } - - return true; - } - - - public function getZIPentriesFilepointer() { - $info = &$this->getid3->info; - - $info['zip']['compressed_size'] = 0; - $info['zip']['uncompressed_size'] = 0; - $info['zip']['entries_count'] = 0; - - rewind($this->getid3->fp); - while ($fileentry = $this->ZIPparseLocalFileHeader()) { - $info['zip']['entries'][] = $fileentry; - $info['zip']['entries_count']++; - $info['zip']['compressed_size'] += $fileentry['compressed_size']; - $info['zip']['uncompressed_size'] += $fileentry['uncompressed_size']; - } - if ($info['zip']['entries_count'] == 0) { - $info['error'][] = 'No Local File Header entries found'; - return false; - } - - return true; - } - - - public function ZIPparseLocalFileHeader() { - $LocalFileHeader['offset'] = ftell($this->getid3->fp); - - $ZIPlocalFileHeader = fread($this->getid3->fp, 30); - - $LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4)); - if ($LocalFileHeader['raw']['signature'] != 0x04034B50) { // "PK\x03\x04" - // invalid Local File Header Signature - fseek($this->getid3->fp, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly - return false; - } - $LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2)); - $LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2)); - $LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2)); - $LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2)); - $LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2)); - $LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4)); - $LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4)); - $LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4)); - $LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2)); - $LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2)); - - $LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10); - $LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8); - $LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']); - $LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size']; - $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size']; - $LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']); - $LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']); - - $FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length']; - if ($FilenameExtrafieldLength > 0) { - $ZIPlocalFileHeader .= fread($this->getid3->fp, $FilenameExtrafieldLength); - - if ($LocalFileHeader['raw']['filename_length'] > 0) { - $LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']); - } - if ($LocalFileHeader['raw']['extra_field_length'] > 0) { - $LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']); - } - } - - if ($LocalFileHeader['compressed_size'] == 0) { - // *Could* be a zero-byte file - // But could also be a file written on the fly that didn't know compressed filesize beforehand. - // Correct compressed filesize should be in the data_descriptor located after this file data, and also in Central Directory (at end of zip file) - if (!empty($this->getid3->info['zip']['central_directory'])) { - foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) { - if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) { - if ($central_directory_entry['compressed_size'] > 0) { - // overwrite local zero value (but not ['raw']'compressed_size']) so that seeking for data_descriptor (and next file entry) works correctly - $LocalFileHeader['compressed_size'] = $central_directory_entry['compressed_size']; - } - break; - } - } - } - - } - $LocalFileHeader['data_offset'] = ftell($this->getid3->fp); - fseek($this->getid3->fp, $LocalFileHeader['compressed_size'], SEEK_CUR); // this should (but may not) match value in $LocalFileHeader['raw']['compressed_size'] -- $LocalFileHeader['compressed_size'] could have been overwritten above with value from Central Directory - - if ($LocalFileHeader['flags']['data_descriptor_used']) { - $DataDescriptor = fread($this->getid3->fp, 16); - $LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4)); - if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08" - $this->getid3->warning[] = 'invalid Local File Header Data Descriptor Signature at offset '.(ftell($this->getid3->fp) - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']); - fseek($this->getid3->fp, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly - return false; - } - $LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4)); - $LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4)); - $LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 12, 4)); - if (!$LocalFileHeader['raw']['compressed_size'] && $LocalFileHeader['data_descriptor']['compressed_size']) { - foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) { - if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) { - if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) { - // $LocalFileHeader['compressed_size'] already set from Central Directory - } else { - $this->getid3->info['warning'][] = 'conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset']; - } - - if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) { - $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size']; - } else { - $this->getid3->info['warning'][] = 'conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset']; - } - break; - } - } - } - } - return $LocalFileHeader; - } - - - public function ZIPparseCentralDirectory() { - $CentralDirectory['offset'] = ftell($this->getid3->fp); - - $ZIPcentralDirectory = fread($this->getid3->fp, 46); - - $CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4)); - if ($CentralDirectory['raw']['signature'] != 0x02014B50) { - // invalid Central Directory Signature - fseek($this->getid3->fp, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly - return false; - } - $CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2)); - $CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2)); - $CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2)); - $CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2)); - $CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2)); - $CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2)); - $CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4)); - $CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4)); - $CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4)); - $CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2)); - $CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2)); - $CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2)); - $CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2)); - $CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2)); - $CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4)); - $CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4)); - - $CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset']; - $CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10); - $CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10); - $CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8); - $CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']); - $CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size']; - $CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size']; - $CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']); - $CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']); - - $FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length']; - if ($FilenameExtrafieldCommentLength > 0) { - $FilenameExtrafieldComment = fread($this->getid3->fp, $FilenameExtrafieldCommentLength); - - if ($CentralDirectory['raw']['filename_length'] > 0) { - $CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']); - } - if ($CentralDirectory['raw']['extra_field_length'] > 0) { - $CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']); - } - if ($CentralDirectory['raw']['file_comment_length'] > 0) { - $CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']); - } - } - - return $CentralDirectory; - } - - public function ZIPparseEndOfCentralDirectory() { - $EndOfCentralDirectory['offset'] = ftell($this->getid3->fp); - - $ZIPendOfCentralDirectory = fread($this->getid3->fp, 22); - - $EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4)); - if ($EndOfCentralDirectory['signature'] != 0x06054B50) { - // invalid End Of Central Directory Signature - fseek($this->getid3->fp, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly - return false; - } - $EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2)); - $EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2)); - $EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2)); - $EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2)); - $EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4)); - $EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4)); - $EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2)); - - if ($EndOfCentralDirectory['comment_length'] > 0) { - $EndOfCentralDirectory['comment'] = fread($this->getid3->fp, $EndOfCentralDirectory['comment_length']); - } - - return $EndOfCentralDirectory; - } - - - public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) { - // https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html - $ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001); - // 0x0002 -- see below - // 0x0004 -- see below - $ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008); - $ParsedFlags['enhanced_deflation'] = (bool) ($flagbytes & 0x0010); - $ParsedFlags['compressed_patched_data'] = (bool) ($flagbytes & 0x0020); - $ParsedFlags['strong_encryption'] = (bool) ($flagbytes & 0x0040); - // 0x0080 - unused - // 0x0100 - unused - // 0x0200 - unused - // 0x0400 - unused - $ParsedFlags['language_encoding'] = (bool) ($flagbytes & 0x0800); - // 0x1000 - reserved - $ParsedFlags['mask_header_values'] = (bool) ($flagbytes & 0x2000); - // 0x4000 - reserved - // 0x8000 - reserved - - switch ($compressionmethod) { - case 6: - $ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096); - $ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2); - break; - - case 8: - case 9: - switch (($flagbytes & 0x0006) >> 1) { - case 0: - $ParsedFlags['compression_speed'] = 'normal'; - break; - case 1: - $ParsedFlags['compression_speed'] = 'maximum'; - break; - case 2: - $ParsedFlags['compression_speed'] = 'fast'; - break; - case 3: - $ParsedFlags['compression_speed'] = 'superfast'; - break; - } - break; - } - - return $ParsedFlags; - } - - - public static function ZIPversionOSLookup($index) { - static $ZIPversionOSLookup = array( - 0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)', - 1 => 'Amiga', - 2 => 'OpenVMS', - 3 => 'Unix', - 4 => 'VM/CMS', - 5 => 'Atari ST', - 6 => 'OS/2 H.P.F.S.', - 7 => 'Macintosh', - 8 => 'Z-System', - 9 => 'CP/M', - 10 => 'Windows NTFS', - 11 => 'MVS', - 12 => 'VSE', - 13 => 'Acorn Risc', - 14 => 'VFAT', - 15 => 'Alternate MVS', - 16 => 'BeOS', - 17 => 'Tandem', - 18 => 'OS/400', - 19 => 'OS/X (Darwin)', - ); - - return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]'); - } - - public static function ZIPcompressionMethodLookup($index) { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html - static $ZIPcompressionMethodLookup = array( - 0 => 'store', - 1 => 'shrink', - 2 => 'reduce-1', - 3 => 'reduce-2', - 4 => 'reduce-3', - 5 => 'reduce-4', - 6 => 'implode', - 7 => 'tokenize', - 8 => 'deflate', - 9 => 'deflate64', - 10 => 'Imploded (old IBM TERSE)', - 11 => 'RESERVED[11]', - 12 => 'BZIP2', - 13 => 'RESERVED[13]', - 14 => 'LZMA (EFS)', - 15 => 'RESERVED[15]', - 16 => 'RESERVED[16]', - 17 => 'RESERVED[17]', - 18 => 'IBM TERSE (new)', - 19 => 'IBM LZ77 z Architecture (PFS)', - 96 => 'JPEG recompressed', - 97 => 'WavPack compressed', - 98 => 'PPMd version I, Rev 1', - ); - - return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]'); - } - - public static function DOStime2UNIXtime($DOSdate, $DOStime) { - // wFatDate - // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format: - // Bits Contents - // 0-4 Day of the month (1-31) - // 5-8 Month (1 = January, 2 = February, and so on) - // 9-15 Year offset from 1980 (add 1980 to get actual year) - - $UNIXday = ($DOSdate & 0x001F); - $UNIXmonth = (($DOSdate & 0x01E0) >> 5); - $UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980; - - // wFatTime - // Specifies the MS-DOS time. The time is a packed 16-bit value with the following format: - // Bits Contents - // 0-4 Second divided by 2 - // 5-10 Minute (0-59) - // 11-15 Hour (0-23 on a 24-hour clock) - - $UNIXsecond = ($DOStime & 0x001F) * 2; - $UNIXminute = (($DOStime & 0x07E0) >> 5); - $UNIXhour = (($DOStime & 0xF800) >> 11); - - return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.zip.php // +// module for analyzing pkZip files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_zip extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'zip'; + $info['zip']['encoding'] = 'ISO-8859-1'; + $info['zip']['files'] = array(); + + $info['zip']['compressed_size'] = 0; + $info['zip']['uncompressed_size'] = 0; + $info['zip']['entries_count'] = 0; + + if (!getid3_lib::intValueSupported($info['filesize'])) { + $info['error'][] = 'File is larger than '.round(PHP_INT_MAX / 1073741824).'GB, not supported by PHP'; + return false; + } else { + $EOCDsearchData = ''; + $EOCDsearchCounter = 0; + while ($EOCDsearchCounter++ < 512) { + + fseek($this->getid3->fp, -128 * $EOCDsearchCounter, SEEK_END); + $EOCDsearchData = fread($this->getid3->fp, 128).$EOCDsearchData; + + if (strstr($EOCDsearchData, 'PK'."\x05\x06")) { + + $EOCDposition = strpos($EOCDsearchData, 'PK'."\x05\x06"); + fseek($this->getid3->fp, (-128 * $EOCDsearchCounter) + $EOCDposition, SEEK_END); + $info['zip']['end_central_directory'] = $this->ZIPparseEndOfCentralDirectory(); + + fseek($this->getid3->fp, $info['zip']['end_central_directory']['directory_offset'], SEEK_SET); + $info['zip']['entries_count'] = 0; + while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) { + $info['zip']['central_directory'][] = $centraldirectoryentry; + $info['zip']['entries_count']++; + $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size']; + $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size']; + + //if ($centraldirectoryentry['uncompressed_size'] > 0) { zero-byte files are valid + if (!empty($centraldirectoryentry['filename'])) { + $info['zip']['files'] = getid3_lib::array_merge_clobber($info['zip']['files'], getid3_lib::CreateDeepArray($centraldirectoryentry['filename'], '/', $centraldirectoryentry['uncompressed_size'])); + } + } + + if ($info['zip']['entries_count'] == 0) { + $info['error'][] = 'No Central Directory entries found (truncated file?)'; + return false; + } + + if (!empty($info['zip']['end_central_directory']['comment'])) { + $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment']; + } + + if (isset($info['zip']['central_directory'][0]['compression_method'])) { + $info['zip']['compression_method'] = $info['zip']['central_directory'][0]['compression_method']; + } + if (isset($info['zip']['central_directory'][0]['flags']['compression_speed'])) { + $info['zip']['compression_speed'] = $info['zip']['central_directory'][0]['flags']['compression_speed']; + } + if (isset($info['zip']['compression_method']) && ($info['zip']['compression_method'] == 'store') && !isset($info['zip']['compression_speed'])) { + $info['zip']['compression_speed'] = 'store'; + } + + // secondary check - we (should) already have all the info we NEED from the Central Directory above, but scanning each + // Local File Header entry will + foreach ($info['zip']['central_directory'] as $central_directory_entry) { + fseek($this->getid3->fp, $central_directory_entry['entry_offset'], SEEK_SET); + if ($fileentry = $this->ZIPparseLocalFileHeader()) { + $info['zip']['entries'][] = $fileentry; + } else { + $info['warning'][] = 'Error parsing Local File Header at offset '.$central_directory_entry['entry_offset']; + } + } + + if (!empty($info['zip']['files']['[Content_Types].xml']) && + !empty($info['zip']['files']['_rels']['.rels']) && + !empty($info['zip']['files']['docProps']['app.xml']) && + !empty($info['zip']['files']['docProps']['core.xml'])) { + // http://technet.microsoft.com/en-us/library/cc179224.aspx + $info['fileformat'] = 'zip.msoffice'; + if (!empty($ThisFileInfo['zip']['files']['ppt'])) { + $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'; + } elseif (!empty($ThisFileInfo['zip']['files']['xl'])) { + $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'; + } elseif (!empty($ThisFileInfo['zip']['files']['word'])) { + $info['mime_type'] = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; + } + } + + return true; + } + } + } + + if (!$this->getZIPentriesFilepointer()) { + unset($info['zip']); + $info['fileformat'] = ''; + $info['error'][] = 'Cannot find End Of Central Directory (truncated file?)'; + return false; + } + + // central directory couldn't be found and/or parsed + // scan through actual file data entries, recover as much as possible from probable trucated file + if ($info['zip']['compressed_size'] > ($info['filesize'] - 46 - 22)) { + $info['error'][] = 'Warning: Truncated file! - Total compressed file sizes ('.$info['zip']['compressed_size'].' bytes) is greater than filesize minus Central Directory and End Of Central Directory structures ('.($info['filesize'] - 46 - 22).' bytes)'; + } + $info['error'][] = 'Cannot find End Of Central Directory - returned list of files in [zip][entries] array may not be complete'; + foreach ($info['zip']['entries'] as $key => $valuearray) { + $info['zip']['files'][$valuearray['filename']] = $valuearray['uncompressed_size']; + } + return true; + } + + + public function getZIPHeaderFilepointerTopDown() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'zip'; + + $info['zip']['compressed_size'] = 0; + $info['zip']['uncompressed_size'] = 0; + $info['zip']['entries_count'] = 0; + + rewind($this->getid3->fp); + while ($fileentry = $this->ZIPparseLocalFileHeader()) { + $info['zip']['entries'][] = $fileentry; + $info['zip']['entries_count']++; + } + if ($info['zip']['entries_count'] == 0) { + $info['error'][] = 'No Local File Header entries found'; + return false; + } + + $info['zip']['entries_count'] = 0; + while ($centraldirectoryentry = $this->ZIPparseCentralDirectory($this->getid3->fp)) { + $info['zip']['central_directory'][] = $centraldirectoryentry; + $info['zip']['entries_count']++; + $info['zip']['compressed_size'] += $centraldirectoryentry['compressed_size']; + $info['zip']['uncompressed_size'] += $centraldirectoryentry['uncompressed_size']; + } + if ($info['zip']['entries_count'] == 0) { + $info['error'][] = 'No Central Directory entries found (truncated file?)'; + return false; + } + + if ($EOCD = $this->ZIPparseEndOfCentralDirectory()) { + $info['zip']['end_central_directory'] = $EOCD; + } else { + $info['error'][] = 'No End Of Central Directory entry found (truncated file?)'; + return false; + } + + if (!empty($info['zip']['end_central_directory']['comment'])) { + $info['zip']['comments']['comment'][] = $info['zip']['end_central_directory']['comment']; + } + + return true; + } + + + public function getZIPentriesFilepointer() { + $info = &$this->getid3->info; + + $info['zip']['compressed_size'] = 0; + $info['zip']['uncompressed_size'] = 0; + $info['zip']['entries_count'] = 0; + + rewind($this->getid3->fp); + while ($fileentry = $this->ZIPparseLocalFileHeader()) { + $info['zip']['entries'][] = $fileentry; + $info['zip']['entries_count']++; + $info['zip']['compressed_size'] += $fileentry['compressed_size']; + $info['zip']['uncompressed_size'] += $fileentry['uncompressed_size']; + } + if ($info['zip']['entries_count'] == 0) { + $info['error'][] = 'No Local File Header entries found'; + return false; + } + + return true; + } + + + public function ZIPparseLocalFileHeader() { + $LocalFileHeader['offset'] = ftell($this->getid3->fp); + + $ZIPlocalFileHeader = fread($this->getid3->fp, 30); + + $LocalFileHeader['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 0, 4)); + if ($LocalFileHeader['raw']['signature'] != 0x04034B50) { // "PK\x03\x04" + // invalid Local File Header Signature + fseek($this->getid3->fp, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + $LocalFileHeader['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 4, 2)); + $LocalFileHeader['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 6, 2)); + $LocalFileHeader['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 8, 2)); + $LocalFileHeader['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 10, 2)); + $LocalFileHeader['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 12, 2)); + $LocalFileHeader['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 14, 4)); + $LocalFileHeader['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 18, 4)); + $LocalFileHeader['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 22, 4)); + $LocalFileHeader['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 26, 2)); + $LocalFileHeader['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPlocalFileHeader, 28, 2)); + + $LocalFileHeader['extract_version'] = sprintf('%1.1f', $LocalFileHeader['raw']['extract_version'] / 10); + $LocalFileHeader['host_os'] = $this->ZIPversionOSLookup(($LocalFileHeader['raw']['extract_version'] & 0xFF00) >> 8); + $LocalFileHeader['compression_method'] = $this->ZIPcompressionMethodLookup($LocalFileHeader['raw']['compression_method']); + $LocalFileHeader['compressed_size'] = $LocalFileHeader['raw']['compressed_size']; + $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['raw']['uncompressed_size']; + $LocalFileHeader['flags'] = $this->ZIPparseGeneralPurposeFlags($LocalFileHeader['raw']['general_flags'], $LocalFileHeader['raw']['compression_method']); + $LocalFileHeader['last_modified_timestamp'] = $this->DOStime2UNIXtime($LocalFileHeader['raw']['last_mod_file_date'], $LocalFileHeader['raw']['last_mod_file_time']); + + $FilenameExtrafieldLength = $LocalFileHeader['raw']['filename_length'] + $LocalFileHeader['raw']['extra_field_length']; + if ($FilenameExtrafieldLength > 0) { + $ZIPlocalFileHeader .= fread($this->getid3->fp, $FilenameExtrafieldLength); + + if ($LocalFileHeader['raw']['filename_length'] > 0) { + $LocalFileHeader['filename'] = substr($ZIPlocalFileHeader, 30, $LocalFileHeader['raw']['filename_length']); + } + if ($LocalFileHeader['raw']['extra_field_length'] > 0) { + $LocalFileHeader['raw']['extra_field_data'] = substr($ZIPlocalFileHeader, 30 + $LocalFileHeader['raw']['filename_length'], $LocalFileHeader['raw']['extra_field_length']); + } + } + + if ($LocalFileHeader['compressed_size'] == 0) { + // *Could* be a zero-byte file + // But could also be a file written on the fly that didn't know compressed filesize beforehand. + // Correct compressed filesize should be in the data_descriptor located after this file data, and also in Central Directory (at end of zip file) + if (!empty($this->getid3->info['zip']['central_directory'])) { + foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) { + if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) { + if ($central_directory_entry['compressed_size'] > 0) { + // overwrite local zero value (but not ['raw']'compressed_size']) so that seeking for data_descriptor (and next file entry) works correctly + $LocalFileHeader['compressed_size'] = $central_directory_entry['compressed_size']; + } + break; + } + } + } + + } + $LocalFileHeader['data_offset'] = ftell($this->getid3->fp); + fseek($this->getid3->fp, $LocalFileHeader['compressed_size'], SEEK_CUR); // this should (but may not) match value in $LocalFileHeader['raw']['compressed_size'] -- $LocalFileHeader['compressed_size'] could have been overwritten above with value from Central Directory + + if ($LocalFileHeader['flags']['data_descriptor_used']) { + $DataDescriptor = fread($this->getid3->fp, 16); + $LocalFileHeader['data_descriptor']['signature'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 0, 4)); + if ($LocalFileHeader['data_descriptor']['signature'] != 0x08074B50) { // "PK\x07\x08" + $this->getid3->warning[] = 'invalid Local File Header Data Descriptor Signature at offset '.(ftell($this->getid3->fp) - 16).' - expecting 08 07 4B 50, found '.getid3_lib::PrintHexBytes($LocalFileHeader['data_descriptor']['signature']); + fseek($this->getid3->fp, $LocalFileHeader['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + $LocalFileHeader['data_descriptor']['crc_32'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 4, 4)); + $LocalFileHeader['data_descriptor']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 8, 4)); + $LocalFileHeader['data_descriptor']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($DataDescriptor, 12, 4)); + if (!$LocalFileHeader['raw']['compressed_size'] && $LocalFileHeader['data_descriptor']['compressed_size']) { + foreach ($this->getid3->info['zip']['central_directory'] as $central_directory_entry) { + if ($central_directory_entry['entry_offset'] == $LocalFileHeader['offset']) { + if ($LocalFileHeader['data_descriptor']['compressed_size'] == $central_directory_entry['compressed_size']) { + // $LocalFileHeader['compressed_size'] already set from Central Directory + } else { + $this->getid3->info['warning'][] = 'conflicting compressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['compressed_size'].') vs Central Directory ('.$central_directory_entry['compressed_size'].') for file at offset '.$LocalFileHeader['offset']; + } + + if ($LocalFileHeader['data_descriptor']['uncompressed_size'] == $central_directory_entry['uncompressed_size']) { + $LocalFileHeader['uncompressed_size'] = $LocalFileHeader['data_descriptor']['uncompressed_size']; + } else { + $this->getid3->info['warning'][] = 'conflicting uncompressed_size from data_descriptor ('.$LocalFileHeader['data_descriptor']['uncompressed_size'].') vs Central Directory ('.$central_directory_entry['uncompressed_size'].') for file at offset '.$LocalFileHeader['offset']; + } + break; + } + } + } + } + return $LocalFileHeader; + } + + + public function ZIPparseCentralDirectory() { + $CentralDirectory['offset'] = ftell($this->getid3->fp); + + $ZIPcentralDirectory = fread($this->getid3->fp, 46); + + $CentralDirectory['raw']['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 0, 4)); + if ($CentralDirectory['raw']['signature'] != 0x02014B50) { + // invalid Central Directory Signature + fseek($this->getid3->fp, $CentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + $CentralDirectory['raw']['create_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 4, 2)); + $CentralDirectory['raw']['extract_version'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 6, 2)); + $CentralDirectory['raw']['general_flags'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 8, 2)); + $CentralDirectory['raw']['compression_method'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 10, 2)); + $CentralDirectory['raw']['last_mod_file_time'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 12, 2)); + $CentralDirectory['raw']['last_mod_file_date'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 14, 2)); + $CentralDirectory['raw']['crc_32'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 16, 4)); + $CentralDirectory['raw']['compressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 20, 4)); + $CentralDirectory['raw']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 24, 4)); + $CentralDirectory['raw']['filename_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 28, 2)); + $CentralDirectory['raw']['extra_field_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 30, 2)); + $CentralDirectory['raw']['file_comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 32, 2)); + $CentralDirectory['raw']['disk_number_start'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 34, 2)); + $CentralDirectory['raw']['internal_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 36, 2)); + $CentralDirectory['raw']['external_file_attrib'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 38, 4)); + $CentralDirectory['raw']['local_header_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPcentralDirectory, 42, 4)); + + $CentralDirectory['entry_offset'] = $CentralDirectory['raw']['local_header_offset']; + $CentralDirectory['create_version'] = sprintf('%1.1f', $CentralDirectory['raw']['create_version'] / 10); + $CentralDirectory['extract_version'] = sprintf('%1.1f', $CentralDirectory['raw']['extract_version'] / 10); + $CentralDirectory['host_os'] = $this->ZIPversionOSLookup(($CentralDirectory['raw']['extract_version'] & 0xFF00) >> 8); + $CentralDirectory['compression_method'] = $this->ZIPcompressionMethodLookup($CentralDirectory['raw']['compression_method']); + $CentralDirectory['compressed_size'] = $CentralDirectory['raw']['compressed_size']; + $CentralDirectory['uncompressed_size'] = $CentralDirectory['raw']['uncompressed_size']; + $CentralDirectory['flags'] = $this->ZIPparseGeneralPurposeFlags($CentralDirectory['raw']['general_flags'], $CentralDirectory['raw']['compression_method']); + $CentralDirectory['last_modified_timestamp'] = $this->DOStime2UNIXtime($CentralDirectory['raw']['last_mod_file_date'], $CentralDirectory['raw']['last_mod_file_time']); + + $FilenameExtrafieldCommentLength = $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'] + $CentralDirectory['raw']['file_comment_length']; + if ($FilenameExtrafieldCommentLength > 0) { + $FilenameExtrafieldComment = fread($this->getid3->fp, $FilenameExtrafieldCommentLength); + + if ($CentralDirectory['raw']['filename_length'] > 0) { + $CentralDirectory['filename'] = substr($FilenameExtrafieldComment, 0, $CentralDirectory['raw']['filename_length']); + } + if ($CentralDirectory['raw']['extra_field_length'] > 0) { + $CentralDirectory['raw']['extra_field_data'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'], $CentralDirectory['raw']['extra_field_length']); + } + if ($CentralDirectory['raw']['file_comment_length'] > 0) { + $CentralDirectory['file_comment'] = substr($FilenameExtrafieldComment, $CentralDirectory['raw']['filename_length'] + $CentralDirectory['raw']['extra_field_length'], $CentralDirectory['raw']['file_comment_length']); + } + } + + return $CentralDirectory; + } + + public function ZIPparseEndOfCentralDirectory() { + $EndOfCentralDirectory['offset'] = ftell($this->getid3->fp); + + $ZIPendOfCentralDirectory = fread($this->getid3->fp, 22); + + $EndOfCentralDirectory['signature'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 0, 4)); + if ($EndOfCentralDirectory['signature'] != 0x06054B50) { + // invalid End Of Central Directory Signature + fseek($this->getid3->fp, $EndOfCentralDirectory['offset'], SEEK_SET); // seek back to where filepointer originally was so it can be handled properly + return false; + } + $EndOfCentralDirectory['disk_number_current'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 4, 2)); + $EndOfCentralDirectory['disk_number_start_directory'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 6, 2)); + $EndOfCentralDirectory['directory_entries_this_disk'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 8, 2)); + $EndOfCentralDirectory['directory_entries_total'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 10, 2)); + $EndOfCentralDirectory['directory_size'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 12, 4)); + $EndOfCentralDirectory['directory_offset'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 16, 4)); + $EndOfCentralDirectory['comment_length'] = getid3_lib::LittleEndian2Int(substr($ZIPendOfCentralDirectory, 20, 2)); + + if ($EndOfCentralDirectory['comment_length'] > 0) { + $EndOfCentralDirectory['comment'] = fread($this->getid3->fp, $EndOfCentralDirectory['comment_length']); + } + + return $EndOfCentralDirectory; + } + + + public static function ZIPparseGeneralPurposeFlags($flagbytes, $compressionmethod) { + // https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip-printable.html + $ParsedFlags['encrypted'] = (bool) ($flagbytes & 0x0001); + // 0x0002 -- see below + // 0x0004 -- see below + $ParsedFlags['data_descriptor_used'] = (bool) ($flagbytes & 0x0008); + $ParsedFlags['enhanced_deflation'] = (bool) ($flagbytes & 0x0010); + $ParsedFlags['compressed_patched_data'] = (bool) ($flagbytes & 0x0020); + $ParsedFlags['strong_encryption'] = (bool) ($flagbytes & 0x0040); + // 0x0080 - unused + // 0x0100 - unused + // 0x0200 - unused + // 0x0400 - unused + $ParsedFlags['language_encoding'] = (bool) ($flagbytes & 0x0800); + // 0x1000 - reserved + $ParsedFlags['mask_header_values'] = (bool) ($flagbytes & 0x2000); + // 0x4000 - reserved + // 0x8000 - reserved + + switch ($compressionmethod) { + case 6: + $ParsedFlags['dictionary_size'] = (($flagbytes & 0x0002) ? 8192 : 4096); + $ParsedFlags['shannon_fano_trees'] = (($flagbytes & 0x0004) ? 3 : 2); + break; + + case 8: + case 9: + switch (($flagbytes & 0x0006) >> 1) { + case 0: + $ParsedFlags['compression_speed'] = 'normal'; + break; + case 1: + $ParsedFlags['compression_speed'] = 'maximum'; + break; + case 2: + $ParsedFlags['compression_speed'] = 'fast'; + break; + case 3: + $ParsedFlags['compression_speed'] = 'superfast'; + break; + } + break; + } + + return $ParsedFlags; + } + + + public static function ZIPversionOSLookup($index) { + static $ZIPversionOSLookup = array( + 0 => 'MS-DOS and OS/2 (FAT / VFAT / FAT32 file systems)', + 1 => 'Amiga', + 2 => 'OpenVMS', + 3 => 'Unix', + 4 => 'VM/CMS', + 5 => 'Atari ST', + 6 => 'OS/2 H.P.F.S.', + 7 => 'Macintosh', + 8 => 'Z-System', + 9 => 'CP/M', + 10 => 'Windows NTFS', + 11 => 'MVS', + 12 => 'VSE', + 13 => 'Acorn Risc', + 14 => 'VFAT', + 15 => 'Alternate MVS', + 16 => 'BeOS', + 17 => 'Tandem', + 18 => 'OS/400', + 19 => 'OS/X (Darwin)', + ); + + return (isset($ZIPversionOSLookup[$index]) ? $ZIPversionOSLookup[$index] : '[unknown]'); + } + + public static function ZIPcompressionMethodLookup($index) { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/ZIP.html + static $ZIPcompressionMethodLookup = array( + 0 => 'store', + 1 => 'shrink', + 2 => 'reduce-1', + 3 => 'reduce-2', + 4 => 'reduce-3', + 5 => 'reduce-4', + 6 => 'implode', + 7 => 'tokenize', + 8 => 'deflate', + 9 => 'deflate64', + 10 => 'Imploded (old IBM TERSE)', + 11 => 'RESERVED[11]', + 12 => 'BZIP2', + 13 => 'RESERVED[13]', + 14 => 'LZMA (EFS)', + 15 => 'RESERVED[15]', + 16 => 'RESERVED[16]', + 17 => 'RESERVED[17]', + 18 => 'IBM TERSE (new)', + 19 => 'IBM LZ77 z Architecture (PFS)', + 96 => 'JPEG recompressed', + 97 => 'WavPack compressed', + 98 => 'PPMd version I, Rev 1', + ); + + return (isset($ZIPcompressionMethodLookup[$index]) ? $ZIPcompressionMethodLookup[$index] : '[unknown]'); + } + + public static function DOStime2UNIXtime($DOSdate, $DOStime) { + // wFatDate + // Specifies the MS-DOS date. The date is a packed 16-bit value with the following format: + // Bits Contents + // 0-4 Day of the month (1-31) + // 5-8 Month (1 = January, 2 = February, and so on) + // 9-15 Year offset from 1980 (add 1980 to get actual year) + + $UNIXday = ($DOSdate & 0x001F); + $UNIXmonth = (($DOSdate & 0x01E0) >> 5); + $UNIXyear = (($DOSdate & 0xFE00) >> 9) + 1980; + + // wFatTime + // Specifies the MS-DOS time. The time is a packed 16-bit value with the following format: + // Bits Contents + // 0-4 Second divided by 2 + // 5-10 Minute (0-59) + // 11-15 Hour (0-23 on a 24-hour clock) + + $UNIXsecond = ($DOStime & 0x001F) * 2; + $UNIXminute = (($DOStime & 0x07E0) >> 5); + $UNIXhour = (($DOStime & 0xF800) >> 11); + + return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.asf.php b/app/libs/vendor/getid3/module.audio-video.asf.php index dc6daf94..cfc60a78 100644 --- a/app/libs/vendor/getid3/module.audio-video.asf.php +++ b/app/libs/vendor/getid3/module.audio-video.asf.php @@ -1,2019 +1,2019 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.asf.php // -// module for analyzing ASF, WMA and WMV files // -// dependencies: module.audio-video.riff.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - -class getid3_asf extends getid3_handler -{ - - public function __construct(getID3 $getid3) { - parent::__construct($getid3); // extends getid3_handler::__construct() - - // initialize all GUID constants - $GUIDarray = $this->KnownGUIDs(); - foreach ($GUIDarray as $GUIDname => $hexstringvalue) { - if (!defined($GUIDname)) { - define($GUIDname, $this->GUIDtoBytestring($hexstringvalue)); - } - } - } - - public function Analyze() { - $info = &$this->getid3->info; - - // Shortcuts - $thisfile_audio = &$info['audio']; - $thisfile_video = &$info['video']; - $info['asf'] = array(); - $thisfile_asf = &$info['asf']; - $thisfile_asf['comments'] = array(); - $thisfile_asf_comments = &$thisfile_asf['comments']; - $thisfile_asf['header_object'] = array(); - $thisfile_asf_headerobject = &$thisfile_asf['header_object']; - - - // ASF structure: - // * Header Object [required] - // * File Properties Object [required] (global file attributes) - // * Stream Properties Object [required] (defines media stream & characteristics) - // * Header Extension Object [required] (additional functionality) - // * Content Description Object (bibliographic information) - // * Script Command Object (commands for during playback) - // * Marker Object (named jumped points within the file) - // * Data Object [required] - // * Data Packets - // * Index Object - - // Header Object: (mandatory, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for header object - GETID3_ASF_Header_Object - // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header - // Number of Header Objects DWORD 32 // number of objects in header object - // Reserved1 BYTE 8 // hardcoded: 0x01 - // Reserved2 BYTE 8 // hardcoded: 0x02 - - $info['fileformat'] = 'asf'; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $HeaderObjectData = fread($this->getid3->fp, 30); - - $thisfile_asf_headerobject['objectid'] = substr($HeaderObjectData, 0, 16); - $thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']); - if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) { - $info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}'; - unset($info['fileformat']); - unset($info['asf']); - return false; - break; - } - $thisfile_asf_headerobject['objectsize'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8)); - $thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4)); - $thisfile_asf_headerobject['reserved1'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1)); - $thisfile_asf_headerobject['reserved2'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1)); - - $NextObjectOffset = ftell($this->getid3->fp); - $ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30); - $offset = 0; - - for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { - $NextObjectGUID = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); - $NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - switch ($NextObjectGUID) { - - case GETID3_ASF_File_Properties_Object: - // File Properties Object: (mandatory, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for file properties object - GETID3_ASF_File_Properties_Object - // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header - // File ID GUID 128 // unique ID - identical to File ID in Data Object - // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1 - // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1 - // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1 - // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1 - // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1 - // Preroll QWORD 64 // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount - // Flags DWORD 32 // - // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid - // * Seekable Flag bits 1 (0x02) // is file seekable - // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero - // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1 - // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1 - // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead - - // shortcut - $thisfile_asf['file_properties_object'] = array(); - $thisfile_asf_filepropertiesobject = &$thisfile_asf['file_properties_object']; - - $thisfile_asf_filepropertiesobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_filepropertiesobject['objectid'] = $NextObjectGUID; - $thisfile_asf_filepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_filepropertiesobject['objectsize'] = $NextObjectSize; - $thisfile_asf_filepropertiesobject['fileid'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_filepropertiesobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']); - $thisfile_asf_filepropertiesobject['filesize'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_filepropertiesobject['creation_date'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']); - $offset += 8; - $thisfile_asf_filepropertiesobject['data_packets'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_filepropertiesobject['play_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_filepropertiesobject['send_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_filepropertiesobject['preroll'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_filepropertiesobject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001); - $thisfile_asf_filepropertiesobject['flags']['seekable'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002); - - $thisfile_asf_filepropertiesobject['min_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_filepropertiesobject['max_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_filepropertiesobject['max_bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - - if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) { - - // broadcast flag is set, some values invalid - unset($thisfile_asf_filepropertiesobject['filesize']); - unset($thisfile_asf_filepropertiesobject['data_packets']); - unset($thisfile_asf_filepropertiesobject['play_duration']); - unset($thisfile_asf_filepropertiesobject['send_duration']); - unset($thisfile_asf_filepropertiesobject['min_packet_size']); - unset($thisfile_asf_filepropertiesobject['max_packet_size']); - - } else { - - // broadcast flag NOT set, perform calculations - $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); - - //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; - $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; - } - break; - - case GETID3_ASF_Stream_Properties_Object: - // Stream Properties Object: (mandatory, one per media stream) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object - // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header - // Stream Type GUID 128 // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media - // Error Correction Type GUID 128 // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types - // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream - // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field - // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field - // Flags WORD 16 // - // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127 - // * Reserved bits 8 (0x7F80) // reserved - set to zero - // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set - // Reserved DWORD 32 // reserved - set to zero - // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type - // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type - - // There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the - // stream number isn't known until halfway through decoding the structure, hence it - // it is decoded to a temporary variable and then stuck in the appropriate index later - - $StreamPropertiesObjectData['offset'] = $NextObjectOffset + $offset; - $StreamPropertiesObjectData['objectid'] = $NextObjectGUID; - $StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext; - $StreamPropertiesObjectData['objectsize'] = $NextObjectSize; - $StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $StreamPropertiesObjectData['stream_type_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']); - $StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']); - $StreamPropertiesObjectData['time_offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $StreamPropertiesObjectData['type_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $StreamPropertiesObjectData['error_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $StreamPropertiesObjectData['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F; - $StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000); - - $offset += 4; // reserved - DWORD - $StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']); - $offset += $StreamPropertiesObjectData['type_data_length']; - $StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']); - $offset += $StreamPropertiesObjectData['error_data_length']; - - switch ($StreamPropertiesObjectData['stream_type']) { - - case GETID3_ASF_Audio_Media: - $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); - $thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr'); - - $audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16)); - unset($audiodata['raw']); - $thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio); - break; - - case GETID3_ASF_Video_Media: - $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); - $thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr'); - break; - - case GETID3_ASF_Command_Media: - default: - // do nothing - break; - - } - - $thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData; - unset($StreamPropertiesObjectData); // clear for next stream, if any - break; - - case GETID3_ASF_Header_Extension_Object: - // Header Extension Object: (mandatory, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object - // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header - // Reserved Field 1 GUID 128 // hardcoded: GETID3_ASF_Reserved_1 - // Reserved Field 2 WORD 16 // hardcoded: 0x00000006 - // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46 - // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects - - // shortcut - $thisfile_asf['header_extension_object'] = array(); - $thisfile_asf_headerextensionobject = &$thisfile_asf['header_extension_object']; - - $thisfile_asf_headerextensionobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_headerextensionobject['objectid'] = $NextObjectGUID; - $thisfile_asf_headerextensionobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_headerextensionobject['objectsize'] = $NextObjectSize; - $thisfile_asf_headerextensionobject['reserved_1'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']); - if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) { - $info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')'; - //return false; - break; - } - $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { - $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"'; - //return false; - break; - } - $thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_headerextensionobject['extension_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']); - $unhandled_sections = 0; - $thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections); - if ($unhandled_sections === 0) { - unset($thisfile_asf_headerextensionobject['extension_data']); - } - $offset += $thisfile_asf_headerextensionobject['extension_data_size']; - break; - - case GETID3_ASF_Codec_List_Object: - // Codec List Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Codec List object - GETID3_ASF_Codec_List_Object - // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header - // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6 - // Codec Entries Count DWORD 32 // number of entries in Codec Entries array - // Codec Entries array of: variable // - // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec - // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field - // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content - // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field - // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content - // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field - // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content - - // shortcut - $thisfile_asf['codec_list_object'] = array(); - $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object']; - - $thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_codeclistobject['objectid'] = $NextObjectGUID; - $thisfile_asf_codeclistobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_codeclistobject['objectsize'] = $NextObjectSize; - $thisfile_asf_codeclistobject['reserved'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']); - if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) { - $info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}'; - //return false; - break; - } - $thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) { - // shortcut - $thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array(); - $thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter]; - - $thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_codeclistobject_codecentries_current['type'] = $this->ASFCodecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']); - - $CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength); - $offset += $CodecNameLength; - - $CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength); - $offset += $CodecDescriptionLength; - - $CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength); - $offset += $CodecInformationLength; - - if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec - - if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) { - $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"'; - } else { - - list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description'])); - $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']); - - if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { - $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000); - } - //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) { - if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) { - //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate']; - $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate']; - } - - $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency)); - switch ($AudioCodecFrequency) { - case 8: - case 8000: - $thisfile_audio['sample_rate'] = 8000; - break; - - case 11: - case 11025: - $thisfile_audio['sample_rate'] = 11025; - break; - - case 12: - case 12000: - $thisfile_audio['sample_rate'] = 12000; - break; - - case 16: - case 16000: - $thisfile_audio['sample_rate'] = 16000; - break; - - case 22: - case 22050: - $thisfile_audio['sample_rate'] = 22050; - break; - - case 24: - case 24000: - $thisfile_audio['sample_rate'] = 24000; - break; - - case 32: - case 32000: - $thisfile_audio['sample_rate'] = 32000; - break; - - case 44: - case 441000: - $thisfile_audio['sample_rate'] = 44100; - break; - - case 48: - case 48000: - $thisfile_audio['sample_rate'] = 48000; - break; - - default: - $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')'; - break; - } - - if (!isset($thisfile_audio['channels'])) { - if (strstr($AudioCodecChannels, 'stereo')) { - $thisfile_audio['channels'] = 2; - } elseif (strstr($AudioCodecChannels, 'mono')) { - $thisfile_audio['channels'] = 1; - } - } - - } - } - } - break; - - case GETID3_ASF_Script_Command_Object: - // Script Command Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Script Command object - GETID3_ASF_Script_Command_Object - // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header - // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6 - // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects - // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects - // Command Types array of: variable // - // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name - // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command - // Commands array of: variable // - // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds - // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object - // * Command Name Length WORD 16 // number of Unicode characters for Command Name - // * Command Name WCHAR variable // array of Unicode characters - name of this command - - // shortcut - $thisfile_asf['script_command_object'] = array(); - $thisfile_asf_scriptcommandobject = &$thisfile_asf['script_command_object']; - - $thisfile_asf_scriptcommandobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_scriptcommandobject['objectid'] = $NextObjectGUID; - $thisfile_asf_scriptcommandobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_scriptcommandobject['objectsize'] = $NextObjectSize; - $thisfile_asf_scriptcommandobject['reserved'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']); - if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) { - $info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}'; - //return false; - break; - } - $thisfile_asf_scriptcommandobject['commands_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_scriptcommandobject['command_types_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { - $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); - $offset += $CommandTypeNameLength; - } - for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { - $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - - $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character - $offset += 2; - $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); - $offset += $CommandTypeNameLength; - } - break; - - case GETID3_ASF_Marker_Object: - // Marker Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Marker object - GETID3_ASF_Marker_Object - // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header - // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB - // Markers Count DWORD 32 // number of Marker structures in Marker Object - // Reserved WORD 16 // hardcoded: 0x0000 - // Name Length WORD 16 // number of bytes in the Name field - // Name WCHAR variable // name of the Marker Object - // Markers array of: variable // - // * Offset QWORD 64 // byte offset into Data Object - // * Presentation Time QWORD 64 // in 100-nanosecond units - // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding) - // * Send Time DWORD 32 // in milliseconds - // * Flags DWORD 32 // hardcoded: 0x00000000 - // * Marker Description Length DWORD 32 // number of bytes in Marker Description field - // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry - // * Padding BYTESTREAM variable // optional padding bytes - - // shortcut - $thisfile_asf['marker_object'] = array(); - $thisfile_asf_markerobject = &$thisfile_asf['marker_object']; - - $thisfile_asf_markerobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_markerobject['objectid'] = $NextObjectGUID; - $thisfile_asf_markerobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_markerobject['objectsize'] = $NextObjectSize; - $thisfile_asf_markerobject['reserved'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']); - if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) { - $info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}'; - break; - } - $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - if ($thisfile_asf_markerobject['reserved_2'] != 0) { - $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"'; - break; - } - $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']); - $offset += $thisfile_asf_markerobject['name_length']; - for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) { - $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); - $offset += 8; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['flags'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']); - $offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; - $PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; - if ($PaddingLength > 0) { - $thisfile_asf_markerobject['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength); - $offset += $PaddingLength; - } - } - break; - - case GETID3_ASF_Bitrate_Mutual_Exclusion_Object: - // Bitrate Mutual Exclusion Object: (optional) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object - // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header - // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown) - // Stream Numbers Count WORD 16 // number of video streams - // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127 - - // shortcut - $thisfile_asf['bitrate_mutual_exclusion_object'] = array(); - $thisfile_asf_bitratemutualexclusionobject = &$thisfile_asf['bitrate_mutual_exclusion_object']; - - $thisfile_asf_bitratemutualexclusionobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_bitratemutualexclusionobject['objectid'] = $NextObjectGUID; - $thisfile_asf_bitratemutualexclusionobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_bitratemutualexclusionobject['objectsize'] = $NextObjectSize; - $thisfile_asf_bitratemutualexclusionobject['reserved'] = substr($ASFHeaderData, $offset, 16); - $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']); - $offset += 16; - if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) { - $info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}'; - //return false; - break; - } - $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { - $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - } - break; - - case GETID3_ASF_Error_Correction_Object: - // Error Correction Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object - // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header - // Error Correction Type GUID 128 // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread) - // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field - // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field - - // shortcut - $thisfile_asf['error_correction_object'] = array(); - $thisfile_asf_errorcorrectionobject = &$thisfile_asf['error_correction_object']; - - $thisfile_asf_errorcorrectionobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_errorcorrectionobject['objectid'] = $NextObjectGUID; - $thisfile_asf_errorcorrectionobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_errorcorrectionobject['objectsize'] = $NextObjectSize; - $thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16); - $offset += 16; - $thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']); - $thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) { - case GETID3_ASF_No_Error_Correction: - // should be no data, but just in case there is, skip to the end of the field - $offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length']; - break; - - case GETID3_ASF_Audio_Spread: - // Field Name Field Type Size (bits) - // Span BYTE 8 // number of packets over which audio will be spread. - // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream - // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream - // Silence Data Length WORD 16 // number of bytes in Silence Data field - // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes - - $thisfile_asf_errorcorrectionobject['span'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1)); - $offset += 1; - $thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_errorcorrectionobject['virtual_chunk_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_errorcorrectionobject['silence_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_errorcorrectionobject['silence_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']); - $offset += $thisfile_asf_errorcorrectionobject['silence_data_length']; - break; - - default: - $info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}'; - //return false; - break; - } - - break; - - case GETID3_ASF_Content_Description_Object: - // Content Description Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Content Description object - GETID3_ASF_Content_Description_Object - // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header - // Title Length WORD 16 // number of bytes in Title field - // Author Length WORD 16 // number of bytes in Author field - // Copyright Length WORD 16 // number of bytes in Copyright field - // Description Length WORD 16 // number of bytes in Description field - // Rating Length WORD 16 // number of bytes in Rating field - // Title WCHAR 16 // array of Unicode characters - Title - // Author WCHAR 16 // array of Unicode characters - Author - // Copyright WCHAR 16 // array of Unicode characters - Copyright - // Description WCHAR 16 // array of Unicode characters - Description - // Rating WCHAR 16 // array of Unicode characters - Rating - - // shortcut - $thisfile_asf['content_description_object'] = array(); - $thisfile_asf_contentdescriptionobject = &$thisfile_asf['content_description_object']; - - $thisfile_asf_contentdescriptionobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_contentdescriptionobject['objectid'] = $NextObjectGUID; - $thisfile_asf_contentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_contentdescriptionobject['objectsize'] = $NextObjectSize; - $thisfile_asf_contentdescriptionobject['title_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_contentdescriptionobject['author_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_contentdescriptionobject['copyright_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_contentdescriptionobject['description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_contentdescriptionobject['rating_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_contentdescriptionobject['title'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']); - $offset += $thisfile_asf_contentdescriptionobject['title_length']; - $thisfile_asf_contentdescriptionobject['author'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']); - $offset += $thisfile_asf_contentdescriptionobject['author_length']; - $thisfile_asf_contentdescriptionobject['copyright'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']); - $offset += $thisfile_asf_contentdescriptionobject['copyright_length']; - $thisfile_asf_contentdescriptionobject['description'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']); - $offset += $thisfile_asf_contentdescriptionobject['description_length']; - $thisfile_asf_contentdescriptionobject['rating'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']); - $offset += $thisfile_asf_contentdescriptionobject['rating_length']; - - $ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating'); - foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) { - if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) { - $thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]); - } - } - break; - - case GETID3_ASF_Extended_Content_Description_Object: - // Extended Content Description Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object - // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header - // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list - // Content Descriptors array of: variable // - // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field - // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name - // * Descriptor Value Data Type WORD 16 // Lookup array: - // 0x0000 = Unicode String (variable length) - // 0x0001 = BYTE array (variable length) - // 0x0002 = BOOL (DWORD, 32 bits) - // 0x0003 = DWORD (DWORD, 32 bits) - // 0x0004 = QWORD (QWORD, 64 bits) - // 0x0005 = WORD (WORD, 16 bits) - // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field - // * Descriptor Value variable variable // value for Content Descriptor - - // shortcut - $thisfile_asf['extended_content_description_object'] = array(); - $thisfile_asf_extendedcontentdescriptionobject = &$thisfile_asf['extended_content_description_object']; - - $thisfile_asf_extendedcontentdescriptionobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_extendedcontentdescriptionobject['objectid'] = $NextObjectGUID; - $thisfile_asf_extendedcontentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize; - $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { - // shortcut - $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array(); - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter]; - - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset'] = $offset + 30; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']); - $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']); - $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']; - switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { - case 0x0000: // Unicode string - break; - - case 0x0001: // BYTE array - // do nothing - break; - - case 0x0002: // BOOL - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - break; - - case 0x0003: // DWORD - case 0x0004: // QWORD - case 0x0005: // WORD - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - break; - - default: - $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')'; - //return false; - break; - } - switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) { - - case 'wm/albumartist': - case 'artist': - // Note: not 'artist', that comes from 'author' tag - $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'wm/albumtitle': - case 'album': - $thisfile_asf_comments['album'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'wm/genre': - case 'genre': - $thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'wm/partofset': - $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'wm/tracknumber': - case 'tracknumber': - // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) - $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - foreach ($thisfile_asf_comments['track'] as $key => $value) { - if (preg_match('/^[0-9\x00]+$/', $value)) { - $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value)); - } - } - break; - - case 'wm/track': - if (empty($thisfile_asf_comments['track'])) { - $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - } - break; - - case 'wm/year': - case 'year': - case 'date': - $thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'wm/lyrics': - case 'lyrics': - $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - break; - - case 'isvbr': - if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) { - $thisfile_audio['bitrate_mode'] = 'vbr'; - $thisfile_video['bitrate_mode'] = 'vbr'; - } - break; - - case 'id3': - // id3v2 module might not be loaded - if (class_exists('getid3_id3v2')) { - $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3'); - $tempfilehandle = fopen($tempfile, 'wb'); - $tempThisfileInfo = array('encoding'=>$info['encoding']); - fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - fclose($tempfilehandle); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($tempfile); - $getid3_id3v2 = new getid3_id3v2($getid3_temp); - $getid3_id3v2->Analyze(); - $info['id3v2'] = $getid3_temp->info['id3v2']; - unset($getid3_temp, $getid3_id3v2); - - unlink($tempfile); - } - break; - - case 'wm/encodingtime': - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - $thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']); - break; - - case 'wm/picture': - $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - foreach ($WMpicture as $key => $value) { - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value; - } - unset($WMpicture); -/* - $wm_picture_offset = 0; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1)); - $wm_picture_offset += 1; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = $this->WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']); - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4)); - $wm_picture_offset += 4; - - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; - do { - $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); - $wm_picture_offset += 2; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair; - } while ($next_byte_pair !== "\x00\x00"); - - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = ''; - do { - $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); - $wm_picture_offset += 2; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair; - } while ($next_byte_pair !== "\x00\x00"); - - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset; - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset); - unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); - - $imageinfo = array(); - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; - $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo); - unset($imageinfo); - if (!empty($imagechunkcheck)) { - $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); - } - if (!isset($thisfile_asf_comments['picture'])) { - $thisfile_asf_comments['picture'] = array(); - } - $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']); -*/ - break; - - default: - switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { - case 0: // Unicode string - if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') { - $thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); - } - break; - - case 1: - break; - } - break; - } - - } - break; - - case GETID3_ASF_Stream_Bitrate_Properties_Object: - // Stream Bitrate Properties Object: (optional, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object - // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header - // Bitrate Records Count WORD 16 // number of records in Bitrate Records - // Bitrate Records array of: variable // - // * Flags WORD 16 // - // * * Stream Number bits 7 (0x007F) // number of this stream - // * * Reserved bits 9 (0xFF80) // hardcoded: 0 - // * Average Bitrate DWORD 32 // in bits per second - - // shortcut - $thisfile_asf['stream_bitrate_properties_object'] = array(); - $thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object']; - - $thisfile_asf_streambitratepropertiesobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_streambitratepropertiesobject['objectid'] = $NextObjectGUID; - $thisfile_asf_streambitratepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize; - $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { - $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); - $offset += 2; - $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; - $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); - $offset += 4; - } - break; - - case GETID3_ASF_Padding_Object: - // Padding Object: (optional) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Padding object - GETID3_ASF_Padding_Object - // Object Size QWORD 64 // size of Padding object, including 24 bytes of ASF Padding Object header - // Padding Data BYTESTREAM variable // ignore - - // shortcut - $thisfile_asf['padding_object'] = array(); - $thisfile_asf_paddingobject = &$thisfile_asf['padding_object']; - - $thisfile_asf_paddingobject['offset'] = $NextObjectOffset + $offset; - $thisfile_asf_paddingobject['objectid'] = $NextObjectGUID; - $thisfile_asf_paddingobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_paddingobject['objectsize'] = $NextObjectSize; - $thisfile_asf_paddingobject['padding_length'] = $thisfile_asf_paddingobject['objectsize'] - 16 - 8; - $thisfile_asf_paddingobject['padding'] = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']); - $offset += ($NextObjectSize - 16 - 8); - break; - - case GETID3_ASF_Extended_Content_Encryption_Object: - case GETID3_ASF_Content_Encryption_Object: - // WMA DRM - just ignore - $offset += ($NextObjectSize - 16 - 8); - break; - - default: - // Implementations shall ignore any standard or non-standard object that they do not know how to handle. - if ($this->GUIDname($NextObjectGUIDtext)) { - $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); - } else { - $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); - } - $offset += ($NextObjectSize - 16 - 8); - break; - } - } - if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) { - $ASFbitrateAudio = 0; - $ASFbitrateVideo = 0; - for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) { - if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { - switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { - case 1: - $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; - break; - - case 2: - $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; - break; - - default: - // do nothing - break; - } - } - } - if ($ASFbitrateAudio > 0) { - $thisfile_audio['bitrate'] = $ASFbitrateAudio; - } - if ($ASFbitrateVideo > 0) { - $thisfile_video['bitrate'] = $ASFbitrateVideo; - } - } - if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) { - - $thisfile_audio['bitrate'] = 0; - $thisfile_video['bitrate'] = 0; - - foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) { - - switch ($streamdata['stream_type']) { - case GETID3_ASF_Audio_Media: - // Field Name Field Type Size (bits) - // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure - // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure - // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure - // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure - // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure - // Bits per sample WORD 16 // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure - // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure - // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes - - // shortcut - $thisfile_asf['audio_media'][$streamnumber] = array(); - $thisfile_asf_audiomedia_currentstream = &$thisfile_asf['audio_media'][$streamnumber]; - - $audiomediaoffset = 0; - - $thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16)); - $audiomediaoffset += 16; - - $thisfile_audio['lossless'] = false; - switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) { - case 0x0001: // PCM - case 0x0163: // WMA9 Lossless - $thisfile_audio['lossless'] = true; - break; - } - - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { - if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { - $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; - $thisfile_audio['bitrate'] += $dataarray['bitrate']; - break; - } - } - } else { - if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) { - $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8; - } elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) { - $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate']; - } - } - $thisfile_audio['streams'][$streamnumber] = $thisfile_asf_audiomedia_currentstream; - $thisfile_audio['streams'][$streamnumber]['wformattag'] = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']; - $thisfile_audio['streams'][$streamnumber]['lossless'] = $thisfile_audio['lossless']; - $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; - $thisfile_audio['streams'][$streamnumber]['dataformat'] = 'wma'; - unset($thisfile_audio['streams'][$streamnumber]['raw']); - - $thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2)); - $audiomediaoffset += 2; - $thisfile_asf_audiomedia_currentstream['codec_data'] = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']); - $audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size']; - - break; - - case GETID3_ASF_Video_Media: - // Field Name Field Type Size (bits) - // Encoded Image Width DWORD 32 // width of image in pixels - // Encoded Image Height DWORD 32 // height of image in pixels - // Reserved Flags BYTE 8 // hardcoded: 0x02 - // Format Data Size WORD 16 // size of Format Data field in bytes - // Format Data array of: variable // - // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure - // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure - // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure - // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure - // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure - // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure - // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure - // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure - // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure - // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure - // * Important Colors Count DWORD 32 // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure - // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes - - // shortcut - $thisfile_asf['video_media'][$streamnumber] = array(); - $thisfile_asf_videomedia_currentstream = &$thisfile_asf['video_media'][$streamnumber]; - - $videomediaoffset = 0; - $thisfile_asf_videomedia_currentstream['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['flags'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1)); - $videomediaoffset += 1; - $thisfile_asf_videomedia_currentstream['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); - $videomediaoffset += 2; - $thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['reserved'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); - $videomediaoffset += 2; - $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); - $videomediaoffset += 2; - $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'] = substr($streamdata['type_specific_data'], $videomediaoffset, 4); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['image_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['vertical_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['colors_used'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); - $videomediaoffset += 4; - $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); - - if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { - foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { - if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { - $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; - $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate']; - $thisfile_video['bitrate'] += $dataarray['bitrate']; - break; - } - } - } - - $thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']); - - $thisfile_video['streams'][$streamnumber]['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']; - $thisfile_video['streams'][$streamnumber]['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec']; - $thisfile_video['streams'][$streamnumber]['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width']; - $thisfile_video['streams'][$streamnumber]['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height']; - $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel']; - break; - - default: - break; - } - } - } - - while (ftell($this->getid3->fp) < $info['avdataend']) { - $NextObjectDataHeader = fread($this->getid3->fp, 24); - $offset = 0; - $NextObjectGUID = substr($NextObjectDataHeader, 0, 16); - $offset += 16; - $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); - $NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8)); - $offset += 8; - - switch ($NextObjectGUID) { - case GETID3_ASF_Data_Object: - // Data Object: (mandatory, one only) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Data object - GETID3_ASF_Data_Object - // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1 - // File ID GUID 128 // unique identifier. identical to File ID field in Header Object - // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1 - // Reserved WORD 16 // hardcoded: 0x0101 - - // shortcut - $thisfile_asf['data_object'] = array(); - $thisfile_asf_dataobject = &$thisfile_asf['data_object']; - - $DataObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 50 - 24); - $offset = 24; - - $thisfile_asf_dataobject['objectid'] = $NextObjectGUID; - $thisfile_asf_dataobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_dataobject['objectsize'] = $NextObjectSize; - - $thisfile_asf_dataobject['fileid'] = substr($DataObjectData, $offset, 16); - $offset += 16; - $thisfile_asf_dataobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']); - $thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8)); - $offset += 8; - $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2)); - $offset += 2; - if ($thisfile_asf_dataobject['reserved'] != 0x0101) { - $info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'; - //return false; - break; - } - - // Data Packets array of: variable // - // * Error Correction Flags BYTE 8 // - // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000 - // * * Opaque Data Present bits 1 // - // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00 - // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure - // * Error Correction Data - - $info['avdataoffset'] = ftell($this->getid3->fp); - fseek($this->getid3->fp, ($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data - $info['avdataend'] = ftell($this->getid3->fp); - break; - - case GETID3_ASF_Simple_Index_Object: - // Simple Index Object: (optional, recommended, one per video stream) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for Simple Index object - GETID3_ASF_Data_Object - // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header - // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object - // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units - // Maximum Packet Count DWORD 32 // maximum packet count for all index entries - // Index Entries Count DWORD 32 // number of Index Entries structures - // Index Entries array of: variable // - // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry - // * Packet Count WORD 16 // number of Data Packets to sent at this index entry - - // shortcut - $thisfile_asf['simple_index_object'] = array(); - $thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object']; - - $SimpleIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 56 - 24); - $offset = 24; - - $thisfile_asf_simpleindexobject['objectid'] = $NextObjectGUID; - $thisfile_asf_simpleindexobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_simpleindexobject['objectsize'] = $NextObjectSize; - - $thisfile_asf_simpleindexobject['fileid'] = substr($SimpleIndexObjectData, $offset, 16); - $offset += 16; - $thisfile_asf_simpleindexobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']); - $thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8)); - $offset += 8; - $thisfile_asf_simpleindexobject['maximum_packet_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); - $offset += 4; - $thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); - $offset += 4; - - $IndexEntriesData = $SimpleIndexObjectData.fread($this->getid3->fp, 6 * $thisfile_asf_simpleindexobject['index_entries_count']); - for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) { - $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); - $offset += 4; - $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); - $offset += 2; - } - - break; - - case GETID3_ASF_Index_Object: - // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1) - // Field Name Field Type Size (bits) - // Object ID GUID 128 // GUID for the Index Object - GETID3_ASF_Index_Object - // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header - // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms. - // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object. - // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object. - - // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0. - // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. - // Index Specifiers array of: varies // - // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. - // * Index Type WORD 16 // Specifies Index Type values as follows: - // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time. - // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object. - // 3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set. - // Nearest Past Cleanpoint is the most common type of index. - // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block. - // * Block Positions QWORD varies // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed. - // * Index Entries array of: varies // - // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value - - // shortcut - $thisfile_asf['asf_index_object'] = array(); - $thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object']; - - $ASFIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 34 - 24); - $offset = 24; - - $thisfile_asf_asfindexobject['objectid'] = $NextObjectGUID; - $thisfile_asf_asfindexobject['objectid_guid'] = $NextObjectGUIDtext; - $thisfile_asf_asfindexobject['objectsize'] = $NextObjectSize; - - $thisfile_asf_asfindexobject['entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); - $offset += 4; - $thisfile_asf_asfindexobject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); - $offset += 2; - $thisfile_asf_asfindexobject['index_blocks_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); - $offset += 4; - - $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { - $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); - $offset += 2; - $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; - $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); - $offset += 2; - $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']); - } - - $ASFIndexObjectData .= fread($this->getid3->fp, 4); - $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); - $offset += 4; - - $ASFIndexObjectData .= fread($this->getid3->fp, 8 * $thisfile_asf_asfindexobject['index_specifiers_count']); - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { - $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); - $offset += 8; - } - - $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']); - for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) { - for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { - $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); - $offset += 4; - } - } - break; - - - default: - // Implementations shall ignore any standard or non-standard object that they do not know how to handle. - if ($this->GUIDname($NextObjectGUIDtext)) { - $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8); - } else { - $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($this->getid3->fp) - 16 - 8); - } - fseek($this->getid3->fp, ($NextObjectSize - 16 - 8), SEEK_CUR); - break; - } - } - - if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) { - foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { - switch ($streamdata['information']) { - case 'WMV1': - case 'WMV2': - case 'WMV3': - case 'MSS1': - case 'MSS2': - case 'WMVA': - case 'WVC1': - case 'WMVP': - case 'WVP2': - $thisfile_video['dataformat'] = 'wmv'; - $info['mime_type'] = 'video/x-ms-wmv'; - break; - - case 'MP42': - case 'MP43': - case 'MP4S': - case 'mp4s': - $thisfile_video['dataformat'] = 'asf'; - $info['mime_type'] = 'video/x-ms-asf'; - break; - - default: - switch ($streamdata['type_raw']) { - case 1: - if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { - $thisfile_video['dataformat'] = 'wmv'; - if ($info['mime_type'] == 'video/x-ms-asf') { - $info['mime_type'] = 'video/x-ms-wmv'; - } - } - break; - - case 2: - if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { - $thisfile_audio['dataformat'] = 'wma'; - if ($info['mime_type'] == 'video/x-ms-asf') { - $info['mime_type'] = 'audio/x-ms-wma'; - } - } - break; - - } - break; - } - } - } - - switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') { - case 'MPEG Layer-3': - $thisfile_audio['dataformat'] = 'mp3'; - break; - - default: - break; - } - - if (isset($thisfile_asf_codeclistobject['codec_entries'])) { - foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { - switch ($streamdata['type_raw']) { - - case 1: // video - $thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); - break; - - case 2: // audio - $thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); - - // AH 2003-10-01 - $thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']); - - $thisfile_audio['codec'] = $thisfile_audio['encoder']; - break; - - default: - $info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']; - break; - - } - } - } - - if (isset($info['audio'])) { - $thisfile_audio['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); - $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); - } - if (!empty($thisfile_video['dataformat'])) { - $thisfile_video['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); - $thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1); - $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); - } - if (!empty($thisfile_video['streams'])) { - $thisfile_video['streams']['resolution_x'] = 0; - $thisfile_video['streams']['resolution_y'] = 0; - foreach ($thisfile_video['streams'] as $key => $valuearray) { - if (($valuearray['resolution_x'] > $thisfile_video['streams']['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['streams']['resolution_y'])) { - $thisfile_video['resolution_x'] = $valuearray['resolution_x']; - $thisfile_video['resolution_y'] = $valuearray['resolution_y']; - } - } - } - $info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0); - - if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) { - $info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8); - } - - return true; - } - - public static function ASFCodecListObjectTypeLookup($CodecListType) { - static $ASFCodecListObjectTypeLookup = array(); - if (empty($ASFCodecListObjectTypeLookup)) { - $ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec'; - $ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec'; - $ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec'; - } - - return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type'); - } - - public static function KnownGUIDs() { - static $GUIDarray = array( - 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', - 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8', - 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8', - 'GETID3_ASF_Script_Command_Object' => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6', - 'GETID3_ASF_No_Error_Correction' => '20FB5700-5B55-11CF-A8FD-00805F5C442B', - 'GETID3_ASF_Content_Branding_Object' => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E', - 'GETID3_ASF_Content_Encryption_Object' => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E', - 'GETID3_ASF_Digital_Signature_Object' => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E', - 'GETID3_ASF_Extended_Content_Encryption_Object' => '298AE614-2622-4C17-B935-DAE07EE9289C', - 'GETID3_ASF_Simple_Index_Object' => '33000890-E5B1-11CF-89F4-00A0C90349CB', - 'GETID3_ASF_Degradable_JPEG_Media' => '35907DE0-E415-11CF-A917-00805F5C442B', - 'GETID3_ASF_Payload_Extension_System_Timecode' => '399595EC-8667-4E2D-8FDB-98814CE76C1E', - 'GETID3_ASF_Binary_Media' => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343', - 'GETID3_ASF_Timecode_Index_Object' => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C', - 'GETID3_ASF_Metadata_Library_Object' => '44231C94-9498-49D1-A141-1D134E457054', - 'GETID3_ASF_Reserved_3' => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6', - 'GETID3_ASF_Reserved_4' => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB', - 'GETID3_ASF_Command_Media' => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6', - 'GETID3_ASF_Header_Extension_Object' => '5FBF03B5-A92E-11CF-8EE3-00C00C205365', - 'GETID3_ASF_Media_Object_Index_Parameters_Obj' => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7', - 'GETID3_ASF_Header_Object' => '75B22630-668E-11CF-A6D9-00AA0062CE6C', - 'GETID3_ASF_Content_Description_Object' => '75B22633-668E-11CF-A6D9-00AA0062CE6C', - 'GETID3_ASF_Error_Correction_Object' => '75B22635-668E-11CF-A6D9-00AA0062CE6C', - 'GETID3_ASF_Data_Object' => '75B22636-668E-11CF-A6D9-00AA0062CE6C', - 'GETID3_ASF_Web_Stream_Media_Subtype' => '776257D4-C627-41CB-8F81-7AC7FF1C40CC', - 'GETID3_ASF_Stream_Bitrate_Properties_Object' => '7BF875CE-468D-11D1-8D82-006097C9A2B2', - 'GETID3_ASF_Language_List_Object' => '7C4346A9-EFE0-4BFC-B229-393EDE415C85', - 'GETID3_ASF_Codec_List_Object' => '86D15240-311D-11D0-A3A4-00A0C90348F6', - 'GETID3_ASF_Reserved_2' => '86D15241-311D-11D0-A3A4-00A0C90348F6', - 'GETID3_ASF_File_Properties_Object' => '8CABDCA1-A947-11CF-8EE4-00C00C205365', - 'GETID3_ASF_File_Transfer_Media' => '91BD222C-F21C-497A-8B6D-5AA86BFC0185', - 'GETID3_ASF_Old_RTP_Extension_Data' => '96800C63-4C94-11D1-837B-0080C7A37F95', - 'GETID3_ASF_Advanced_Mutual_Exclusion_Object' => 'A08649CF-4775-4670-8A16-6E35357566CD', - 'GETID3_ASF_Bandwidth_Sharing_Object' => 'A69609E6-517B-11D2-B6AF-00C04FD908E9', - 'GETID3_ASF_Reserved_1' => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365', - 'GETID3_ASF_Bandwidth_Sharing_Exclusive' => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9', - 'GETID3_ASF_Bandwidth_Sharing_Partial' => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9', - 'GETID3_ASF_JFIF_Media' => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B', - 'GETID3_ASF_Stream_Properties_Object' => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365', - 'GETID3_ASF_Video_Media' => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B', - 'GETID3_ASF_Audio_Spread' => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220', - 'GETID3_ASF_Metadata_Object' => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA', - 'GETID3_ASF_Payload_Ext_Syst_Sample_Duration' => 'C6BD9450-867F-4907-83A3-C77921B733AD', - 'GETID3_ASF_Group_Mutual_Exclusion_Object' => 'D1465A40-5A79-4338-B71B-E36B8FD6C249', - 'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850', - 'GETID3_ASF_Stream_Prioritization_Object' => 'D4FED15B-88D3-454F-81F0-ED5C45999E24', - 'GETID3_ASF_Payload_Ext_System_Content_Type' => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC', - 'GETID3_ASF_Old_File_Properties_Object' => 'D6E229D0-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_ASF_Header_Object' => 'D6E229D1-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_ASF_Data_Object' => 'D6E229D2-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Index_Object' => 'D6E229D3-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Stream_Properties_Object' => 'D6E229D4-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Content_Description_Object' => 'D6E229D5-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Script_Command_Object' => 'D6E229D6-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Marker_Object' => 'D6E229D7-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Component_Download_Object' => 'D6E229D8-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Stream_Group_Object' => 'D6E229D9-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Scalable_Object' => 'D6E229DA-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Prioritization_Object' => 'D6E229DB-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Bitrate_Mutual_Exclusion_Object' => 'D6E229DC-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Inter_Media_Dependency_Object' => 'D6E229DD-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Rating_Object' => 'D6E229DE-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Index_Parameters_Object' => 'D6E229DF-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Color_Table_Object' => 'D6E229E0-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Language_List_Object' => 'D6E229E1-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Audio_Media' => 'D6E229E2-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Video_Media' => 'D6E229E3-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Image_Media' => 'D6E229E4-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Timecode_Media' => 'D6E229E5-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Text_Media' => 'D6E229E6-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_MIDI_Media' => 'D6E229E7-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Command_Media' => 'D6E229E8-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_No_Error_Concealment' => 'D6E229EA-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Scrambled_Audio' => 'D6E229EB-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_No_Color_Table' => 'D6E229EC-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_SMPTE_Time' => 'D6E229ED-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_ASCII_Text' => 'D6E229EE-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Unicode_Text' => 'D6E229EF-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_HTML_Text' => 'D6E229F0-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_URL_Command' => 'D6E229F1-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Filename_Command' => 'D6E229F2-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_ACM_Codec' => 'D6E229F3-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_VCM_Codec' => 'D6E229F4-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_QuickTime_Codec' => 'D6E229F5-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_DirectShow_Transform_Filter' => 'D6E229F6-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_DirectShow_Rendering_Filter' => 'D6E229F7-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_No_Enhancement' => 'D6E229F8-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Unknown_Enhancement_Type' => 'D6E229F9-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Temporal_Enhancement' => 'D6E229FA-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Spatial_Enhancement' => 'D6E229FB-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Quality_Enhancement' => 'D6E229FC-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Number_of_Channels_Enhancement' => 'D6E229FD-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Frequency_Response_Enhancement' => 'D6E229FE-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Media_Object' => 'D6E229FF-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Mutex_Language' => 'D6E22A00-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Mutex_Bitrate' => 'D6E22A01-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Mutex_Unknown' => 'D6E22A02-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_ASF_Placeholder_Object' => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Old_Data_Unit_Extension_Object' => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE', - 'GETID3_ASF_Web_Stream_Format' => 'DA1E6B13-8359-4050-B398-388E965BF00C', - 'GETID3_ASF_Payload_Ext_System_File_Name' => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B', - 'GETID3_ASF_Marker_Object' => 'F487CD01-A951-11CF-8EE6-00C00C205365', - 'GETID3_ASF_Timecode_Index_Parameters_Object' => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24', - 'GETID3_ASF_Audio_Media' => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B', - 'GETID3_ASF_Media_Object_Index_Object' => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C', - 'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE', - 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html - 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html - ); - return $GUIDarray; - } - - public static function GUIDname($GUIDstring) { - static $GUIDarray = array(); - if (empty($GUIDarray)) { - $GUIDarray = self::KnownGUIDs(); - } - return array_search($GUIDstring, $GUIDarray); - } - - public static function ASFIndexObjectIndexTypeLookup($id) { - static $ASFIndexObjectIndexTypeLookup = array(); - if (empty($ASFIndexObjectIndexTypeLookup)) { - $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; - $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; - $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; - } - return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); - } - - public static function GUIDtoBytestring($GUIDstring) { - // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: - // first 4 bytes are in little-endian order - // next 2 bytes are appended in little-endian order - // next 2 bytes are appended in little-endian order - // next 2 bytes are appended in big-endian order - // next 6 bytes are appended in big-endian order - - // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string: - // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp - - $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2))); - - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2))); - - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2))); - - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2))); - - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2))); - $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2))); - - return $hexbytecharstring; - } - - public static function BytestringToGUID($Bytestring) { - $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= '-'; - $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= '-'; - $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= '-'; - $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= '-'; - $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT); - $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT); - - return strtoupper($GUIDstring); - } - - public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { - // FILETIME is a 64-bit unsigned integer representing - // the number of 100-nanosecond intervals since January 1, 1601 - // UNIX timestamp is number of seconds since January 1, 1970 - // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days - if ($round) { - return intval(round(($FILETIME - 116444736000000000) / 10000000)); - } - return ($FILETIME - 116444736000000000) / 10000000; - } - - public static function WMpictureTypeLookup($WMpictureType) { - static $WMpictureTypeLookup = array(); - if (empty($WMpictureTypeLookup)) { - $WMpictureTypeLookup[0x03] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Front Cover'); - $WMpictureTypeLookup[0x04] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Back Cover'); - $WMpictureTypeLookup[0x00] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'User Defined'); - $WMpictureTypeLookup[0x05] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Leaflet Page'); - $WMpictureTypeLookup[0x06] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Media Label'); - $WMpictureTypeLookup[0x07] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lead Artist'); - $WMpictureTypeLookup[0x08] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Artist'); - $WMpictureTypeLookup[0x09] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Conductor'); - $WMpictureTypeLookup[0x0A] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band'); - $WMpictureTypeLookup[0x0B] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Composer'); - $WMpictureTypeLookup[0x0C] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lyricist'); - $WMpictureTypeLookup[0x0D] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Recording Location'); - $WMpictureTypeLookup[0x0E] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Recording'); - $WMpictureTypeLookup[0x0F] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Performance'); - $WMpictureTypeLookup[0x10] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Video Screen Capture'); - $WMpictureTypeLookup[0x12] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Illustration'); - $WMpictureTypeLookup[0x13] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band Logotype'); - $WMpictureTypeLookup[0x14] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Publisher Logotype'); - } - return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : ''); - } - - public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) { - // http://msdn.microsoft.com/en-us/library/bb643323.aspx - - $offset = 0; - $objectOffset = 0; - $HeaderExtensionObjectParsed = array(); - while ($objectOffset < strlen($asf_header_extension_object_data)) { - $offset = $objectOffset; - $thisObject = array(); - - $thisObject['guid'] = substr($asf_header_extension_object_data, $offset, 16); - $offset += 16; - $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']); - $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']); - - $thisObject['size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); - $offset += 8; - if ($thisObject['size'] <= 0) { - break; - } - - switch ($thisObject['guid']) { - case GETID3_ASF_Extended_Stream_Properties_Object: - $thisObject['start_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); - $offset += 8; - $thisObject['start_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['start_time']); - - $thisObject['end_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); - $offset += 8; - $thisObject['end_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['end_time']); - - $thisObject['data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['alternate_data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['alternate_buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['maximum_object_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - $thisObject['flags']['reliable'] = (bool) $thisObject['flags_raw'] & 0x00000001; - $thisObject['flags']['seekable'] = (bool) $thisObject['flags_raw'] & 0x00000002; - $thisObject['flags']['no_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000004; - $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008; - - $thisObject['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $thisObject['stream_language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $thisObject['average_time_per_frame'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $thisObject['stream_name_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $thisObject['payload_extension_system_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - for ($i = 0; $i < $thisObject['stream_name_count']; $i++) { - $streamName = array(); - - $streamName['language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $streamName['stream_name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $streamName['stream_name'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $streamName['stream_name_length'])); - $offset += $streamName['stream_name_length']; - - $thisObject['stream_names'][$i] = $streamName; - } - - for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) { - $payloadExtensionSystem = array(); - - $payloadExtensionSystem['extension_system_id'] = substr($asf_header_extension_object_data, $offset, 16); - $offset += 16; - $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']); - - $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - if ($payloadExtensionSystem['extension_system_size'] <= 0) { - break 2; - } - - $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $payloadExtensionSystem['extension_system_info_length'])); - $offset += $payloadExtensionSystem['extension_system_info_length']; - - $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem; - } - - break; - - case GETID3_ASF_Padding_Object: - // padding, skip it - break; - - case GETID3_ASF_Metadata_Object: - $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - for ($i = 0; $i < $thisObject['description_record_counts']; $i++) { - $descriptionRecord = array(); - - $descriptionRecord['reserved_1'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); // must be zero - $offset += 2; - - $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); - - $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); - $offset += $descriptionRecord['name_length']; - - $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); - $offset += $descriptionRecord['data_length']; - switch ($descriptionRecord['data_type']) { - case 0x0000: // Unicode string - break; - - case 0x0001: // BYTE array - // do nothing - break; - - case 0x0002: // BOOL - $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']); - break; - - case 0x0003: // DWORD - case 0x0004: // QWORD - case 0x0005: // WORD - $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']); - break; - - case 0x0006: // GUID - $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']); - break; - } - - $thisObject['description_record'][$i] = $descriptionRecord; - } - break; - - case GETID3_ASF_Language_List_Object: - $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) { - $languageIDrecord = array(); - - $languageIDrecord['language_id_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1)); - $offset += 1; - - $languageIDrecord['language_id'] = substr($asf_header_extension_object_data, $offset, $languageIDrecord['language_id_length']); - $offset += $languageIDrecord['language_id_length']; - - $thisObject['language_id_record'][$i] = $languageIDrecord; - } - break; - - case GETID3_ASF_Metadata_Library_Object: - $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - for ($i = 0; $i < $thisObject['description_records_count']; $i++) { - $descriptionRecord = array(); - - $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - - $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); - $offset += 2; - $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); - - $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); - $offset += 4; - - $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); - $offset += $descriptionRecord['name_length']; - - $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); - $offset += $descriptionRecord['data_length']; - - if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) { - $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']); - foreach ($WMpicture as $key => $value) { - $descriptionRecord['data'] = $WMpicture; - } - unset($WMpicture); - } - - $thisObject['description_record'][$i] = $descriptionRecord; - } - break; - - default: - $unhandled_sections++; - if ($this->GUIDname($thisObject['guid_text'])) { - $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8); - } else { - $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8); - } - break; - } - $HeaderExtensionObjectParsed[] = $thisObject; - - $objectOffset += $thisObject['size']; - } - return $HeaderExtensionObjectParsed; - } - - - public static function ASFmetadataLibraryObjectDataTypeLookup($id) { - static $ASFmetadataLibraryObjectDataTypeLookup = array( - 0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters - 0x0001 => 'BYTE array', // The type of the data is implementation-specific - 0x0002 => 'BOOL', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values - 0x0003 => 'DWORD', // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer - 0x0004 => 'QWORD', // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer - 0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer - 0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID - ); - return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid'); - } - - public function ASF_WMpicture(&$data) { - //typedef struct _WMPicture{ - // LPWSTR pwszMIMEType; - // BYTE bPictureType; - // LPWSTR pwszDescription; - // DWORD dwDataLen; - // BYTE* pbData; - //} WM_PICTURE; - - $WMpicture = array(); - - $offset = 0; - $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1)); - $offset += 1; - $WMpicture['image_type'] = $this->WMpictureTypeLookup($WMpicture['image_type_id']); - $WMpicture['image_size'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 4)); - $offset += 4; - - $WMpicture['image_mime'] = ''; - do { - $next_byte_pair = substr($data, $offset, 2); - $offset += 2; - $WMpicture['image_mime'] .= $next_byte_pair; - } while ($next_byte_pair !== "\x00\x00"); - - $WMpicture['image_description'] = ''; - do { - $next_byte_pair = substr($data, $offset, 2); - $offset += 2; - $WMpicture['image_description'] .= $next_byte_pair; - } while ($next_byte_pair !== "\x00\x00"); - - $WMpicture['dataoffset'] = $offset; - $WMpicture['data'] = substr($data, $offset); - - $imageinfo = array(); - $WMpicture['image_mime'] = ''; - $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo); - unset($imageinfo); - if (!empty($imagechunkcheck)) { - $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); - } - if (!isset($this->getid3->info['asf']['comments']['picture'])) { - $this->getid3->info['asf']['comments']['picture'] = array(); - } - $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']); - - return $WMpicture; - } - - - // Remove terminator 00 00 and convert UTF-16LE to Latin-1 - public static function TrimConvert($string) { - return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); - } - - - // Remove terminator 00 00 - public static function TrimTerm($string) { - // remove terminator, only if present (it should be, but...) - if (substr($string, -2) === "\x00\x00") { - $string = substr($string, 0, -2); - } - return $string; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.asf.php // +// module for analyzing ASF, WMA and WMV files // +// dependencies: module.audio-video.riff.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + +class getid3_asf extends getid3_handler +{ + + public function __construct(getID3 $getid3) { + parent::__construct($getid3); // extends getid3_handler::__construct() + + // initialize all GUID constants + $GUIDarray = $this->KnownGUIDs(); + foreach ($GUIDarray as $GUIDname => $hexstringvalue) { + if (!defined($GUIDname)) { + define($GUIDname, $this->GUIDtoBytestring($hexstringvalue)); + } + } + } + + public function Analyze() { + $info = &$this->getid3->info; + + // Shortcuts + $thisfile_audio = &$info['audio']; + $thisfile_video = &$info['video']; + $info['asf'] = array(); + $thisfile_asf = &$info['asf']; + $thisfile_asf['comments'] = array(); + $thisfile_asf_comments = &$thisfile_asf['comments']; + $thisfile_asf['header_object'] = array(); + $thisfile_asf_headerobject = &$thisfile_asf['header_object']; + + + // ASF structure: + // * Header Object [required] + // * File Properties Object [required] (global file attributes) + // * Stream Properties Object [required] (defines media stream & characteristics) + // * Header Extension Object [required] (additional functionality) + // * Content Description Object (bibliographic information) + // * Script Command Object (commands for during playback) + // * Marker Object (named jumped points within the file) + // * Data Object [required] + // * Data Packets + // * Index Object + + // Header Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for header object - GETID3_ASF_Header_Object + // Object Size QWORD 64 // size of header object, including 30 bytes of Header Object header + // Number of Header Objects DWORD 32 // number of objects in header object + // Reserved1 BYTE 8 // hardcoded: 0x01 + // Reserved2 BYTE 8 // hardcoded: 0x02 + + $info['fileformat'] = 'asf'; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $HeaderObjectData = fread($this->getid3->fp, 30); + + $thisfile_asf_headerobject['objectid'] = substr($HeaderObjectData, 0, 16); + $thisfile_asf_headerobject['objectid_guid'] = $this->BytestringToGUID($thisfile_asf_headerobject['objectid']); + if ($thisfile_asf_headerobject['objectid'] != GETID3_ASF_Header_Object) { + $info['warning'][] = 'ASF header GUID {'.$this->BytestringToGUID($thisfile_asf_headerobject['objectid']).'} does not match expected "GETID3_ASF_Header_Object" GUID {'.$this->BytestringToGUID(GETID3_ASF_Header_Object).'}'; + unset($info['fileformat']); + unset($info['asf']); + return false; + break; + } + $thisfile_asf_headerobject['objectsize'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 16, 8)); + $thisfile_asf_headerobject['headerobjects'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 24, 4)); + $thisfile_asf_headerobject['reserved1'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 28, 1)); + $thisfile_asf_headerobject['reserved2'] = getid3_lib::LittleEndian2Int(substr($HeaderObjectData, 29, 1)); + + $NextObjectOffset = ftell($this->getid3->fp); + $ASFHeaderData = fread($this->getid3->fp, $thisfile_asf_headerobject['objectsize'] - 30); + $offset = 0; + + for ($HeaderObjectsCounter = 0; $HeaderObjectsCounter < $thisfile_asf_headerobject['headerobjects']; $HeaderObjectsCounter++) { + $NextObjectGUID = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); + $NextObjectSize = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + switch ($NextObjectGUID) { + + case GETID3_ASF_File_Properties_Object: + // File Properties Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for file properties object - GETID3_ASF_File_Properties_Object + // Object Size QWORD 64 // size of file properties object, including 104 bytes of File Properties Object header + // File ID GUID 128 // unique ID - identical to File ID in Data Object + // File Size QWORD 64 // entire file in bytes. Invalid if Broadcast Flag == 1 + // Creation Date QWORD 64 // date & time of file creation. Maybe invalid if Broadcast Flag == 1 + // Data Packets Count QWORD 64 // number of data packets in Data Object. Invalid if Broadcast Flag == 1 + // Play Duration QWORD 64 // playtime, in 100-nanosecond units. Invalid if Broadcast Flag == 1 + // Send Duration QWORD 64 // time needed to send file, in 100-nanosecond units. Players can ignore this value. Invalid if Broadcast Flag == 1 + // Preroll QWORD 64 // time to buffer data before starting to play file, in 1-millisecond units. If <> 0, PlayDuration and PresentationTime have been offset by this amount + // Flags DWORD 32 // + // * Broadcast Flag bits 1 (0x01) // file is currently being written, some header values are invalid + // * Seekable Flag bits 1 (0x02) // is file seekable + // * Reserved bits 30 (0xFFFFFFFC) // reserved - set to zero + // Minimum Data Packet Size DWORD 32 // in bytes. should be same as Maximum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Data Packet Size DWORD 32 // in bytes. should be same as Minimum Data Packet Size. Invalid if Broadcast Flag == 1 + // Maximum Bitrate DWORD 32 // maximum instantaneous bitrate in bits per second for entire file, including all data streams and ASF overhead + + // shortcut + $thisfile_asf['file_properties_object'] = array(); + $thisfile_asf_filepropertiesobject = &$thisfile_asf['file_properties_object']; + + $thisfile_asf_filepropertiesobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_filepropertiesobject['objectid'] = $NextObjectGUID; + $thisfile_asf_filepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_filepropertiesobject['objectsize'] = $NextObjectSize; + $thisfile_asf_filepropertiesobject['fileid'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_filepropertiesobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_filepropertiesobject['fileid']); + $thisfile_asf_filepropertiesobject['filesize'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_filepropertiesobject['creation_date'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $thisfile_asf_filepropertiesobject['creation_date_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_filepropertiesobject['creation_date']); + $offset += 8; + $thisfile_asf_filepropertiesobject['data_packets'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_filepropertiesobject['play_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_filepropertiesobject['send_duration'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_filepropertiesobject['preroll'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_filepropertiesobject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_filepropertiesobject['flags']['broadcast'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0001); + $thisfile_asf_filepropertiesobject['flags']['seekable'] = (bool) ($thisfile_asf_filepropertiesobject['flags_raw'] & 0x0002); + + $thisfile_asf_filepropertiesobject['min_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_filepropertiesobject['max_packet_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_filepropertiesobject['max_bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + + if ($thisfile_asf_filepropertiesobject['flags']['broadcast']) { + + // broadcast flag is set, some values invalid + unset($thisfile_asf_filepropertiesobject['filesize']); + unset($thisfile_asf_filepropertiesobject['data_packets']); + unset($thisfile_asf_filepropertiesobject['play_duration']); + unset($thisfile_asf_filepropertiesobject['send_duration']); + unset($thisfile_asf_filepropertiesobject['min_packet_size']); + unset($thisfile_asf_filepropertiesobject['max_packet_size']); + + } else { + + // broadcast flag NOT set, perform calculations + $info['playtime_seconds'] = ($thisfile_asf_filepropertiesobject['play_duration'] / 10000000) - ($thisfile_asf_filepropertiesobject['preroll'] / 1000); + + //$info['bitrate'] = $thisfile_asf_filepropertiesobject['max_bitrate']; + $info['bitrate'] = ((isset($thisfile_asf_filepropertiesobject['filesize']) ? $thisfile_asf_filepropertiesobject['filesize'] : $info['filesize']) * 8) / $info['playtime_seconds']; + } + break; + + case GETID3_ASF_Stream_Properties_Object: + // Stream Properties Object: (mandatory, one per media stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for stream properties object - GETID3_ASF_Stream_Properties_Object + // Object Size QWORD 64 // size of stream properties object, including 78 bytes of Stream Properties Object header + // Stream Type GUID 128 // GETID3_ASF_Audio_Media, GETID3_ASF_Video_Media or GETID3_ASF_Command_Media + // Error Correction Type GUID 128 // GETID3_ASF_Audio_Spread for audio-only streams, GETID3_ASF_No_Error_Correction for other stream types + // Time Offset QWORD 64 // 100-nanosecond units. typically zero. added to all timestamps of samples in the stream + // Type-Specific Data Length DWORD 32 // number of bytes for Type-Specific Data field + // Error Correction Data Length DWORD 32 // number of bytes for Error Correction Data field + // Flags WORD 16 // + // * Stream Number bits 7 (0x007F) // number of this stream. 1 <= valid <= 127 + // * Reserved bits 8 (0x7F80) // reserved - set to zero + // * Encrypted Content Flag bits 1 (0x8000) // stream contents encrypted if set + // Reserved DWORD 32 // reserved - set to zero + // Type-Specific Data BYTESTREAM variable // type-specific format data, depending on value of Stream Type + // Error Correction Data BYTESTREAM variable // error-correction-specific format data, depending on value of Error Correct Type + + // There is one GETID3_ASF_Stream_Properties_Object for each stream (audio, video) but the + // stream number isn't known until halfway through decoding the structure, hence it + // it is decoded to a temporary variable and then stuck in the appropriate index later + + $StreamPropertiesObjectData['offset'] = $NextObjectOffset + $offset; + $StreamPropertiesObjectData['objectid'] = $NextObjectGUID; + $StreamPropertiesObjectData['objectid_guid'] = $NextObjectGUIDtext; + $StreamPropertiesObjectData['objectsize'] = $NextObjectSize; + $StreamPropertiesObjectData['stream_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $StreamPropertiesObjectData['stream_type_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['stream_type']); + $StreamPropertiesObjectData['error_correct_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $StreamPropertiesObjectData['error_correct_guid'] = $this->BytestringToGUID($StreamPropertiesObjectData['error_correct_type']); + $StreamPropertiesObjectData['time_offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $StreamPropertiesObjectData['type_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $StreamPropertiesObjectData['error_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $StreamPropertiesObjectData['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $StreamPropertiesObjectStreamNumber = $StreamPropertiesObjectData['flags_raw'] & 0x007F; + $StreamPropertiesObjectData['flags']['encrypted'] = (bool) ($StreamPropertiesObjectData['flags_raw'] & 0x8000); + + $offset += 4; // reserved - DWORD + $StreamPropertiesObjectData['type_specific_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['type_data_length']); + $offset += $StreamPropertiesObjectData['type_data_length']; + $StreamPropertiesObjectData['error_correct_data'] = substr($ASFHeaderData, $offset, $StreamPropertiesObjectData['error_data_length']); + $offset += $StreamPropertiesObjectData['error_data_length']; + + switch ($StreamPropertiesObjectData['stream_type']) { + + case GETID3_ASF_Audio_Media: + $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); + $thisfile_audio['bitrate_mode'] = (!empty($thisfile_audio['bitrate_mode']) ? $thisfile_audio['bitrate_mode'] : 'cbr'); + + $audiodata = getid3_riff::parseWAVEFORMATex(substr($StreamPropertiesObjectData['type_specific_data'], 0, 16)); + unset($audiodata['raw']); + $thisfile_audio = getid3_lib::array_merge_noclobber($audiodata, $thisfile_audio); + break; + + case GETID3_ASF_Video_Media: + $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); + $thisfile_video['bitrate_mode'] = (!empty($thisfile_video['bitrate_mode']) ? $thisfile_video['bitrate_mode'] : 'cbr'); + break; + + case GETID3_ASF_Command_Media: + default: + // do nothing + break; + + } + + $thisfile_asf['stream_properties_object'][$StreamPropertiesObjectStreamNumber] = $StreamPropertiesObjectData; + unset($StreamPropertiesObjectData); // clear for next stream, if any + break; + + case GETID3_ASF_Header_Extension_Object: + // Header Extension Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Header Extension object - GETID3_ASF_Header_Extension_Object + // Object Size QWORD 64 // size of Header Extension object, including 46 bytes of Header Extension Object header + // Reserved Field 1 GUID 128 // hardcoded: GETID3_ASF_Reserved_1 + // Reserved Field 2 WORD 16 // hardcoded: 0x00000006 + // Header Extension Data Size DWORD 32 // in bytes. valid: 0, or > 24. equals object size minus 46 + // Header Extension Data BYTESTREAM variable // array of zero or more extended header objects + + // shortcut + $thisfile_asf['header_extension_object'] = array(); + $thisfile_asf_headerextensionobject = &$thisfile_asf['header_extension_object']; + + $thisfile_asf_headerextensionobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_headerextensionobject['objectid'] = $NextObjectGUID; + $thisfile_asf_headerextensionobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_headerextensionobject['objectsize'] = $NextObjectSize; + $thisfile_asf_headerextensionobject['reserved_1'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_headerextensionobject['reserved_1_guid'] = $this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']); + if ($thisfile_asf_headerextensionobject['reserved_1'] != GETID3_ASF_Reserved_1) { + $info['warning'][] = 'header_extension_object.reserved_1 GUID ('.$this->BytestringToGUID($thisfile_asf_headerextensionobject['reserved_1']).') does not match expected "GETID3_ASF_Reserved_1" GUID ('.$this->BytestringToGUID(GETID3_ASF_Reserved_1).')'; + //return false; + break; + } + $thisfile_asf_headerextensionobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + if ($thisfile_asf_headerextensionobject['reserved_2'] != 6) { + $info['warning'][] = 'header_extension_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_headerextensionobject['reserved_2']).') does not match expected value of "6"'; + //return false; + break; + } + $thisfile_asf_headerextensionobject['extension_data_size'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_headerextensionobject['extension_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_headerextensionobject['extension_data_size']); + $unhandled_sections = 0; + $thisfile_asf_headerextensionobject['extension_data_parsed'] = $this->ASF_HeaderExtensionObjectDataParse($thisfile_asf_headerextensionobject['extension_data'], $unhandled_sections); + if ($unhandled_sections === 0) { + unset($thisfile_asf_headerextensionobject['extension_data']); + } + $offset += $thisfile_asf_headerextensionobject['extension_data_size']; + break; + + case GETID3_ASF_Codec_List_Object: + // Codec List Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Codec List object - GETID3_ASF_Codec_List_Object + // Object Size QWORD 64 // size of Codec List object, including 44 bytes of Codec List Object header + // Reserved GUID 128 // hardcoded: 86D15241-311D-11D0-A3A4-00A0C90348F6 + // Codec Entries Count DWORD 32 // number of entries in Codec Entries array + // Codec Entries array of: variable // + // * Type WORD 16 // 0x0001 = Video Codec, 0x0002 = Audio Codec, 0xFFFF = Unknown Codec + // * Codec Name Length WORD 16 // number of Unicode characters stored in the Codec Name field + // * Codec Name WCHAR variable // array of Unicode characters - name of codec used to create the content + // * Codec Description Length WORD 16 // number of Unicode characters stored in the Codec Description field + // * Codec Description WCHAR variable // array of Unicode characters - description of format used to create the content + // * Codec Information Length WORD 16 // number of Unicode characters stored in the Codec Information field + // * Codec Information BYTESTREAM variable // opaque array of information bytes about the codec used to create the content + + // shortcut + $thisfile_asf['codec_list_object'] = array(); + $thisfile_asf_codeclistobject = &$thisfile_asf['codec_list_object']; + + $thisfile_asf_codeclistobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_codeclistobject['objectid'] = $NextObjectGUID; + $thisfile_asf_codeclistobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_codeclistobject['objectsize'] = $NextObjectSize; + $thisfile_asf_codeclistobject['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_codeclistobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']); + if ($thisfile_asf_codeclistobject['reserved'] != $this->GUIDtoBytestring('86D15241-311D-11D0-A3A4-00A0C90348F6')) { + $info['warning'][] = 'codec_list_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_codeclistobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {86D15241-311D-11D0-A3A4-00A0C90348F6}'; + //return false; + break; + } + $thisfile_asf_codeclistobject['codec_entries_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + for ($CodecEntryCounter = 0; $CodecEntryCounter < $thisfile_asf_codeclistobject['codec_entries_count']; $CodecEntryCounter++) { + // shortcut + $thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter] = array(); + $thisfile_asf_codeclistobject_codecentries_current = &$thisfile_asf_codeclistobject['codec_entries'][$CodecEntryCounter]; + + $thisfile_asf_codeclistobject_codecentries_current['type_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_codeclistobject_codecentries_current['type'] = $this->ASFCodecListObjectTypeLookup($thisfile_asf_codeclistobject_codecentries_current['type_raw']); + + $CodecNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_codeclistobject_codecentries_current['name'] = substr($ASFHeaderData, $offset, $CodecNameLength); + $offset += $CodecNameLength; + + $CodecDescriptionLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_codeclistobject_codecentries_current['description'] = substr($ASFHeaderData, $offset, $CodecDescriptionLength); + $offset += $CodecDescriptionLength; + + $CodecInformationLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_codeclistobject_codecentries_current['information'] = substr($ASFHeaderData, $offset, $CodecInformationLength); + $offset += $CodecInformationLength; + + if ($thisfile_asf_codeclistobject_codecentries_current['type_raw'] == 2) { // audio codec + + if (strpos($thisfile_asf_codeclistobject_codecentries_current['description'], ',') === false) { + $info['warning'][] = '[asf][codec_list_object][codec_entries]['.$CodecEntryCounter.'][description] expected to contain comma-seperated list of parameters: "'.$thisfile_asf_codeclistobject_codecentries_current['description'].'"'; + } else { + + list($AudioCodecBitrate, $AudioCodecFrequency, $AudioCodecChannels) = explode(',', $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description'])); + $thisfile_audio['codec'] = $this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['name']); + + if (!isset($thisfile_audio['bitrate']) && strstr($AudioCodecBitrate, 'kbps')) { + $thisfile_audio['bitrate'] = (int) (trim(str_replace('kbps', '', $AudioCodecBitrate)) * 1000); + } + //if (!isset($thisfile_video['bitrate']) && isset($thisfile_audio['bitrate']) && isset($thisfile_asf['file_properties_object']['max_bitrate']) && ($thisfile_asf_codeclistobject['codec_entries_count'] > 1)) { + if (empty($thisfile_video['bitrate']) && !empty($thisfile_audio['bitrate']) && !empty($info['bitrate'])) { + //$thisfile_video['bitrate'] = $thisfile_asf['file_properties_object']['max_bitrate'] - $thisfile_audio['bitrate']; + $thisfile_video['bitrate'] = $info['bitrate'] - $thisfile_audio['bitrate']; + } + + $AudioCodecFrequency = (int) trim(str_replace('kHz', '', $AudioCodecFrequency)); + switch ($AudioCodecFrequency) { + case 8: + case 8000: + $thisfile_audio['sample_rate'] = 8000; + break; + + case 11: + case 11025: + $thisfile_audio['sample_rate'] = 11025; + break; + + case 12: + case 12000: + $thisfile_audio['sample_rate'] = 12000; + break; + + case 16: + case 16000: + $thisfile_audio['sample_rate'] = 16000; + break; + + case 22: + case 22050: + $thisfile_audio['sample_rate'] = 22050; + break; + + case 24: + case 24000: + $thisfile_audio['sample_rate'] = 24000; + break; + + case 32: + case 32000: + $thisfile_audio['sample_rate'] = 32000; + break; + + case 44: + case 441000: + $thisfile_audio['sample_rate'] = 44100; + break; + + case 48: + case 48000: + $thisfile_audio['sample_rate'] = 48000; + break; + + default: + $info['warning'][] = 'unknown frequency: "'.$AudioCodecFrequency.'" ('.$this->TrimConvert($thisfile_asf_codeclistobject_codecentries_current['description']).')'; + break; + } + + if (!isset($thisfile_audio['channels'])) { + if (strstr($AudioCodecChannels, 'stereo')) { + $thisfile_audio['channels'] = 2; + } elseif (strstr($AudioCodecChannels, 'mono')) { + $thisfile_audio['channels'] = 1; + } + } + + } + } + } + break; + + case GETID3_ASF_Script_Command_Object: + // Script Command Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Script Command object - GETID3_ASF_Script_Command_Object + // Object Size QWORD 64 // size of Script Command object, including 44 bytes of Script Command Object header + // Reserved GUID 128 // hardcoded: 4B1ACBE3-100B-11D0-A39B-00A0C90348F6 + // Commands Count WORD 16 // number of Commands structures in the Script Commands Objects + // Command Types Count WORD 16 // number of Command Types structures in the Script Commands Objects + // Command Types array of: variable // + // * Command Type Name Length WORD 16 // number of Unicode characters for Command Type Name + // * Command Type Name WCHAR variable // array of Unicode characters - name of a type of command + // Commands array of: variable // + // * Presentation Time DWORD 32 // presentation time of that command, in milliseconds + // * Type Index WORD 16 // type of this command, as a zero-based index into the array of Command Types of this object + // * Command Name Length WORD 16 // number of Unicode characters for Command Name + // * Command Name WCHAR variable // array of Unicode characters - name of this command + + // shortcut + $thisfile_asf['script_command_object'] = array(); + $thisfile_asf_scriptcommandobject = &$thisfile_asf['script_command_object']; + + $thisfile_asf_scriptcommandobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_scriptcommandobject['objectid'] = $NextObjectGUID; + $thisfile_asf_scriptcommandobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_scriptcommandobject['objectsize'] = $NextObjectSize; + $thisfile_asf_scriptcommandobject['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_scriptcommandobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']); + if ($thisfile_asf_scriptcommandobject['reserved'] != $this->GUIDtoBytestring('4B1ACBE3-100B-11D0-A39B-00A0C90348F6')) { + $info['warning'][] = 'script_command_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_scriptcommandobject['reserved']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4B1ACBE3-100B-11D0-A39B-00A0C90348F6}'; + //return false; + break; + } + $thisfile_asf_scriptcommandobject['commands_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_scriptcommandobject['command_types_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($CommandTypesCounter = 0; $CommandTypesCounter < $thisfile_asf_scriptcommandobject['command_types_count']; $CommandTypesCounter++) { + $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_scriptcommandobject['command_types'][$CommandTypesCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + } + for ($CommandsCounter = 0; $CommandsCounter < $thisfile_asf_scriptcommandobject['commands_count']; $CommandsCounter++) { + $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['type_index'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + + $CommandTypeNameLength = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)) * 2; // 2 bytes per character + $offset += 2; + $thisfile_asf_scriptcommandobject['commands'][$CommandsCounter]['name'] = substr($ASFHeaderData, $offset, $CommandTypeNameLength); + $offset += $CommandTypeNameLength; + } + break; + + case GETID3_ASF_Marker_Object: + // Marker Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Marker object - GETID3_ASF_Marker_Object + // Object Size QWORD 64 // size of Marker object, including 48 bytes of Marker Object header + // Reserved GUID 128 // hardcoded: 4CFEDB20-75F6-11CF-9C0F-00A0C90349CB + // Markers Count DWORD 32 // number of Marker structures in Marker Object + // Reserved WORD 16 // hardcoded: 0x0000 + // Name Length WORD 16 // number of bytes in the Name field + // Name WCHAR variable // name of the Marker Object + // Markers array of: variable // + // * Offset QWORD 64 // byte offset into Data Object + // * Presentation Time QWORD 64 // in 100-nanosecond units + // * Entry Length WORD 16 // length in bytes of (Send Time + Flags + Marker Description Length + Marker Description + Padding) + // * Send Time DWORD 32 // in milliseconds + // * Flags DWORD 32 // hardcoded: 0x00000000 + // * Marker Description Length DWORD 32 // number of bytes in Marker Description field + // * Marker Description WCHAR variable // array of Unicode characters - description of marker entry + // * Padding BYTESTREAM variable // optional padding bytes + + // shortcut + $thisfile_asf['marker_object'] = array(); + $thisfile_asf_markerobject = &$thisfile_asf['marker_object']; + + $thisfile_asf_markerobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_markerobject['objectid'] = $NextObjectGUID; + $thisfile_asf_markerobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_markerobject['objectsize'] = $NextObjectSize; + $thisfile_asf_markerobject['reserved'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_markerobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_markerobject['reserved']); + if ($thisfile_asf_markerobject['reserved'] != $this->GUIDtoBytestring('4CFEDB20-75F6-11CF-9C0F-00A0C90349CB')) { + $info['warning'][] = 'marker_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_markerobject['reserved_1']).'} does not match expected "GETID3_ASF_Reserved_1" GUID {4CFEDB20-75F6-11CF-9C0F-00A0C90349CB}'; + break; + } + $thisfile_asf_markerobject['markers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_markerobject['reserved_2'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + if ($thisfile_asf_markerobject['reserved_2'] != 0) { + $info['warning'][] = 'marker_object.reserved_2 ('.getid3_lib::PrintHexBytes($thisfile_asf_markerobject['reserved_2']).') does not match expected value of "0"'; + break; + } + $thisfile_asf_markerobject['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_markerobject['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['name_length']); + $offset += $thisfile_asf_markerobject['name_length']; + for ($MarkersCounter = 0; $MarkersCounter < $thisfile_asf_markerobject['markers_count']; $MarkersCounter++) { + $thisfile_asf_markerobject['markers'][$MarkersCounter]['offset'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['presentation_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 8)); + $offset += 8; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['send_time'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['flags'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description'] = substr($ASFHeaderData, $offset, $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']); + $offset += $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; + $PaddingLength = $thisfile_asf_markerobject['markers'][$MarkersCounter]['entry_length'] - 4 - 4 - 4 - $thisfile_asf_markerobject['markers'][$MarkersCounter]['marker_description_length']; + if ($PaddingLength > 0) { + $thisfile_asf_markerobject['markers'][$MarkersCounter]['padding'] = substr($ASFHeaderData, $offset, $PaddingLength); + $offset += $PaddingLength; + } + } + break; + + case GETID3_ASF_Bitrate_Mutual_Exclusion_Object: + // Bitrate Mutual Exclusion Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Bitrate Mutual Exclusion object - GETID3_ASF_Bitrate_Mutual_Exclusion_Object + // Object Size QWORD 64 // size of Bitrate Mutual Exclusion object, including 42 bytes of Bitrate Mutual Exclusion Object header + // Exlusion Type GUID 128 // nature of mutual exclusion relationship. one of: (GETID3_ASF_Mutex_Bitrate, GETID3_ASF_Mutex_Unknown) + // Stream Numbers Count WORD 16 // number of video streams + // Stream Numbers WORD variable // array of mutually exclusive video stream numbers. 1 <= valid <= 127 + + // shortcut + $thisfile_asf['bitrate_mutual_exclusion_object'] = array(); + $thisfile_asf_bitratemutualexclusionobject = &$thisfile_asf['bitrate_mutual_exclusion_object']; + + $thisfile_asf_bitratemutualexclusionobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_bitratemutualexclusionobject['objectid'] = $NextObjectGUID; + $thisfile_asf_bitratemutualexclusionobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_bitratemutualexclusionobject['objectsize'] = $NextObjectSize; + $thisfile_asf_bitratemutualexclusionobject['reserved'] = substr($ASFHeaderData, $offset, 16); + $thisfile_asf_bitratemutualexclusionobject['reserved_guid'] = $this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']); + $offset += 16; + if (($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Bitrate) && ($thisfile_asf_bitratemutualexclusionobject['reserved'] != GETID3_ASF_Mutex_Unknown)) { + $info['warning'][] = 'bitrate_mutual_exclusion_object.reserved GUID {'.$this->BytestringToGUID($thisfile_asf_bitratemutualexclusionobject['reserved']).'} does not match expected "GETID3_ASF_Mutex_Bitrate" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Bitrate).'} or "GETID3_ASF_Mutex_Unknown" GUID {'.$this->BytestringToGUID(GETID3_ASF_Mutex_Unknown).'}'; + //return false; + break; + } + $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($StreamNumberCounter = 0; $StreamNumberCounter < $thisfile_asf_bitratemutualexclusionobject['stream_numbers_count']; $StreamNumberCounter++) { + $thisfile_asf_bitratemutualexclusionobject['stream_numbers'][$StreamNumberCounter] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + } + break; + + case GETID3_ASF_Error_Correction_Object: + // Error Correction Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Error Correction object - GETID3_ASF_Error_Correction_Object + // Object Size QWORD 64 // size of Error Correction object, including 44 bytes of Error Correction Object header + // Error Correction Type GUID 128 // type of error correction. one of: (GETID3_ASF_No_Error_Correction, GETID3_ASF_Audio_Spread) + // Error Correction Data Length DWORD 32 // number of bytes in Error Correction Data field + // Error Correction Data BYTESTREAM variable // structure depends on value of Error Correction Type field + + // shortcut + $thisfile_asf['error_correction_object'] = array(); + $thisfile_asf_errorcorrectionobject = &$thisfile_asf['error_correction_object']; + + $thisfile_asf_errorcorrectionobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_errorcorrectionobject['objectid'] = $NextObjectGUID; + $thisfile_asf_errorcorrectionobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_errorcorrectionobject['objectsize'] = $NextObjectSize; + $thisfile_asf_errorcorrectionobject['error_correction_type'] = substr($ASFHeaderData, $offset, 16); + $offset += 16; + $thisfile_asf_errorcorrectionobject['error_correction_guid'] = $this->BytestringToGUID($thisfile_asf_errorcorrectionobject['error_correction_type']); + $thisfile_asf_errorcorrectionobject['error_correction_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + switch ($thisfile_asf_errorcorrectionobject['error_correction_type']) { + case GETID3_ASF_No_Error_Correction: + // should be no data, but just in case there is, skip to the end of the field + $offset += $thisfile_asf_errorcorrectionobject['error_correction_data_length']; + break; + + case GETID3_ASF_Audio_Spread: + // Field Name Field Type Size (bits) + // Span BYTE 8 // number of packets over which audio will be spread. + // Virtual Packet Length WORD 16 // size of largest audio payload found in audio stream + // Virtual Chunk Length WORD 16 // size of largest audio payload found in audio stream + // Silence Data Length WORD 16 // number of bytes in Silence Data field + // Silence Data BYTESTREAM variable // hardcoded: 0x00 * (Silence Data Length) bytes + + $thisfile_asf_errorcorrectionobject['span'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 1)); + $offset += 1; + $thisfile_asf_errorcorrectionobject['virtual_packet_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_errorcorrectionobject['virtual_chunk_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_errorcorrectionobject['silence_data_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_errorcorrectionobject['silence_data'] = substr($ASFHeaderData, $offset, $thisfile_asf_errorcorrectionobject['silence_data_length']); + $offset += $thisfile_asf_errorcorrectionobject['silence_data_length']; + break; + + default: + $info['warning'][] = 'error_correction_object.error_correction_type GUID {'.$this->BytestringToGUID($thisfile_asf_errorcorrectionobject['reserved']).'} does not match expected "GETID3_ASF_No_Error_Correction" GUID {'.$this->BytestringToGUID(GETID3_ASF_No_Error_Correction).'} or "GETID3_ASF_Audio_Spread" GUID {'.$this->BytestringToGUID(GETID3_ASF_Audio_Spread).'}'; + //return false; + break; + } + + break; + + case GETID3_ASF_Content_Description_Object: + // Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Content Description object - GETID3_ASF_Content_Description_Object + // Object Size QWORD 64 // size of Content Description object, including 34 bytes of Content Description Object header + // Title Length WORD 16 // number of bytes in Title field + // Author Length WORD 16 // number of bytes in Author field + // Copyright Length WORD 16 // number of bytes in Copyright field + // Description Length WORD 16 // number of bytes in Description field + // Rating Length WORD 16 // number of bytes in Rating field + // Title WCHAR 16 // array of Unicode characters - Title + // Author WCHAR 16 // array of Unicode characters - Author + // Copyright WCHAR 16 // array of Unicode characters - Copyright + // Description WCHAR 16 // array of Unicode characters - Description + // Rating WCHAR 16 // array of Unicode characters - Rating + + // shortcut + $thisfile_asf['content_description_object'] = array(); + $thisfile_asf_contentdescriptionobject = &$thisfile_asf['content_description_object']; + + $thisfile_asf_contentdescriptionobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_contentdescriptionobject['objectid'] = $NextObjectGUID; + $thisfile_asf_contentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_contentdescriptionobject['objectsize'] = $NextObjectSize; + $thisfile_asf_contentdescriptionobject['title_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_contentdescriptionobject['author_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_contentdescriptionobject['copyright_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_contentdescriptionobject['description_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_contentdescriptionobject['rating_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_contentdescriptionobject['title'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['title_length']); + $offset += $thisfile_asf_contentdescriptionobject['title_length']; + $thisfile_asf_contentdescriptionobject['author'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['author_length']); + $offset += $thisfile_asf_contentdescriptionobject['author_length']; + $thisfile_asf_contentdescriptionobject['copyright'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['copyright_length']); + $offset += $thisfile_asf_contentdescriptionobject['copyright_length']; + $thisfile_asf_contentdescriptionobject['description'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['description_length']); + $offset += $thisfile_asf_contentdescriptionobject['description_length']; + $thisfile_asf_contentdescriptionobject['rating'] = substr($ASFHeaderData, $offset, $thisfile_asf_contentdescriptionobject['rating_length']); + $offset += $thisfile_asf_contentdescriptionobject['rating_length']; + + $ASFcommentKeysToCopy = array('title'=>'title', 'author'=>'artist', 'copyright'=>'copyright', 'description'=>'comment', 'rating'=>'rating'); + foreach ($ASFcommentKeysToCopy as $keytocopyfrom => $keytocopyto) { + if (!empty($thisfile_asf_contentdescriptionobject[$keytocopyfrom])) { + $thisfile_asf_comments[$keytocopyto][] = $this->TrimTerm($thisfile_asf_contentdescriptionobject[$keytocopyfrom]); + } + } + break; + + case GETID3_ASF_Extended_Content_Description_Object: + // Extended Content Description Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Extended Content Description object - GETID3_ASF_Extended_Content_Description_Object + // Object Size QWORD 64 // size of ExtendedContent Description object, including 26 bytes of Extended Content Description Object header + // Content Descriptors Count WORD 16 // number of entries in Content Descriptors list + // Content Descriptors array of: variable // + // * Descriptor Name Length WORD 16 // size in bytes of Descriptor Name field + // * Descriptor Name WCHAR variable // array of Unicode characters - Descriptor Name + // * Descriptor Value Data Type WORD 16 // Lookup array: + // 0x0000 = Unicode String (variable length) + // 0x0001 = BYTE array (variable length) + // 0x0002 = BOOL (DWORD, 32 bits) + // 0x0003 = DWORD (DWORD, 32 bits) + // 0x0004 = QWORD (QWORD, 64 bits) + // 0x0005 = WORD (WORD, 16 bits) + // * Descriptor Value Length WORD 16 // number of bytes stored in Descriptor Value field + // * Descriptor Value variable variable // value for Content Descriptor + + // shortcut + $thisfile_asf['extended_content_description_object'] = array(); + $thisfile_asf_extendedcontentdescriptionobject = &$thisfile_asf['extended_content_description_object']; + + $thisfile_asf_extendedcontentdescriptionobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_extendedcontentdescriptionobject['objectid'] = $NextObjectGUID; + $thisfile_asf_extendedcontentdescriptionobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_extendedcontentdescriptionobject['objectsize'] = $NextObjectSize; + $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($ExtendedContentDescriptorsCounter = 0; $ExtendedContentDescriptorsCounter < $thisfile_asf_extendedcontentdescriptionobject['content_descriptors_count']; $ExtendedContentDescriptorsCounter++) { + // shortcut + $thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter] = array(); + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current = &$thisfile_asf_extendedcontentdescriptionobject['content_descriptors'][$ExtendedContentDescriptorsCounter]; + + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['base_offset'] = $offset + 30; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']); + $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name_length']; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = substr($ASFHeaderData, $offset, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']); + $offset += $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_length']; + switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { + case 0x0000: // Unicode string + break; + + case 0x0001: // BYTE array + // do nothing + break; + + case 0x0002: // BOOL + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = (bool) getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + break; + + case 0x0003: // DWORD + case 0x0004: // QWORD + case 0x0005: // WORD + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'] = getid3_lib::LittleEndian2Int($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + break; + + default: + $info['warning'][] = 'extended_content_description.content_descriptors.'.$ExtendedContentDescriptorsCounter.'.value_type is invalid ('.$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type'].')'; + //return false; + break; + } + switch ($this->TrimConvert(strtolower($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']))) { + + case 'wm/albumartist': + case 'artist': + // Note: not 'artist', that comes from 'author' tag + $thisfile_asf_comments['albumartist'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'wm/albumtitle': + case 'album': + $thisfile_asf_comments['album'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'wm/genre': + case 'genre': + $thisfile_asf_comments['genre'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'wm/partofset': + $thisfile_asf_comments['partofset'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'wm/tracknumber': + case 'tracknumber': + // be careful casting to int: casting unicode strings to int gives unexpected results (stops parsing at first non-numeric character) + $thisfile_asf_comments['track'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + foreach ($thisfile_asf_comments['track'] as $key => $value) { + if (preg_match('/^[0-9\x00]+$/', $value)) { + $thisfile_asf_comments['track'][$key] = intval(str_replace("\x00", '', $value)); + } + } + break; + + case 'wm/track': + if (empty($thisfile_asf_comments['track'])) { + $thisfile_asf_comments['track'] = array(1 + $this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + } + break; + + case 'wm/year': + case 'year': + case 'date': + $thisfile_asf_comments['year'] = array( $this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'wm/lyrics': + case 'lyrics': + $thisfile_asf_comments['lyrics'] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + break; + + case 'isvbr': + if ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']) { + $thisfile_audio['bitrate_mode'] = 'vbr'; + $thisfile_video['bitrate_mode'] = 'vbr'; + } + break; + + case 'id3': + // id3v2 module might not be loaded + if (class_exists('getid3_id3v2')) { + $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3'); + $tempfilehandle = fopen($tempfile, 'wb'); + $tempThisfileInfo = array('encoding'=>$info['encoding']); + fwrite($tempfilehandle, $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + fclose($tempfilehandle); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($tempfile); + $getid3_id3v2 = new getid3_id3v2($getid3_temp); + $getid3_id3v2->Analyze(); + $info['id3v2'] = $getid3_temp->info['id3v2']; + unset($getid3_temp, $getid3_id3v2); + + unlink($tempfile); + } + break; + + case 'wm/encodingtime': + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix'] = $this->FILETIMEtoUNIXtime($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + $thisfile_asf_comments['encoding_time_unix'] = array($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['encoding_time_unix']); + break; + + case 'wm/picture': + $WMpicture = $this->ASF_WMpicture($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + foreach ($WMpicture as $key => $value) { + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current[$key] = $value; + } + unset($WMpicture); +/* + $wm_picture_offset = 0; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 1)); + $wm_picture_offset += 1; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type'] = $this->WMpictureTypeLookup($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_type_id']); + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 4)); + $wm_picture_offset += 4; + + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; + do { + $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); + $wm_picture_offset += 2; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] = ''; + do { + $next_byte_pair = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset, 2); + $wm_picture_offset += 2; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_description'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['dataoffset'] = $wm_picture_offset; + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'] = substr($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'], $wm_picture_offset); + unset($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value']); + + $imageinfo = array(); + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = ''; + $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], $imageinfo); + unset($imageinfo); + if (!empty($imagechunkcheck)) { + $thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); + } + if (!isset($thisfile_asf_comments['picture'])) { + $thisfile_asf_comments['picture'] = array(); + } + $thisfile_asf_comments['picture'][] = array('data'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['data'], 'image_mime'=>$thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['image_mime']); +*/ + break; + + default: + switch ($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value_type']) { + case 0: // Unicode string + if (substr($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name']), 0, 3) == 'WM/') { + $thisfile_asf_comments[str_replace('wm/', '', strtolower($this->TrimConvert($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['name'])))] = array($this->TrimTerm($thisfile_asf_extendedcontentdescriptionobject_contentdescriptor_current['value'])); + } + break; + + case 1: + break; + } + break; + } + + } + break; + + case GETID3_ASF_Stream_Bitrate_Properties_Object: + // Stream Bitrate Properties Object: (optional, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Stream Bitrate Properties object - GETID3_ASF_Stream_Bitrate_Properties_Object + // Object Size QWORD 64 // size of Extended Content Description object, including 26 bytes of Stream Bitrate Properties Object header + // Bitrate Records Count WORD 16 // number of records in Bitrate Records + // Bitrate Records array of: variable // + // * Flags WORD 16 // + // * * Stream Number bits 7 (0x007F) // number of this stream + // * * Reserved bits 9 (0xFF80) // hardcoded: 0 + // * Average Bitrate DWORD 32 // in bits per second + + // shortcut + $thisfile_asf['stream_bitrate_properties_object'] = array(); + $thisfile_asf_streambitratepropertiesobject = &$thisfile_asf['stream_bitrate_properties_object']; + + $thisfile_asf_streambitratepropertiesobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_streambitratepropertiesobject['objectid'] = $NextObjectGUID; + $thisfile_asf_streambitratepropertiesobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_streambitratepropertiesobject['objectsize'] = $NextObjectSize; + $thisfile_asf_streambitratepropertiesobject['bitrate_records_count'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitratepropertiesobject['bitrate_records_count']; $BitrateRecordsCounter++) { + $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 2)); + $offset += 2; + $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags']['stream_number'] = $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['flags_raw'] & 0x007F; + $thisfile_asf_streambitratepropertiesobject['bitrate_records'][$BitrateRecordsCounter]['bitrate'] = getid3_lib::LittleEndian2Int(substr($ASFHeaderData, $offset, 4)); + $offset += 4; + } + break; + + case GETID3_ASF_Padding_Object: + // Padding Object: (optional) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Padding object - GETID3_ASF_Padding_Object + // Object Size QWORD 64 // size of Padding object, including 24 bytes of ASF Padding Object header + // Padding Data BYTESTREAM variable // ignore + + // shortcut + $thisfile_asf['padding_object'] = array(); + $thisfile_asf_paddingobject = &$thisfile_asf['padding_object']; + + $thisfile_asf_paddingobject['offset'] = $NextObjectOffset + $offset; + $thisfile_asf_paddingobject['objectid'] = $NextObjectGUID; + $thisfile_asf_paddingobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_paddingobject['objectsize'] = $NextObjectSize; + $thisfile_asf_paddingobject['padding_length'] = $thisfile_asf_paddingobject['objectsize'] - 16 - 8; + $thisfile_asf_paddingobject['padding'] = substr($ASFHeaderData, $offset, $thisfile_asf_paddingobject['padding_length']); + $offset += ($NextObjectSize - 16 - 8); + break; + + case GETID3_ASF_Extended_Content_Encryption_Object: + case GETID3_ASF_Content_Encryption_Object: + // WMA DRM - just ignore + $offset += ($NextObjectSize - 16 - 8); + break; + + default: + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if ($this->GUIDname($NextObjectGUIDtext)) { + $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); + } else { + $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF header at offset '.($offset - 16 - 8); + } + $offset += ($NextObjectSize - 16 - 8); + break; + } + } + if (isset($thisfile_asf_streambitrateproperties['bitrate_records_count'])) { + $ASFbitrateAudio = 0; + $ASFbitrateVideo = 0; + for ($BitrateRecordsCounter = 0; $BitrateRecordsCounter < $thisfile_asf_streambitrateproperties['bitrate_records_count']; $BitrateRecordsCounter++) { + if (isset($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter])) { + switch ($thisfile_asf_codeclistobject['codec_entries'][$BitrateRecordsCounter]['type_raw']) { + case 1: + $ASFbitrateVideo += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; + break; + + case 2: + $ASFbitrateAudio += $thisfile_asf_streambitrateproperties['bitrate_records'][$BitrateRecordsCounter]['bitrate']; + break; + + default: + // do nothing + break; + } + } + } + if ($ASFbitrateAudio > 0) { + $thisfile_audio['bitrate'] = $ASFbitrateAudio; + } + if ($ASFbitrateVideo > 0) { + $thisfile_video['bitrate'] = $ASFbitrateVideo; + } + } + if (isset($thisfile_asf['stream_properties_object']) && is_array($thisfile_asf['stream_properties_object'])) { + + $thisfile_audio['bitrate'] = 0; + $thisfile_video['bitrate'] = 0; + + foreach ($thisfile_asf['stream_properties_object'] as $streamnumber => $streamdata) { + + switch ($streamdata['stream_type']) { + case GETID3_ASF_Audio_Media: + // Field Name Field Type Size (bits) + // Codec ID / Format Tag WORD 16 // unique ID of audio codec - defined as wFormatTag field of WAVEFORMATEX structure + // Number of Channels WORD 16 // number of channels of audio - defined as nChannels field of WAVEFORMATEX structure + // Samples Per Second DWORD 32 // in Hertz - defined as nSamplesPerSec field of WAVEFORMATEX structure + // Average number of Bytes/sec DWORD 32 // bytes/sec of audio stream - defined as nAvgBytesPerSec field of WAVEFORMATEX structure + // Block Alignment WORD 16 // block size in bytes of audio codec - defined as nBlockAlign field of WAVEFORMATEX structure + // Bits per sample WORD 16 // bits per sample of mono data. set to zero for variable bitrate codecs. defined as wBitsPerSample field of WAVEFORMATEX structure + // Codec Specific Data Size WORD 16 // size in bytes of Codec Specific Data buffer - defined as cbSize field of WAVEFORMATEX structure + // Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + // shortcut + $thisfile_asf['audio_media'][$streamnumber] = array(); + $thisfile_asf_audiomedia_currentstream = &$thisfile_asf['audio_media'][$streamnumber]; + + $audiomediaoffset = 0; + + $thisfile_asf_audiomedia_currentstream = getid3_riff::parseWAVEFORMATex(substr($streamdata['type_specific_data'], $audiomediaoffset, 16)); + $audiomediaoffset += 16; + + $thisfile_audio['lossless'] = false; + switch ($thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']) { + case 0x0001: // PCM + case 0x0163: // WMA9 Lossless + $thisfile_audio['lossless'] = true; + break; + } + + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { + $thisfile_asf_audiomedia_currentstream['bitrate'] = $dataarray['bitrate']; + $thisfile_audio['bitrate'] += $dataarray['bitrate']; + break; + } + } + } else { + if (!empty($thisfile_asf_audiomedia_currentstream['bytes_sec'])) { + $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bytes_sec'] * 8; + } elseif (!empty($thisfile_asf_audiomedia_currentstream['bitrate'])) { + $thisfile_audio['bitrate'] += $thisfile_asf_audiomedia_currentstream['bitrate']; + } + } + $thisfile_audio['streams'][$streamnumber] = $thisfile_asf_audiomedia_currentstream; + $thisfile_audio['streams'][$streamnumber]['wformattag'] = $thisfile_asf_audiomedia_currentstream['raw']['wFormatTag']; + $thisfile_audio['streams'][$streamnumber]['lossless'] = $thisfile_audio['lossless']; + $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; + $thisfile_audio['streams'][$streamnumber]['dataformat'] = 'wma'; + unset($thisfile_audio['streams'][$streamnumber]['raw']); + + $thisfile_asf_audiomedia_currentstream['codec_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $audiomediaoffset, 2)); + $audiomediaoffset += 2; + $thisfile_asf_audiomedia_currentstream['codec_data'] = substr($streamdata['type_specific_data'], $audiomediaoffset, $thisfile_asf_audiomedia_currentstream['codec_data_size']); + $audiomediaoffset += $thisfile_asf_audiomedia_currentstream['codec_data_size']; + + break; + + case GETID3_ASF_Video_Media: + // Field Name Field Type Size (bits) + // Encoded Image Width DWORD 32 // width of image in pixels + // Encoded Image Height DWORD 32 // height of image in pixels + // Reserved Flags BYTE 8 // hardcoded: 0x02 + // Format Data Size WORD 16 // size of Format Data field in bytes + // Format Data array of: variable // + // * Format Data Size DWORD 32 // number of bytes in Format Data field, in bytes - defined as biSize field of BITMAPINFOHEADER structure + // * Image Width LONG 32 // width of encoded image in pixels - defined as biWidth field of BITMAPINFOHEADER structure + // * Image Height LONG 32 // height of encoded image in pixels - defined as biHeight field of BITMAPINFOHEADER structure + // * Reserved WORD 16 // hardcoded: 0x0001 - defined as biPlanes field of BITMAPINFOHEADER structure + // * Bits Per Pixel Count WORD 16 // bits per pixel - defined as biBitCount field of BITMAPINFOHEADER structure + // * Compression ID FOURCC 32 // fourcc of video codec - defined as biCompression field of BITMAPINFOHEADER structure + // * Image Size DWORD 32 // image size in bytes - defined as biSizeImage field of BITMAPINFOHEADER structure + // * Horizontal Pixels / Meter DWORD 32 // horizontal resolution of target device in pixels per meter - defined as biXPelsPerMeter field of BITMAPINFOHEADER structure + // * Vertical Pixels / Meter DWORD 32 // vertical resolution of target device in pixels per meter - defined as biYPelsPerMeter field of BITMAPINFOHEADER structure + // * Colors Used Count DWORD 32 // number of color indexes in the color table that are actually used - defined as biClrUsed field of BITMAPINFOHEADER structure + // * Important Colors Count DWORD 32 // number of color index required for displaying bitmap. if zero, all colors are required. defined as biClrImportant field of BITMAPINFOHEADER structure + // * Codec Specific Data BYTESTREAM variable // array of codec-specific data bytes + + // shortcut + $thisfile_asf['video_media'][$streamnumber] = array(); + $thisfile_asf_videomedia_currentstream = &$thisfile_asf['video_media'][$streamnumber]; + + $videomediaoffset = 0; + $thisfile_asf_videomedia_currentstream['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['flags'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 1)); + $videomediaoffset += 1; + $thisfile_asf_videomedia_currentstream['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $thisfile_asf_videomedia_currentstream['format_data']['format_data_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['image_width'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['image_height'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['reserved'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 2)); + $videomediaoffset += 2; + $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc'] = substr($streamdata['type_specific_data'], $videomediaoffset, 4); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['image_size'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['horizontal_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['vertical_pels'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['colors_used'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['colors_important'] = getid3_lib::LittleEndian2Int(substr($streamdata['type_specific_data'], $videomediaoffset, 4)); + $videomediaoffset += 4; + $thisfile_asf_videomedia_currentstream['format_data']['codec_data'] = substr($streamdata['type_specific_data'], $videomediaoffset); + + if (!empty($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'])) { + foreach ($thisfile_asf['stream_bitrate_properties_object']['bitrate_records'] as $dummy => $dataarray) { + if (isset($dataarray['flags']['stream_number']) && ($dataarray['flags']['stream_number'] == $streamnumber)) { + $thisfile_asf_videomedia_currentstream['bitrate'] = $dataarray['bitrate']; + $thisfile_video['streams'][$streamnumber]['bitrate'] = $dataarray['bitrate']; + $thisfile_video['bitrate'] += $dataarray['bitrate']; + break; + } + } + } + + $thisfile_asf_videomedia_currentstream['format_data']['codec'] = getid3_riff::fourccLookup($thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']); + + $thisfile_video['streams'][$streamnumber]['fourcc'] = $thisfile_asf_videomedia_currentstream['format_data']['codec_fourcc']; + $thisfile_video['streams'][$streamnumber]['codec'] = $thisfile_asf_videomedia_currentstream['format_data']['codec']; + $thisfile_video['streams'][$streamnumber]['resolution_x'] = $thisfile_asf_videomedia_currentstream['image_width']; + $thisfile_video['streams'][$streamnumber]['resolution_y'] = $thisfile_asf_videomedia_currentstream['image_height']; + $thisfile_video['streams'][$streamnumber]['bits_per_sample'] = $thisfile_asf_videomedia_currentstream['format_data']['bits_per_pixel']; + break; + + default: + break; + } + } + } + + while (ftell($this->getid3->fp) < $info['avdataend']) { + $NextObjectDataHeader = fread($this->getid3->fp, 24); + $offset = 0; + $NextObjectGUID = substr($NextObjectDataHeader, 0, 16); + $offset += 16; + $NextObjectGUIDtext = $this->BytestringToGUID($NextObjectGUID); + $NextObjectSize = getid3_lib::LittleEndian2Int(substr($NextObjectDataHeader, $offset, 8)); + $offset += 8; + + switch ($NextObjectGUID) { + case GETID3_ASF_Data_Object: + // Data Object: (mandatory, one only) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Data object - GETID3_ASF_Data_Object + // Object Size QWORD 64 // size of Data object, including 50 bytes of Data Object header. may be 0 if FilePropertiesObject.BroadcastFlag == 1 + // File ID GUID 128 // unique identifier. identical to File ID field in Header Object + // Total Data Packets QWORD 64 // number of Data Packet entries in Data Object. invalid if FilePropertiesObject.BroadcastFlag == 1 + // Reserved WORD 16 // hardcoded: 0x0101 + + // shortcut + $thisfile_asf['data_object'] = array(); + $thisfile_asf_dataobject = &$thisfile_asf['data_object']; + + $DataObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 50 - 24); + $offset = 24; + + $thisfile_asf_dataobject['objectid'] = $NextObjectGUID; + $thisfile_asf_dataobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_dataobject['objectsize'] = $NextObjectSize; + + $thisfile_asf_dataobject['fileid'] = substr($DataObjectData, $offset, 16); + $offset += 16; + $thisfile_asf_dataobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_dataobject['fileid']); + $thisfile_asf_dataobject['total_data_packets'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 8)); + $offset += 8; + $thisfile_asf_dataobject['reserved'] = getid3_lib::LittleEndian2Int(substr($DataObjectData, $offset, 2)); + $offset += 2; + if ($thisfile_asf_dataobject['reserved'] != 0x0101) { + $info['warning'][] = 'data_object.reserved ('.getid3_lib::PrintHexBytes($thisfile_asf_dataobject['reserved']).') does not match expected value of "0x0101"'; + //return false; + break; + } + + // Data Packets array of: variable // + // * Error Correction Flags BYTE 8 // + // * * Error Correction Data Length bits 4 // if Error Correction Length Type == 00, size of Error Correction Data in bytes, else hardcoded: 0000 + // * * Opaque Data Present bits 1 // + // * * Error Correction Length Type bits 2 // number of bits for size of the error correction data. hardcoded: 00 + // * * Error Correction Present bits 1 // If set, use Opaque Data Packet structure, else use Payload structure + // * Error Correction Data + + $info['avdataoffset'] = ftell($this->getid3->fp); + fseek($this->getid3->fp, ($thisfile_asf_dataobject['objectsize'] - 50), SEEK_CUR); // skip actual audio/video data + $info['avdataend'] = ftell($this->getid3->fp); + break; + + case GETID3_ASF_Simple_Index_Object: + // Simple Index Object: (optional, recommended, one per video stream) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for Simple Index object - GETID3_ASF_Data_Object + // Object Size QWORD 64 // size of Simple Index object, including 56 bytes of Simple Index Object header + // File ID GUID 128 // unique identifier. may be zero or identical to File ID field in Data Object and Header Object + // Index Entry Time Interval QWORD 64 // interval between index entries in 100-nanosecond units + // Maximum Packet Count DWORD 32 // maximum packet count for all index entries + // Index Entries Count DWORD 32 // number of Index Entries structures + // Index Entries array of: variable // + // * Packet Number DWORD 32 // number of the Data Packet associated with this index entry + // * Packet Count WORD 16 // number of Data Packets to sent at this index entry + + // shortcut + $thisfile_asf['simple_index_object'] = array(); + $thisfile_asf_simpleindexobject = &$thisfile_asf['simple_index_object']; + + $SimpleIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 56 - 24); + $offset = 24; + + $thisfile_asf_simpleindexobject['objectid'] = $NextObjectGUID; + $thisfile_asf_simpleindexobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_simpleindexobject['objectsize'] = $NextObjectSize; + + $thisfile_asf_simpleindexobject['fileid'] = substr($SimpleIndexObjectData, $offset, 16); + $offset += 16; + $thisfile_asf_simpleindexobject['fileid_guid'] = $this->BytestringToGUID($thisfile_asf_simpleindexobject['fileid']); + $thisfile_asf_simpleindexobject['index_entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 8)); + $offset += 8; + $thisfile_asf_simpleindexobject['maximum_packet_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + $offset += 4; + $thisfile_asf_simpleindexobject['index_entries_count'] = getid3_lib::LittleEndian2Int(substr($SimpleIndexObjectData, $offset, 4)); + $offset += 4; + + $IndexEntriesData = $SimpleIndexObjectData.fread($this->getid3->fp, 6 * $thisfile_asf_simpleindexobject['index_entries_count']); + for ($IndexEntriesCounter = 0; $IndexEntriesCounter < $thisfile_asf_simpleindexobject['index_entries_count']; $IndexEntriesCounter++) { + $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_number'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); + $offset += 4; + $thisfile_asf_simpleindexobject['index_entries'][$IndexEntriesCounter]['packet_count'] = getid3_lib::LittleEndian2Int(substr($IndexEntriesData, $offset, 4)); + $offset += 2; + } + + break; + + case GETID3_ASF_Index_Object: + // 6.2 ASF top-level Index Object (optional but recommended when appropriate, 0 or 1) + // Field Name Field Type Size (bits) + // Object ID GUID 128 // GUID for the Index Object - GETID3_ASF_Index_Object + // Object Size QWORD 64 // Specifies the size, in bytes, of the Index Object, including at least 34 bytes of Index Object header + // Index Entry Time Interval DWORD 32 // Specifies the time interval between each index entry in ms. + // Index Specifiers Count WORD 16 // Specifies the number of Index Specifiers structures in this Index Object. + // Index Blocks Count DWORD 32 // Specifies the number of Index Blocks structures in this Index Object. + + // Index Entry Time Interval DWORD 32 // Specifies the time interval between index entries in milliseconds. This value cannot be 0. + // Index Specifiers Count WORD 16 // Specifies the number of entries in the Index Specifiers list. Valid values are 1 and greater. + // Index Specifiers array of: varies // + // * Stream Number WORD 16 // Specifies the stream number that the Index Specifiers refer to. Valid values are between 1 and 127. + // * Index Type WORD 16 // Specifies Index Type values as follows: + // 1 = Nearest Past Data Packet - indexes point to the data packet whose presentation time is closest to the index entry time. + // 2 = Nearest Past Media Object - indexes point to the closest data packet containing an entire object or first fragment of an object. + // 3 = Nearest Past Cleanpoint. - indexes point to the closest data packet containing an entire object (or first fragment of an object) that has the Cleanpoint Flag set. + // Nearest Past Cleanpoint is the most common type of index. + // Index Entry Count DWORD 32 // Specifies the number of Index Entries in the block. + // * Block Positions QWORD varies // Specifies a list of byte offsets of the beginnings of the blocks relative to the beginning of the first Data Packet (i.e., the beginning of the Data Object + 50 bytes). The number of entries in this list is specified by the value of the Index Specifiers Count field. The order of those byte offsets is tied to the order in which Index Specifiers are listed. + // * Index Entries array of: varies // + // * * Offsets DWORD varies // An offset value of 0xffffffff indicates an invalid offset value + + // shortcut + $thisfile_asf['asf_index_object'] = array(); + $thisfile_asf_asfindexobject = &$thisfile_asf['asf_index_object']; + + $ASFIndexObjectData = $NextObjectDataHeader.fread($this->getid3->fp, 34 - 24); + $offset = 24; + + $thisfile_asf_asfindexobject['objectid'] = $NextObjectGUID; + $thisfile_asf_asfindexobject['objectid_guid'] = $NextObjectGUIDtext; + $thisfile_asf_asfindexobject['objectsize'] = $NextObjectSize; + + $thisfile_asf_asfindexobject['entry_time_interval'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + $thisfile_asf_asfindexobject['index_specifiers_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $thisfile_asf_asfindexobject['index_blocks_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + + $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count']); + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + $IndexSpecifierStreamNumber = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['stream_number'] = $IndexSpecifierStreamNumber; + $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 2)); + $offset += 2; + $thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type_text'] = $this->ASFIndexObjectIndexTypeLookup($thisfile_asf_asfindexobject['index_specifiers'][$IndexSpecifiersCounter]['index_type']); + } + + $ASFIndexObjectData .= fread($this->getid3->fp, 4); + $thisfile_asf_asfindexobject['index_entry_count'] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + + $ASFIndexObjectData .= fread($this->getid3->fp, 8 * $thisfile_asf_asfindexobject['index_specifiers_count']); + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + $thisfile_asf_asfindexobject['block_positions'][$IndexSpecifiersCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 8)); + $offset += 8; + } + + $ASFIndexObjectData .= fread($this->getid3->fp, 4 * $thisfile_asf_asfindexobject['index_specifiers_count'] * $thisfile_asf_asfindexobject['index_entry_count']); + for ($IndexEntryCounter = 0; $IndexEntryCounter < $thisfile_asf_asfindexobject['index_entry_count']; $IndexEntryCounter++) { + for ($IndexSpecifiersCounter = 0; $IndexSpecifiersCounter < $thisfile_asf_asfindexobject['index_specifiers_count']; $IndexSpecifiersCounter++) { + $thisfile_asf_asfindexobject['offsets'][$IndexSpecifiersCounter][$IndexEntryCounter] = getid3_lib::LittleEndian2Int(substr($ASFIndexObjectData, $offset, 4)); + $offset += 4; + } + } + break; + + + default: + // Implementations shall ignore any standard or non-standard object that they do not know how to handle. + if ($this->GUIDname($NextObjectGUIDtext)) { + $info['warning'][] = 'unhandled GUID "'.$this->GUIDname($NextObjectGUIDtext).'" {'.$NextObjectGUIDtext.'} in ASF body at offset '.($offset - 16 - 8); + } else { + $info['warning'][] = 'unknown GUID {'.$NextObjectGUIDtext.'} in ASF body at offset '.(ftell($this->getid3->fp) - 16 - 8); + } + fseek($this->getid3->fp, ($NextObjectSize - 16 - 8), SEEK_CUR); + break; + } + } + + if (isset($thisfile_asf_codeclistobject['codec_entries']) && is_array($thisfile_asf_codeclistobject['codec_entries'])) { + foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { + switch ($streamdata['information']) { + case 'WMV1': + case 'WMV2': + case 'WMV3': + case 'MSS1': + case 'MSS2': + case 'WMVA': + case 'WVC1': + case 'WMVP': + case 'WVP2': + $thisfile_video['dataformat'] = 'wmv'; + $info['mime_type'] = 'video/x-ms-wmv'; + break; + + case 'MP42': + case 'MP43': + case 'MP4S': + case 'mp4s': + $thisfile_video['dataformat'] = 'asf'; + $info['mime_type'] = 'video/x-ms-asf'; + break; + + default: + switch ($streamdata['type_raw']) { + case 1: + if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { + $thisfile_video['dataformat'] = 'wmv'; + if ($info['mime_type'] == 'video/x-ms-asf') { + $info['mime_type'] = 'video/x-ms-wmv'; + } + } + break; + + case 2: + if (strstr($this->TrimConvert($streamdata['name']), 'Windows Media')) { + $thisfile_audio['dataformat'] = 'wma'; + if ($info['mime_type'] == 'video/x-ms-asf') { + $info['mime_type'] = 'audio/x-ms-wma'; + } + } + break; + + } + break; + } + } + } + + switch (isset($thisfile_audio['codec']) ? $thisfile_audio['codec'] : '') { + case 'MPEG Layer-3': + $thisfile_audio['dataformat'] = 'mp3'; + break; + + default: + break; + } + + if (isset($thisfile_asf_codeclistobject['codec_entries'])) { + foreach ($thisfile_asf_codeclistobject['codec_entries'] as $streamnumber => $streamdata) { + switch ($streamdata['type_raw']) { + + case 1: // video + $thisfile_video['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); + break; + + case 2: // audio + $thisfile_audio['encoder'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][$streamnumber]['name']); + + // AH 2003-10-01 + $thisfile_audio['encoder_options'] = $this->TrimConvert($thisfile_asf_codeclistobject['codec_entries'][0]['description']); + + $thisfile_audio['codec'] = $thisfile_audio['encoder']; + break; + + default: + $info['warning'][] = 'Unknown streamtype: [codec_list_object][codec_entries]['.$streamnumber.'][type_raw] == '.$streamdata['type_raw']; + break; + + } + } + } + + if (isset($info['audio'])) { + $thisfile_audio['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); + $thisfile_audio['dataformat'] = (!empty($thisfile_audio['dataformat']) ? $thisfile_audio['dataformat'] : 'asf'); + } + if (!empty($thisfile_video['dataformat'])) { + $thisfile_video['lossless'] = (isset($thisfile_audio['lossless']) ? $thisfile_audio['lossless'] : false); + $thisfile_video['pixel_aspect_ratio'] = (isset($thisfile_audio['pixel_aspect_ratio']) ? $thisfile_audio['pixel_aspect_ratio'] : (float) 1); + $thisfile_video['dataformat'] = (!empty($thisfile_video['dataformat']) ? $thisfile_video['dataformat'] : 'asf'); + } + if (!empty($thisfile_video['streams'])) { + $thisfile_video['streams']['resolution_x'] = 0; + $thisfile_video['streams']['resolution_y'] = 0; + foreach ($thisfile_video['streams'] as $key => $valuearray) { + if (($valuearray['resolution_x'] > $thisfile_video['streams']['resolution_x']) || ($valuearray['resolution_y'] > $thisfile_video['streams']['resolution_y'])) { + $thisfile_video['resolution_x'] = $valuearray['resolution_x']; + $thisfile_video['resolution_y'] = $valuearray['resolution_y']; + } + } + } + $info['bitrate'] = (isset($thisfile_audio['bitrate']) ? $thisfile_audio['bitrate'] : 0) + (isset($thisfile_video['bitrate']) ? $thisfile_video['bitrate'] : 0); + + if ((!isset($info['playtime_seconds']) || ($info['playtime_seconds'] <= 0)) && ($info['bitrate'] > 0)) { + $info['playtime_seconds'] = ($info['filesize'] - $info['avdataoffset']) / ($info['bitrate'] / 8); + } + + return true; + } + + public static function ASFCodecListObjectTypeLookup($CodecListType) { + static $ASFCodecListObjectTypeLookup = array(); + if (empty($ASFCodecListObjectTypeLookup)) { + $ASFCodecListObjectTypeLookup[0x0001] = 'Video Codec'; + $ASFCodecListObjectTypeLookup[0x0002] = 'Audio Codec'; + $ASFCodecListObjectTypeLookup[0xFFFF] = 'Unknown Codec'; + } + + return (isset($ASFCodecListObjectTypeLookup[$CodecListType]) ? $ASFCodecListObjectTypeLookup[$CodecListType] : 'Invalid Codec Type'); + } + + public static function KnownGUIDs() { + static $GUIDarray = array( + 'GETID3_ASF_Extended_Stream_Properties_Object' => '14E6A5CB-C672-4332-8399-A96952065B5A', + 'GETID3_ASF_Padding_Object' => '1806D474-CADF-4509-A4BA-9AABCB96AAE8', + 'GETID3_ASF_Payload_Ext_Syst_Pixel_Aspect_Ratio' => '1B1EE554-F9EA-4BC8-821A-376B74E4C4B8', + 'GETID3_ASF_Script_Command_Object' => '1EFB1A30-0B62-11D0-A39B-00A0C90348F6', + 'GETID3_ASF_No_Error_Correction' => '20FB5700-5B55-11CF-A8FD-00805F5C442B', + 'GETID3_ASF_Content_Branding_Object' => '2211B3FA-BD23-11D2-B4B7-00A0C955FC6E', + 'GETID3_ASF_Content_Encryption_Object' => '2211B3FB-BD23-11D2-B4B7-00A0C955FC6E', + 'GETID3_ASF_Digital_Signature_Object' => '2211B3FC-BD23-11D2-B4B7-00A0C955FC6E', + 'GETID3_ASF_Extended_Content_Encryption_Object' => '298AE614-2622-4C17-B935-DAE07EE9289C', + 'GETID3_ASF_Simple_Index_Object' => '33000890-E5B1-11CF-89F4-00A0C90349CB', + 'GETID3_ASF_Degradable_JPEG_Media' => '35907DE0-E415-11CF-A917-00805F5C442B', + 'GETID3_ASF_Payload_Extension_System_Timecode' => '399595EC-8667-4E2D-8FDB-98814CE76C1E', + 'GETID3_ASF_Binary_Media' => '3AFB65E2-47EF-40F2-AC2C-70A90D71D343', + 'GETID3_ASF_Timecode_Index_Object' => '3CB73FD0-0C4A-4803-953D-EDF7B6228F0C', + 'GETID3_ASF_Metadata_Library_Object' => '44231C94-9498-49D1-A141-1D134E457054', + 'GETID3_ASF_Reserved_3' => '4B1ACBE3-100B-11D0-A39B-00A0C90348F6', + 'GETID3_ASF_Reserved_4' => '4CFEDB20-75F6-11CF-9C0F-00A0C90349CB', + 'GETID3_ASF_Command_Media' => '59DACFC0-59E6-11D0-A3AC-00A0C90348F6', + 'GETID3_ASF_Header_Extension_Object' => '5FBF03B5-A92E-11CF-8EE3-00C00C205365', + 'GETID3_ASF_Media_Object_Index_Parameters_Obj' => '6B203BAD-3F11-4E84-ACA8-D7613DE2CFA7', + 'GETID3_ASF_Header_Object' => '75B22630-668E-11CF-A6D9-00AA0062CE6C', + 'GETID3_ASF_Content_Description_Object' => '75B22633-668E-11CF-A6D9-00AA0062CE6C', + 'GETID3_ASF_Error_Correction_Object' => '75B22635-668E-11CF-A6D9-00AA0062CE6C', + 'GETID3_ASF_Data_Object' => '75B22636-668E-11CF-A6D9-00AA0062CE6C', + 'GETID3_ASF_Web_Stream_Media_Subtype' => '776257D4-C627-41CB-8F81-7AC7FF1C40CC', + 'GETID3_ASF_Stream_Bitrate_Properties_Object' => '7BF875CE-468D-11D1-8D82-006097C9A2B2', + 'GETID3_ASF_Language_List_Object' => '7C4346A9-EFE0-4BFC-B229-393EDE415C85', + 'GETID3_ASF_Codec_List_Object' => '86D15240-311D-11D0-A3A4-00A0C90348F6', + 'GETID3_ASF_Reserved_2' => '86D15241-311D-11D0-A3A4-00A0C90348F6', + 'GETID3_ASF_File_Properties_Object' => '8CABDCA1-A947-11CF-8EE4-00C00C205365', + 'GETID3_ASF_File_Transfer_Media' => '91BD222C-F21C-497A-8B6D-5AA86BFC0185', + 'GETID3_ASF_Old_RTP_Extension_Data' => '96800C63-4C94-11D1-837B-0080C7A37F95', + 'GETID3_ASF_Advanced_Mutual_Exclusion_Object' => 'A08649CF-4775-4670-8A16-6E35357566CD', + 'GETID3_ASF_Bandwidth_Sharing_Object' => 'A69609E6-517B-11D2-B6AF-00C04FD908E9', + 'GETID3_ASF_Reserved_1' => 'ABD3D211-A9BA-11cf-8EE6-00C00C205365', + 'GETID3_ASF_Bandwidth_Sharing_Exclusive' => 'AF6060AA-5197-11D2-B6AF-00C04FD908E9', + 'GETID3_ASF_Bandwidth_Sharing_Partial' => 'AF6060AB-5197-11D2-B6AF-00C04FD908E9', + 'GETID3_ASF_JFIF_Media' => 'B61BE100-5B4E-11CF-A8FD-00805F5C442B', + 'GETID3_ASF_Stream_Properties_Object' => 'B7DC0791-A9B7-11CF-8EE6-00C00C205365', + 'GETID3_ASF_Video_Media' => 'BC19EFC0-5B4D-11CF-A8FD-00805F5C442B', + 'GETID3_ASF_Audio_Spread' => 'BFC3CD50-618F-11CF-8BB2-00AA00B4E220', + 'GETID3_ASF_Metadata_Object' => 'C5F8CBEA-5BAF-4877-8467-AA8C44FA4CCA', + 'GETID3_ASF_Payload_Ext_Syst_Sample_Duration' => 'C6BD9450-867F-4907-83A3-C77921B733AD', + 'GETID3_ASF_Group_Mutual_Exclusion_Object' => 'D1465A40-5A79-4338-B71B-E36B8FD6C249', + 'GETID3_ASF_Extended_Content_Description_Object' => 'D2D0A440-E307-11D2-97F0-00A0C95EA850', + 'GETID3_ASF_Stream_Prioritization_Object' => 'D4FED15B-88D3-454F-81F0-ED5C45999E24', + 'GETID3_ASF_Payload_Ext_System_Content_Type' => 'D590DC20-07BC-436C-9CF7-F3BBFBF1A4DC', + 'GETID3_ASF_Old_File_Properties_Object' => 'D6E229D0-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_ASF_Header_Object' => 'D6E229D1-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_ASF_Data_Object' => 'D6E229D2-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Index_Object' => 'D6E229D3-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Stream_Properties_Object' => 'D6E229D4-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Content_Description_Object' => 'D6E229D5-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Script_Command_Object' => 'D6E229D6-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Marker_Object' => 'D6E229D7-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Component_Download_Object' => 'D6E229D8-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Stream_Group_Object' => 'D6E229D9-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Scalable_Object' => 'D6E229DA-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Prioritization_Object' => 'D6E229DB-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Bitrate_Mutual_Exclusion_Object' => 'D6E229DC-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Inter_Media_Dependency_Object' => 'D6E229DD-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Rating_Object' => 'D6E229DE-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Index_Parameters_Object' => 'D6E229DF-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Color_Table_Object' => 'D6E229E0-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Language_List_Object' => 'D6E229E1-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Audio_Media' => 'D6E229E2-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Video_Media' => 'D6E229E3-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Image_Media' => 'D6E229E4-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Timecode_Media' => 'D6E229E5-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Text_Media' => 'D6E229E6-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_MIDI_Media' => 'D6E229E7-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Command_Media' => 'D6E229E8-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_No_Error_Concealment' => 'D6E229EA-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Scrambled_Audio' => 'D6E229EB-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_No_Color_Table' => 'D6E229EC-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_SMPTE_Time' => 'D6E229ED-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_ASCII_Text' => 'D6E229EE-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Unicode_Text' => 'D6E229EF-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_HTML_Text' => 'D6E229F0-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_URL_Command' => 'D6E229F1-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Filename_Command' => 'D6E229F2-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_ACM_Codec' => 'D6E229F3-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_VCM_Codec' => 'D6E229F4-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_QuickTime_Codec' => 'D6E229F5-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_DirectShow_Transform_Filter' => 'D6E229F6-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_DirectShow_Rendering_Filter' => 'D6E229F7-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_No_Enhancement' => 'D6E229F8-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Unknown_Enhancement_Type' => 'D6E229F9-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Temporal_Enhancement' => 'D6E229FA-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Spatial_Enhancement' => 'D6E229FB-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Quality_Enhancement' => 'D6E229FC-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Number_of_Channels_Enhancement' => 'D6E229FD-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Frequency_Response_Enhancement' => 'D6E229FE-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Media_Object' => 'D6E229FF-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Mutex_Language' => 'D6E22A00-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Mutex_Bitrate' => 'D6E22A01-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Mutex_Unknown' => 'D6E22A02-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_ASF_Placeholder_Object' => 'D6E22A0E-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Old_Data_Unit_Extension_Object' => 'D6E22A0F-35DA-11D1-9034-00A0C90349BE', + 'GETID3_ASF_Web_Stream_Format' => 'DA1E6B13-8359-4050-B398-388E965BF00C', + 'GETID3_ASF_Payload_Ext_System_File_Name' => 'E165EC0E-19ED-45D7-B4A7-25CBD1E28E9B', + 'GETID3_ASF_Marker_Object' => 'F487CD01-A951-11CF-8EE6-00C00C205365', + 'GETID3_ASF_Timecode_Index_Parameters_Object' => 'F55E496D-9797-4B5D-8C8B-604DFE9BFB24', + 'GETID3_ASF_Audio_Media' => 'F8699E40-5B4D-11CF-A8FD-00805F5C442B', + 'GETID3_ASF_Media_Object_Index_Object' => 'FEB103F8-12AD-4C64-840F-2A1D2F7AD48C', + 'GETID3_ASF_Alt_Extended_Content_Encryption_Obj' => 'FF889EF1-ADEE-40DA-9E71-98704BB928CE', + 'GETID3_ASF_Index_Placeholder_Object' => 'D9AADE20-7C17-4F9C-BC28-8555DD98E2A2', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html + 'GETID3_ASF_Compatibility_Object' => '26F18B5D-4584-47EC-9F5F-0E651F0452C9', // http://cpan.uwinnipeg.ca/htdocs/Audio-WMA/Audio/WMA.pm.html + ); + return $GUIDarray; + } + + public static function GUIDname($GUIDstring) { + static $GUIDarray = array(); + if (empty($GUIDarray)) { + $GUIDarray = self::KnownGUIDs(); + } + return array_search($GUIDstring, $GUIDarray); + } + + public static function ASFIndexObjectIndexTypeLookup($id) { + static $ASFIndexObjectIndexTypeLookup = array(); + if (empty($ASFIndexObjectIndexTypeLookup)) { + $ASFIndexObjectIndexTypeLookup[1] = 'Nearest Past Data Packet'; + $ASFIndexObjectIndexTypeLookup[2] = 'Nearest Past Media Object'; + $ASFIndexObjectIndexTypeLookup[3] = 'Nearest Past Cleanpoint'; + } + return (isset($ASFIndexObjectIndexTypeLookup[$id]) ? $ASFIndexObjectIndexTypeLookup[$id] : 'invalid'); + } + + public static function GUIDtoBytestring($GUIDstring) { + // Microsoft defines these 16-byte (128-bit) GUIDs in the strangest way: + // first 4 bytes are in little-endian order + // next 2 bytes are appended in little-endian order + // next 2 bytes are appended in little-endian order + // next 2 bytes are appended in big-endian order + // next 6 bytes are appended in big-endian order + + // AaBbCcDd-EeFf-GgHh-IiJj-KkLlMmNnOoPp is stored as this 16-byte string: + // $Dd $Cc $Bb $Aa $Ff $Ee $Hh $Gg $Ii $Jj $Kk $Ll $Mm $Nn $Oo $Pp + + $hexbytecharstring = chr(hexdec(substr($GUIDstring, 6, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 4, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 2, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 0, 2))); + + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 11, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 9, 2))); + + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 16, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 14, 2))); + + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 19, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 21, 2))); + + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 24, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 26, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 28, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 30, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 32, 2))); + $hexbytecharstring .= chr(hexdec(substr($GUIDstring, 34, 2))); + + return $hexbytecharstring; + } + + public static function BytestringToGUID($Bytestring) { + $GUIDstring = str_pad(dechex(ord($Bytestring{3})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{2})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{1})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{0})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= '-'; + $GUIDstring .= str_pad(dechex(ord($Bytestring{5})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{4})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= '-'; + $GUIDstring .= str_pad(dechex(ord($Bytestring{7})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{6})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= '-'; + $GUIDstring .= str_pad(dechex(ord($Bytestring{8})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{9})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= '-'; + $GUIDstring .= str_pad(dechex(ord($Bytestring{10})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{11})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{12})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{13})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{14})), 2, '0', STR_PAD_LEFT); + $GUIDstring .= str_pad(dechex(ord($Bytestring{15})), 2, '0', STR_PAD_LEFT); + + return strtoupper($GUIDstring); + } + + public static function FILETIMEtoUNIXtime($FILETIME, $round=true) { + // FILETIME is a 64-bit unsigned integer representing + // the number of 100-nanosecond intervals since January 1, 1601 + // UNIX timestamp is number of seconds since January 1, 1970 + // 116444736000000000 = 10000000 * 60 * 60 * 24 * 365 * 369 + 89 leap days + if ($round) { + return intval(round(($FILETIME - 116444736000000000) / 10000000)); + } + return ($FILETIME - 116444736000000000) / 10000000; + } + + public static function WMpictureTypeLookup($WMpictureType) { + static $WMpictureTypeLookup = array(); + if (empty($WMpictureTypeLookup)) { + $WMpictureTypeLookup[0x03] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Front Cover'); + $WMpictureTypeLookup[0x04] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Back Cover'); + $WMpictureTypeLookup[0x00] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'User Defined'); + $WMpictureTypeLookup[0x05] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Leaflet Page'); + $WMpictureTypeLookup[0x06] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Media Label'); + $WMpictureTypeLookup[0x07] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lead Artist'); + $WMpictureTypeLookup[0x08] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Artist'); + $WMpictureTypeLookup[0x09] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Conductor'); + $WMpictureTypeLookup[0x0A] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band'); + $WMpictureTypeLookup[0x0B] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Composer'); + $WMpictureTypeLookup[0x0C] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Lyricist'); + $WMpictureTypeLookup[0x0D] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Recording Location'); + $WMpictureTypeLookup[0x0E] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Recording'); + $WMpictureTypeLookup[0x0F] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'During Performance'); + $WMpictureTypeLookup[0x10] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Video Screen Capture'); + $WMpictureTypeLookup[0x12] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Illustration'); + $WMpictureTypeLookup[0x13] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Band Logotype'); + $WMpictureTypeLookup[0x14] = getid3_lib::iconv_fallback('ISO-8859-1', 'UTF-16LE', 'Publisher Logotype'); + } + return (isset($WMpictureTypeLookup[$WMpictureType]) ? $WMpictureTypeLookup[$WMpictureType] : ''); + } + + public function ASF_HeaderExtensionObjectDataParse(&$asf_header_extension_object_data, &$unhandled_sections) { + // http://msdn.microsoft.com/en-us/library/bb643323.aspx + + $offset = 0; + $objectOffset = 0; + $HeaderExtensionObjectParsed = array(); + while ($objectOffset < strlen($asf_header_extension_object_data)) { + $offset = $objectOffset; + $thisObject = array(); + + $thisObject['guid'] = substr($asf_header_extension_object_data, $offset, 16); + $offset += 16; + $thisObject['guid_text'] = $this->BytestringToGUID($thisObject['guid']); + $thisObject['guid_name'] = $this->GUIDname($thisObject['guid_text']); + + $thisObject['size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); + $offset += 8; + if ($thisObject['size'] <= 0) { + break; + } + + switch ($thisObject['guid']) { + case GETID3_ASF_Extended_Stream_Properties_Object: + $thisObject['start_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); + $offset += 8; + $thisObject['start_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['start_time']); + + $thisObject['end_time'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 8)); + $offset += 8; + $thisObject['end_time_unix'] = $this->FILETIMEtoUNIXtime($thisObject['end_time']); + + $thisObject['data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['alternate_data_bitrate'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['alternate_buffer_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['alternate_initial_buffer_fullness'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['maximum_object_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['flags_raw'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + $thisObject['flags']['reliable'] = (bool) $thisObject['flags_raw'] & 0x00000001; + $thisObject['flags']['seekable'] = (bool) $thisObject['flags_raw'] & 0x00000002; + $thisObject['flags']['no_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000004; + $thisObject['flags']['resend_live_cleanpoints'] = (bool) $thisObject['flags_raw'] & 0x00000008; + + $thisObject['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $thisObject['stream_language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $thisObject['average_time_per_frame'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $thisObject['stream_name_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $thisObject['payload_extension_system_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['stream_name_count']; $i++) { + $streamName = array(); + + $streamName['language_id_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $streamName['stream_name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $streamName['stream_name'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $streamName['stream_name_length'])); + $offset += $streamName['stream_name_length']; + + $thisObject['stream_names'][$i] = $streamName; + } + + for ($i = 0; $i < $thisObject['payload_extension_system_count']; $i++) { + $payloadExtensionSystem = array(); + + $payloadExtensionSystem['extension_system_id'] = substr($asf_header_extension_object_data, $offset, 16); + $offset += 16; + $payloadExtensionSystem['extension_system_id_text'] = $this->BytestringToGUID($payloadExtensionSystem['extension_system_id']); + + $payloadExtensionSystem['extension_system_size'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + if ($payloadExtensionSystem['extension_system_size'] <= 0) { + break 2; + } + + $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $payloadExtensionSystem['extension_system_info_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, $payloadExtensionSystem['extension_system_info_length'])); + $offset += $payloadExtensionSystem['extension_system_info_length']; + + $thisObject['payload_extension_systems'][$i] = $payloadExtensionSystem; + } + + break; + + case GETID3_ASF_Padding_Object: + // padding, skip it + break; + + case GETID3_ASF_Metadata_Object: + $thisObject['description_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['description_record_counts']; $i++) { + $descriptionRecord = array(); + + $descriptionRecord['reserved_1'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); // must be zero + $offset += 2; + + $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); + + $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); + $offset += $descriptionRecord['name_length']; + + $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); + $offset += $descriptionRecord['data_length']; + switch ($descriptionRecord['data_type']) { + case 0x0000: // Unicode string + break; + + case 0x0001: // BYTE array + // do nothing + break; + + case 0x0002: // BOOL + $descriptionRecord['data'] = (bool) getid3_lib::LittleEndian2Int($descriptionRecord['data']); + break; + + case 0x0003: // DWORD + case 0x0004: // QWORD + case 0x0005: // WORD + $descriptionRecord['data'] = getid3_lib::LittleEndian2Int($descriptionRecord['data']); + break; + + case 0x0006: // GUID + $descriptionRecord['data_text'] = $this->BytestringToGUID($descriptionRecord['data']); + break; + } + + $thisObject['description_record'][$i] = $descriptionRecord; + } + break; + + case GETID3_ASF_Language_List_Object: + $thisObject['language_id_record_counts'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['language_id_record_counts']; $i++) { + $languageIDrecord = array(); + + $languageIDrecord['language_id_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 1)); + $offset += 1; + + $languageIDrecord['language_id'] = substr($asf_header_extension_object_data, $offset, $languageIDrecord['language_id_length']); + $offset += $languageIDrecord['language_id_length']; + + $thisObject['language_id_record'][$i] = $languageIDrecord; + } + break; + + case GETID3_ASF_Metadata_Library_Object: + $thisObject['description_records_count'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisObject['description_records_count']; $i++) { + $descriptionRecord = array(); + + $descriptionRecord['language_list_index'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $descriptionRecord['stream_number'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $descriptionRecord['name_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + + $descriptionRecord['data_type'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 2)); + $offset += 2; + $descriptionRecord['data_type_text'] = $this->ASFmetadataLibraryObjectDataTypeLookup($descriptionRecord['data_type']); + + $descriptionRecord['data_length'] = getid3_lib::LittleEndian2Int(substr($asf_header_extension_object_data, $offset, 4)); + $offset += 4; + + $descriptionRecord['name'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['name_length']); + $offset += $descriptionRecord['name_length']; + + $descriptionRecord['data'] = substr($asf_header_extension_object_data, $offset, $descriptionRecord['data_length']); + $offset += $descriptionRecord['data_length']; + + if (preg_match('#^WM/Picture$#', str_replace("\x00", '', trim($descriptionRecord['name'])))) { + $WMpicture = $this->ASF_WMpicture($descriptionRecord['data']); + foreach ($WMpicture as $key => $value) { + $descriptionRecord['data'] = $WMpicture; + } + unset($WMpicture); + } + + $thisObject['description_record'][$i] = $descriptionRecord; + } + break; + + default: + $unhandled_sections++; + if ($this->GUIDname($thisObject['guid_text'])) { + $this->getid3->info['warning'][] = 'unhandled Header Extension Object GUID "'.$this->GUIDname($thisObject['guid_text']).'" {'.$thisObject['guid_text'].'} at offset '.($offset - 16 - 8); + } else { + $this->getid3->info['warning'][] = 'unknown Header Extension Object GUID {'.$thisObject['guid_text'].'} in at offset '.($offset - 16 - 8); + } + break; + } + $HeaderExtensionObjectParsed[] = $thisObject; + + $objectOffset += $thisObject['size']; + } + return $HeaderExtensionObjectParsed; + } + + + public static function ASFmetadataLibraryObjectDataTypeLookup($id) { + static $ASFmetadataLibraryObjectDataTypeLookup = array( + 0x0000 => 'Unicode string', // The data consists of a sequence of Unicode characters + 0x0001 => 'BYTE array', // The type of the data is implementation-specific + 0x0002 => 'BOOL', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer. Only 0x0000 or 0x0001 are permitted values + 0x0003 => 'DWORD', // The data is 4 bytes long and should be interpreted as a 32-bit unsigned integer + 0x0004 => 'QWORD', // The data is 8 bytes long and should be interpreted as a 64-bit unsigned integer + 0x0005 => 'WORD', // The data is 2 bytes long and should be interpreted as a 16-bit unsigned integer + 0x0006 => 'GUID', // The data is 16 bytes long and should be interpreted as a 128-bit GUID + ); + return (isset($ASFmetadataLibraryObjectDataTypeLookup[$id]) ? $ASFmetadataLibraryObjectDataTypeLookup[$id] : 'invalid'); + } + + public function ASF_WMpicture(&$data) { + //typedef struct _WMPicture{ + // LPWSTR pwszMIMEType; + // BYTE bPictureType; + // LPWSTR pwszDescription; + // DWORD dwDataLen; + // BYTE* pbData; + //} WM_PICTURE; + + $WMpicture = array(); + + $offset = 0; + $WMpicture['image_type_id'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 1)); + $offset += 1; + $WMpicture['image_type'] = $this->WMpictureTypeLookup($WMpicture['image_type_id']); + $WMpicture['image_size'] = getid3_lib::LittleEndian2Int(substr($data, $offset, 4)); + $offset += 4; + + $WMpicture['image_mime'] = ''; + do { + $next_byte_pair = substr($data, $offset, 2); + $offset += 2; + $WMpicture['image_mime'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $WMpicture['image_description'] = ''; + do { + $next_byte_pair = substr($data, $offset, 2); + $offset += 2; + $WMpicture['image_description'] .= $next_byte_pair; + } while ($next_byte_pair !== "\x00\x00"); + + $WMpicture['dataoffset'] = $offset; + $WMpicture['data'] = substr($data, $offset); + + $imageinfo = array(); + $WMpicture['image_mime'] = ''; + $imagechunkcheck = getid3_lib::GetDataImageSize($WMpicture['data'], $imageinfo); + unset($imageinfo); + if (!empty($imagechunkcheck)) { + $WMpicture['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); + } + if (!isset($this->getid3->info['asf']['comments']['picture'])) { + $this->getid3->info['asf']['comments']['picture'] = array(); + } + $this->getid3->info['asf']['comments']['picture'][] = array('data'=>$WMpicture['data'], 'image_mime'=>$WMpicture['image_mime']); + + return $WMpicture; + } + + + // Remove terminator 00 00 and convert UTF-16LE to Latin-1 + public static function TrimConvert($string) { + return trim(getid3_lib::iconv_fallback('UTF-16LE', 'ISO-8859-1', self::TrimTerm($string)), ' '); + } + + + // Remove terminator 00 00 + public static function TrimTerm($string) { + // remove terminator, only if present (it should be, but...) + if (substr($string, -2) === "\x00\x00") { + $string = substr($string, 0, -2); + } + return $string; + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.bink.php b/app/libs/vendor/getid3/module.audio-video.bink.php index 6d40b807..19262766 100644 --- a/app/libs/vendor/getid3/module.audio-video.bink.php +++ b/app/libs/vendor/getid3/module.audio-video.bink.php @@ -1,71 +1,71 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.bink.php // -// module for analyzing Bink or Smacker audio-video files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_bink extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - -$info['error'][] = 'Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']'; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $fileTypeID = fread($this->getid3->fp, 3); - switch ($fileTypeID) { - case 'BIK': - return $this->ParseBink(); - break; - - case 'SMK': - return $this->ParseSmacker(); - break; - - default: - $info['error'][] = 'Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"'; - return false; - break; - } - - return true; - - } - - public function ParseBink() { - $info = &$this->getid3->info; - $info['fileformat'] = 'bink'; - $info['video']['dataformat'] = 'bink'; - - $fileData = 'BIK'.fread($this->getid3->fp, 13); - - $info['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4)); - $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2)); - - if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) { - $info['error'][] = 'Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']); - } - - return true; - } - - public function ParseSmacker() { - $info = &$this->getid3->info; - $info['fileformat'] = 'smacker'; - $info['video']['dataformat'] = 'smacker'; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.bink.php // +// module for analyzing Bink or Smacker audio-video files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_bink extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + +$info['error'][] = 'Bink / Smacker files not properly processed by this version of getID3() ['.$this->getid3->version().']'; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $fileTypeID = fread($this->getid3->fp, 3); + switch ($fileTypeID) { + case 'BIK': + return $this->ParseBink(); + break; + + case 'SMK': + return $this->ParseSmacker(); + break; + + default: + $info['error'][] = 'Expecting "BIK" or "SMK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($fileTypeID).'"'; + return false; + break; + } + + return true; + + } + + public function ParseBink() { + $info = &$this->getid3->info; + $info['fileformat'] = 'bink'; + $info['video']['dataformat'] = 'bink'; + + $fileData = 'BIK'.fread($this->getid3->fp, 13); + + $info['bink']['data_size'] = getid3_lib::LittleEndian2Int(substr($fileData, 4, 4)); + $info['bink']['frame_count'] = getid3_lib::LittleEndian2Int(substr($fileData, 8, 2)); + + if (($info['avdataend'] - $info['avdataoffset']) != ($info['bink']['data_size'] + 8)) { + $info['error'][] = 'Probably truncated file: expecting '.$info['bink']['data_size'].' bytes, found '.($info['avdataend'] - $info['avdataoffset']); + } + + return true; + } + + public function ParseSmacker() { + $info = &$this->getid3->info; + $info['fileformat'] = 'smacker'; + $info['video']['dataformat'] = 'smacker'; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.flv.php b/app/libs/vendor/getid3/module.audio-video.flv.php index e70f51b2..f9c4cf3e 100644 --- a/app/libs/vendor/getid3/module.audio-video.flv.php +++ b/app/libs/vendor/getid3/module.audio-video.flv.php @@ -1,729 +1,729 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -// // -// FLV module by Seth Kaufman // -// // -// * version 0.1 (26 June 2005) // -// // -// // -// * version 0.1.1 (15 July 2005) // -// minor modifications by James Heinrich // -// // -// * version 0.2 (22 February 2006) // -// Support for On2 VP6 codec and meta information // -// by Steve Webster // -// // -// * version 0.3 (15 June 2006) // -// Modified to not read entire file into memory // -// by James Heinrich // -// // -// * version 0.4 (07 December 2007) // -// Bugfixes for incorrectly parsed FLV dimensions // -// and incorrect parsing of onMetaTag // -// by Evgeny Moysevich // -// // -// * version 0.5 (21 May 2009) // -// Fixed parsing of audio tags and added additional codec // -// details. The duration is now read from onMetaTag (if // -// exists), rather than parsing whole file // -// by Nigel Barnes // -// // -// * version 0.6 (24 May 2009) // -// Better parsing of files with h264 video // -// by Evgeny Moysevich // -// // -// * version 0.6.1 (30 May 2011) // -// prevent infinite loops in expGolombUe() // -// // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.flv.php // -// module for analyzing Shockwave Flash Video files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - -define('GETID3_FLV_TAG_AUDIO', 8); -define('GETID3_FLV_TAG_VIDEO', 9); -define('GETID3_FLV_TAG_META', 18); - -define('GETID3_FLV_VIDEO_H263', 2); -define('GETID3_FLV_VIDEO_SCREEN', 3); -define('GETID3_FLV_VIDEO_VP6FLV', 4); -define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5); -define('GETID3_FLV_VIDEO_SCREENV2', 6); -define('GETID3_FLV_VIDEO_H264', 7); - -define('H264_AVC_SEQUENCE_HEADER', 0); -define('H264_PROFILE_BASELINE', 66); -define('H264_PROFILE_MAIN', 77); -define('H264_PROFILE_EXTENDED', 88); -define('H264_PROFILE_HIGH', 100); -define('H264_PROFILE_HIGH10', 110); -define('H264_PROFILE_HIGH422', 122); -define('H264_PROFILE_HIGH444', 144); -define('H264_PROFILE_HIGH444_PREDICTIVE', 244); - -class getid3_flv extends getid3_handler -{ - public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $FLVdataLength = $info['avdataend'] - $info['avdataoffset']; - $FLVheader = fread($this->getid3->fp, 5); - - $info['fileformat'] = 'flv'; - $info['flv']['header']['signature'] = substr($FLVheader, 0, 3); - $info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1)); - $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1)); - - $magic = 'FLV'; - if ($info['flv']['header']['signature'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"'; - unset($info['flv']); - unset($info['fileformat']); - return false; - } - - $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04); - $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01); - - $FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4)); - $FLVheaderFrameLength = 9; - if ($FrameSizeDataLength > $FLVheaderFrameLength) { - fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR); - } - $Duration = 0; - $found_video = false; - $found_audio = false; - $found_meta = false; - $found_valid_meta_playtime = false; - $tagParseCount = 0; - $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0); - $flv_framecount = &$info['flv']['framecount']; - while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) { - $ThisTagHeader = fread($this->getid3->fp, 16); - - $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4)); - $TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1)); - $DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3)); - $Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3)); - $LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1)); - $NextOffset = ftell($this->getid3->fp) - 1 + $DataLength; - if ($Timestamp > $Duration) { - $Duration = $Timestamp; - } - - $flv_framecount['total']++; - switch ($TagType) { - case GETID3_FLV_TAG_AUDIO: - $flv_framecount['audio']++; - if (!$found_audio) { - $found_audio = true; - $info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F; - $info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03; - $info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01; - $info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01; - } - break; - - case GETID3_FLV_TAG_VIDEO: - $flv_framecount['video']++; - if (!$found_video) { - $found_video = true; - $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07; - - $FLVvideoHeader = fread($this->getid3->fp, 11); - - if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) { - // this code block contributed by: moysevichØgmail*com - - $AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1)); - if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) { - // read AVCDecoderConfigurationRecord - $configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1)); - $AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1)); - $profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1)); - $lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1)); - $numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1)); - - if (($numOfSequenceParameterSets & 0x1F) != 0) { - // there is at least one SequenceParameterSet - // read size of the first SequenceParameterSet - //$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2)); - $spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2)); - // read the first SequenceParameterSet - $sps = fread($this->getid3->fp, $spsSize); - if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red - $spsReader = new AVCSequenceParameterSetReader($sps); - $spsReader->readData(); - $info['video']['resolution_x'] = $spsReader->getWidth(); - $info['video']['resolution_y'] = $spsReader->getHeight(); - } - } - } - // end: moysevichØgmail*com - - } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) { - - $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7; - $PictureSizeType = $PictureSizeType & 0x0007; - $info['flv']['header']['videoSizeType'] = $PictureSizeType; - switch ($PictureSizeType) { - case 0: - //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)); - //$PictureSizeEnc <<= 1; - //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8; - //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2)); - //$PictureSizeEnc <<= 1; - //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8; - - $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2)); - $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)); - $PictureSizeEnc['x'] >>= 7; - $PictureSizeEnc['y'] >>= 7; - $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF; - $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF; - break; - - case 1: - $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3)); - $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3)); - $PictureSizeEnc['x'] >>= 7; - $PictureSizeEnc['y'] >>= 7; - $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF; - $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF; - break; - - case 2: - $info['video']['resolution_x'] = 352; - $info['video']['resolution_y'] = 288; - break; - - case 3: - $info['video']['resolution_x'] = 176; - $info['video']['resolution_y'] = 144; - break; - - case 4: - $info['video']['resolution_x'] = 128; - $info['video']['resolution_y'] = 96; - break; - - case 5: - $info['video']['resolution_x'] = 320; - $info['video']['resolution_y'] = 240; - break; - - case 6: - $info['video']['resolution_x'] = 160; - $info['video']['resolution_y'] = 120; - break; - - default: - $info['video']['resolution_x'] = 0; - $info['video']['resolution_y'] = 0; - break; - - } - } - $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y']; - } - break; - - // Meta tag - case GETID3_FLV_TAG_META: - if (!$found_meta) { - $found_meta = true; - fseek($this->getid3->fp, -1, SEEK_CUR); - $datachunk = fread($this->getid3->fp, $DataLength); - $AMFstream = new AMFStream($datachunk); - $reader = new AMFReader($AMFstream); - $eventName = $reader->readData(); - $info['flv']['meta'][$eventName] = $reader->readData(); - unset($reader); - - $copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate'); - foreach ($copykeys as $sourcekey => $destkey) { - if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) { - switch ($sourcekey) { - case 'width': - case 'height': - $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey])); - break; - case 'audiodatarate': - $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000)); - break; - case 'videodatarate': - case 'frame_rate': - default: - $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey]; - break; - } - } - } - if (!empty($info['flv']['meta']['onMetaData']['duration'])) { - $found_valid_meta_playtime = true; - } - } - break; - - default: - // noop - break; - } - fseek($this->getid3->fp, $NextOffset, SEEK_SET); - } - - $info['playtime_seconds'] = $Duration / 1000; - if ($info['playtime_seconds'] > 0) { - $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - - if ($info['flv']['header']['hasAudio']) { - $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']); - $info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']); - $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']); - - $info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo - $info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed - $info['audio']['dataformat'] = 'flv'; - } - if (!empty($info['flv']['header']['hasVideo'])) { - $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']); - $info['video']['dataformat'] = 'flv'; - $info['video']['lossless'] = false; - } - - // Set information from meta - if (!empty($info['flv']['meta']['onMetaData']['duration'])) { - $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration']; - $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) { - $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']); - } - if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) { - $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']); - } - return true; - } - - - public function FLVaudioFormat($id) { - $FLVaudioFormat = array( - 0 => 'Linear PCM, platform endian', - 1 => 'ADPCM', - 2 => 'mp3', - 3 => 'Linear PCM, little endian', - 4 => 'Nellymoser 16kHz mono', - 5 => 'Nellymoser 8kHz mono', - 6 => 'Nellymoser', - 7 => 'G.711A-law logarithmic PCM', - 8 => 'G.711 mu-law logarithmic PCM', - 9 => 'reserved', - 10 => 'AAC', - 11 => false, // unknown? - 12 => false, // unknown? - 13 => false, // unknown? - 14 => 'mp3 8kHz', - 15 => 'Device-specific sound', - ); - return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false); - } - - public function FLVaudioRate($id) { - $FLVaudioRate = array( - 0 => 5500, - 1 => 11025, - 2 => 22050, - 3 => 44100, - ); - return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false); - } - - public function FLVaudioBitDepth($id) { - $FLVaudioBitDepth = array( - 0 => 8, - 1 => 16, - ); - return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false); - } - - public function FLVvideoCodec($id) { - $FLVvideoCodec = array( - GETID3_FLV_VIDEO_H263 => 'Sorenson H.263', - GETID3_FLV_VIDEO_SCREEN => 'Screen video', - GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6', - GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel', - GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2', - GETID3_FLV_VIDEO_H264 => 'Sorenson H.264', - ); - return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false); - } -} - -class AMFStream { - public $bytes; - public $pos; - - public function AMFStream(&$bytes) { - $this->bytes =& $bytes; - $this->pos = 0; - } - - public function readByte() { - return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1)); - } - - public function readInt() { - return ($this->readByte() << 8) + $this->readByte(); - } - - public function readLong() { - return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); - } - - public function readDouble() { - return getid3_lib::BigEndian2Float($this->read(8)); - } - - public function readUTF() { - $length = $this->readInt(); - return $this->read($length); - } - - public function readLongUTF() { - $length = $this->readLong(); - return $this->read($length); - } - - public function read($length) { - $val = substr($this->bytes, $this->pos, $length); - $this->pos += $length; - return $val; - } - - public function peekByte() { - $pos = $this->pos; - $val = $this->readByte(); - $this->pos = $pos; - return $val; - } - - public function peekInt() { - $pos = $this->pos; - $val = $this->readInt(); - $this->pos = $pos; - return $val; - } - - public function peekLong() { - $pos = $this->pos; - $val = $this->readLong(); - $this->pos = $pos; - return $val; - } - - public function peekDouble() { - $pos = $this->pos; - $val = $this->readDouble(); - $this->pos = $pos; - return $val; - } - - public function peekUTF() { - $pos = $this->pos; - $val = $this->readUTF(); - $this->pos = $pos; - return $val; - } - - public function peekLongUTF() { - $pos = $this->pos; - $val = $this->readLongUTF(); - $this->pos = $pos; - return $val; - } -} - -class AMFReader { - public $stream; - - public function AMFReader(&$stream) { - $this->stream =& $stream; - } - - public function readData() { - $value = null; - - $type = $this->stream->readByte(); - switch ($type) { - - // Double - case 0: - $value = $this->readDouble(); - break; - - // Boolean - case 1: - $value = $this->readBoolean(); - break; - - // String - case 2: - $value = $this->readString(); - break; - - // Object - case 3: - $value = $this->readObject(); - break; - - // null - case 6: - return null; - break; - - // Mixed array - case 8: - $value = $this->readMixedArray(); - break; - - // Array - case 10: - $value = $this->readArray(); - break; - - // Date - case 11: - $value = $this->readDate(); - break; - - // Long string - case 13: - $value = $this->readLongString(); - break; - - // XML (handled as string) - case 15: - $value = $this->readXML(); - break; - - // Typed object (handled as object) - case 16: - $value = $this->readTypedObject(); - break; - - // Long string - default: - $value = '(unknown or unsupported data type)'; - break; - } - - return $value; - } - - public function readDouble() { - return $this->stream->readDouble(); - } - - public function readBoolean() { - return $this->stream->readByte() == 1; - } - - public function readString() { - return $this->stream->readUTF(); - } - - public function readObject() { - // Get highest numerical index - ignored -// $highestIndex = $this->stream->readLong(); - - $data = array(); - - while ($key = $this->stream->readUTF()) { - $data[$key] = $this->readData(); - } - // Mixed array record ends with empty string (0x00 0x00) and 0x09 - if (($key == '') && ($this->stream->peekByte() == 0x09)) { - // Consume byte - $this->stream->readByte(); - } - return $data; - } - - public function readMixedArray() { - // Get highest numerical index - ignored - $highestIndex = $this->stream->readLong(); - - $data = array(); - - while ($key = $this->stream->readUTF()) { - if (is_numeric($key)) { - $key = (float) $key; - } - $data[$key] = $this->readData(); - } - // Mixed array record ends with empty string (0x00 0x00) and 0x09 - if (($key == '') && ($this->stream->peekByte() == 0x09)) { - // Consume byte - $this->stream->readByte(); - } - - return $data; - } - - public function readArray() { - $length = $this->stream->readLong(); - $data = array(); - - for ($i = 0; $i < $length; $i++) { - $data[] = $this->readData(); - } - return $data; - } - - public function readDate() { - $timestamp = $this->stream->readDouble(); - $timezone = $this->stream->readInt(); - return $timestamp; - } - - public function readLongString() { - return $this->stream->readLongUTF(); - } - - public function readXML() { - return $this->stream->readLongUTF(); - } - - public function readTypedObject() { - $className = $this->stream->readUTF(); - return $this->readObject(); - } -} - -class AVCSequenceParameterSetReader { - public $sps; - public $start = 0; - public $currentBytes = 0; - public $currentBits = 0; - public $width; - public $height; - - public function AVCSequenceParameterSetReader($sps) { - $this->sps = $sps; - } - - public function readData() { - $this->skipBits(8); - $this->skipBits(8); - $profile = $this->getBits(8); // read profile - $this->skipBits(16); - $this->expGolombUe(); // read sps id - if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) { - if ($this->expGolombUe() == 3) { - $this->skipBits(1); - } - $this->expGolombUe(); - $this->expGolombUe(); - $this->skipBits(1); - if ($this->getBit()) { - for ($i = 0; $i < 8; $i++) { - if ($this->getBit()) { - $size = $i < 6 ? 16 : 64; - $lastScale = 8; - $nextScale = 8; - for ($j = 0; $j < $size; $j++) { - if ($nextScale != 0) { - $deltaScale = $this->expGolombUe(); - $nextScale = ($lastScale + $deltaScale + 256) % 256; - } - if ($nextScale != 0) { - $lastScale = $nextScale; - } - } - } - } - } - } - $this->expGolombUe(); - $pocType = $this->expGolombUe(); - if ($pocType == 0) { - $this->expGolombUe(); - } elseif ($pocType == 1) { - $this->skipBits(1); - $this->expGolombSe(); - $this->expGolombSe(); - $pocCycleLength = $this->expGolombUe(); - for ($i = 0; $i < $pocCycleLength; $i++) { - $this->expGolombSe(); - } - } - $this->expGolombUe(); - $this->skipBits(1); - $this->width = ($this->expGolombUe() + 1) * 16; - $heightMap = $this->expGolombUe() + 1; - $this->height = (2 - $this->getBit()) * $heightMap * 16; - } - - public function skipBits($bits) { - $newBits = $this->currentBits + $bits; - $this->currentBytes += (int)floor($newBits / 8); - $this->currentBits = $newBits % 8; - } - - public function getBit() { - $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01; - $this->skipBits(1); - return $result; - } - - public function getBits($bits) { - $result = 0; - for ($i = 0; $i < $bits; $i++) { - $result = ($result << 1) + $this->getBit(); - } - return $result; - } - - public function expGolombUe() { - $significantBits = 0; - $bit = $this->getBit(); - while ($bit == 0) { - $significantBits++; - $bit = $this->getBit(); - - if ($significantBits > 31) { - // something is broken, this is an emergency escape to prevent infinite loops - return 0; - } - } - return (1 << $significantBits) + $this->getBits($significantBits) - 1; - } - - public function expGolombSe() { - $result = $this->expGolombUe(); - if (($result & 0x01) == 0) { - return -($result >> 1); - } else { - return ($result + 1) >> 1; - } - } - - public function getWidth() { - return $this->width; - } - - public function getHeight() { - return $this->height; - } -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +// // +// FLV module by Seth Kaufman // +// // +// * version 0.1 (26 June 2005) // +// // +// // +// * version 0.1.1 (15 July 2005) // +// minor modifications by James Heinrich // +// // +// * version 0.2 (22 February 2006) // +// Support for On2 VP6 codec and meta information // +// by Steve Webster // +// // +// * version 0.3 (15 June 2006) // +// Modified to not read entire file into memory // +// by James Heinrich // +// // +// * version 0.4 (07 December 2007) // +// Bugfixes for incorrectly parsed FLV dimensions // +// and incorrect parsing of onMetaTag // +// by Evgeny Moysevich // +// // +// * version 0.5 (21 May 2009) // +// Fixed parsing of audio tags and added additional codec // +// details. The duration is now read from onMetaTag (if // +// exists), rather than parsing whole file // +// by Nigel Barnes // +// // +// * version 0.6 (24 May 2009) // +// Better parsing of files with h264 video // +// by Evgeny Moysevich // +// // +// * version 0.6.1 (30 May 2011) // +// prevent infinite loops in expGolombUe() // +// // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.flv.php // +// module for analyzing Shockwave Flash Video files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +define('GETID3_FLV_TAG_AUDIO', 8); +define('GETID3_FLV_TAG_VIDEO', 9); +define('GETID3_FLV_TAG_META', 18); + +define('GETID3_FLV_VIDEO_H263', 2); +define('GETID3_FLV_VIDEO_SCREEN', 3); +define('GETID3_FLV_VIDEO_VP6FLV', 4); +define('GETID3_FLV_VIDEO_VP6FLV_ALPHA', 5); +define('GETID3_FLV_VIDEO_SCREENV2', 6); +define('GETID3_FLV_VIDEO_H264', 7); + +define('H264_AVC_SEQUENCE_HEADER', 0); +define('H264_PROFILE_BASELINE', 66); +define('H264_PROFILE_MAIN', 77); +define('H264_PROFILE_EXTENDED', 88); +define('H264_PROFILE_HIGH', 100); +define('H264_PROFILE_HIGH10', 110); +define('H264_PROFILE_HIGH422', 122); +define('H264_PROFILE_HIGH444', 144); +define('H264_PROFILE_HIGH444_PREDICTIVE', 244); + +class getid3_flv extends getid3_handler +{ + public $max_frames = 100000; // break out of the loop if too many frames have been scanned; only scan this many if meta frame does not contain useful duration + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $FLVdataLength = $info['avdataend'] - $info['avdataoffset']; + $FLVheader = fread($this->getid3->fp, 5); + + $info['fileformat'] = 'flv'; + $info['flv']['header']['signature'] = substr($FLVheader, 0, 3); + $info['flv']['header']['version'] = getid3_lib::BigEndian2Int(substr($FLVheader, 3, 1)); + $TypeFlags = getid3_lib::BigEndian2Int(substr($FLVheader, 4, 1)); + + $magic = 'FLV'; + if ($info['flv']['header']['signature'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['flv']['header']['signature']).'"'; + unset($info['flv']); + unset($info['fileformat']); + return false; + } + + $info['flv']['header']['hasAudio'] = (bool) ($TypeFlags & 0x04); + $info['flv']['header']['hasVideo'] = (bool) ($TypeFlags & 0x01); + + $FrameSizeDataLength = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 4)); + $FLVheaderFrameLength = 9; + if ($FrameSizeDataLength > $FLVheaderFrameLength) { + fseek($this->getid3->fp, $FrameSizeDataLength - $FLVheaderFrameLength, SEEK_CUR); + } + $Duration = 0; + $found_video = false; + $found_audio = false; + $found_meta = false; + $found_valid_meta_playtime = false; + $tagParseCount = 0; + $info['flv']['framecount'] = array('total'=>0, 'audio'=>0, 'video'=>0); + $flv_framecount = &$info['flv']['framecount']; + while (((ftell($this->getid3->fp) + 16) < $info['avdataend']) && (($tagParseCount++ <= $this->max_frames) || !$found_valid_meta_playtime)) { + $ThisTagHeader = fread($this->getid3->fp, 16); + + $PreviousTagLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 0, 4)); + $TagType = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 4, 1)); + $DataLength = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 5, 3)); + $Timestamp = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 8, 3)); + $LastHeaderByte = getid3_lib::BigEndian2Int(substr($ThisTagHeader, 15, 1)); + $NextOffset = ftell($this->getid3->fp) - 1 + $DataLength; + if ($Timestamp > $Duration) { + $Duration = $Timestamp; + } + + $flv_framecount['total']++; + switch ($TagType) { + case GETID3_FLV_TAG_AUDIO: + $flv_framecount['audio']++; + if (!$found_audio) { + $found_audio = true; + $info['flv']['audio']['audioFormat'] = ($LastHeaderByte >> 4) & 0x0F; + $info['flv']['audio']['audioRate'] = ($LastHeaderByte >> 2) & 0x03; + $info['flv']['audio']['audioSampleSize'] = ($LastHeaderByte >> 1) & 0x01; + $info['flv']['audio']['audioType'] = $LastHeaderByte & 0x01; + } + break; + + case GETID3_FLV_TAG_VIDEO: + $flv_framecount['video']++; + if (!$found_video) { + $found_video = true; + $info['flv']['video']['videoCodec'] = $LastHeaderByte & 0x07; + + $FLVvideoHeader = fread($this->getid3->fp, 11); + + if ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H264) { + // this code block contributed by: moysevichØgmail*com + + $AVCPacketType = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 0, 1)); + if ($AVCPacketType == H264_AVC_SEQUENCE_HEADER) { + // read AVCDecoderConfigurationRecord + $configurationVersion = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 1)); + $AVCProfileIndication = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 1)); + $profile_compatibility = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 1)); + $lengthSizeMinusOne = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 7, 1)); + $numOfSequenceParameterSets = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 8, 1)); + + if (($numOfSequenceParameterSets & 0x1F) != 0) { + // there is at least one SequenceParameterSet + // read size of the first SequenceParameterSet + //$spsSize = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 9, 2)); + $spsSize = getid3_lib::LittleEndian2Int(substr($FLVvideoHeader, 9, 2)); + // read the first SequenceParameterSet + $sps = fread($this->getid3->fp, $spsSize); + if (strlen($sps) == $spsSize) { // make sure that whole SequenceParameterSet was red + $spsReader = new AVCSequenceParameterSetReader($sps); + $spsReader->readData(); + $info['video']['resolution_x'] = $spsReader->getWidth(); + $info['video']['resolution_y'] = $spsReader->getHeight(); + } + } + } + // end: moysevichØgmail*com + + } elseif ($info['flv']['video']['videoCodec'] == GETID3_FLV_VIDEO_H263) { + + $PictureSizeType = (getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 3, 2))) >> 7; + $PictureSizeType = $PictureSizeType & 0x0007; + $info['flv']['header']['videoSizeType'] = $PictureSizeType; + switch ($PictureSizeType) { + case 0: + //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)); + //$PictureSizeEnc <<= 1; + //$info['video']['resolution_x'] = ($PictureSizeEnc & 0xFF00) >> 8; + //$PictureSizeEnc = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 2)); + //$PictureSizeEnc <<= 1; + //$info['video']['resolution_y'] = ($PictureSizeEnc & 0xFF00) >> 8; + + $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 2)); + $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 5, 2)); + $PictureSizeEnc['x'] >>= 7; + $PictureSizeEnc['y'] >>= 7; + $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFF; + $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFF; + break; + + case 1: + $PictureSizeEnc['x'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 4, 3)); + $PictureSizeEnc['y'] = getid3_lib::BigEndian2Int(substr($FLVvideoHeader, 6, 3)); + $PictureSizeEnc['x'] >>= 7; + $PictureSizeEnc['y'] >>= 7; + $info['video']['resolution_x'] = $PictureSizeEnc['x'] & 0xFFFF; + $info['video']['resolution_y'] = $PictureSizeEnc['y'] & 0xFFFF; + break; + + case 2: + $info['video']['resolution_x'] = 352; + $info['video']['resolution_y'] = 288; + break; + + case 3: + $info['video']['resolution_x'] = 176; + $info['video']['resolution_y'] = 144; + break; + + case 4: + $info['video']['resolution_x'] = 128; + $info['video']['resolution_y'] = 96; + break; + + case 5: + $info['video']['resolution_x'] = 320; + $info['video']['resolution_y'] = 240; + break; + + case 6: + $info['video']['resolution_x'] = 160; + $info['video']['resolution_y'] = 120; + break; + + default: + $info['video']['resolution_x'] = 0; + $info['video']['resolution_y'] = 0; + break; + + } + } + $info['video']['pixel_aspect_ratio'] = $info['video']['resolution_x'] / $info['video']['resolution_y']; + } + break; + + // Meta tag + case GETID3_FLV_TAG_META: + if (!$found_meta) { + $found_meta = true; + fseek($this->getid3->fp, -1, SEEK_CUR); + $datachunk = fread($this->getid3->fp, $DataLength); + $AMFstream = new AMFStream($datachunk); + $reader = new AMFReader($AMFstream); + $eventName = $reader->readData(); + $info['flv']['meta'][$eventName] = $reader->readData(); + unset($reader); + + $copykeys = array('framerate'=>'frame_rate', 'width'=>'resolution_x', 'height'=>'resolution_y', 'audiodatarate'=>'bitrate', 'videodatarate'=>'bitrate'); + foreach ($copykeys as $sourcekey => $destkey) { + if (isset($info['flv']['meta']['onMetaData'][$sourcekey])) { + switch ($sourcekey) { + case 'width': + case 'height': + $info['video'][$destkey] = intval(round($info['flv']['meta']['onMetaData'][$sourcekey])); + break; + case 'audiodatarate': + $info['audio'][$destkey] = getid3_lib::CastAsInt(round($info['flv']['meta']['onMetaData'][$sourcekey] * 1000)); + break; + case 'videodatarate': + case 'frame_rate': + default: + $info['video'][$destkey] = $info['flv']['meta']['onMetaData'][$sourcekey]; + break; + } + } + } + if (!empty($info['flv']['meta']['onMetaData']['duration'])) { + $found_valid_meta_playtime = true; + } + } + break; + + default: + // noop + break; + } + fseek($this->getid3->fp, $NextOffset, SEEK_SET); + } + + $info['playtime_seconds'] = $Duration / 1000; + if ($info['playtime_seconds'] > 0) { + $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + + if ($info['flv']['header']['hasAudio']) { + $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['audio']['audioFormat']); + $info['audio']['sample_rate'] = $this->FLVaudioRate($info['flv']['audio']['audioRate']); + $info['audio']['bits_per_sample'] = $this->FLVaudioBitDepth($info['flv']['audio']['audioSampleSize']); + + $info['audio']['channels'] = $info['flv']['audio']['audioType'] + 1; // 0=mono,1=stereo + $info['audio']['lossless'] = ($info['flv']['audio']['audioFormat'] ? false : true); // 0=uncompressed + $info['audio']['dataformat'] = 'flv'; + } + if (!empty($info['flv']['header']['hasVideo'])) { + $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['video']['videoCodec']); + $info['video']['dataformat'] = 'flv'; + $info['video']['lossless'] = false; + } + + // Set information from meta + if (!empty($info['flv']['meta']['onMetaData']['duration'])) { + $info['playtime_seconds'] = $info['flv']['meta']['onMetaData']['duration']; + $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + if (isset($info['flv']['meta']['onMetaData']['audiocodecid'])) { + $info['audio']['codec'] = $this->FLVaudioFormat($info['flv']['meta']['onMetaData']['audiocodecid']); + } + if (isset($info['flv']['meta']['onMetaData']['videocodecid'])) { + $info['video']['codec'] = $this->FLVvideoCodec($info['flv']['meta']['onMetaData']['videocodecid']); + } + return true; + } + + + public function FLVaudioFormat($id) { + $FLVaudioFormat = array( + 0 => 'Linear PCM, platform endian', + 1 => 'ADPCM', + 2 => 'mp3', + 3 => 'Linear PCM, little endian', + 4 => 'Nellymoser 16kHz mono', + 5 => 'Nellymoser 8kHz mono', + 6 => 'Nellymoser', + 7 => 'G.711A-law logarithmic PCM', + 8 => 'G.711 mu-law logarithmic PCM', + 9 => 'reserved', + 10 => 'AAC', + 11 => false, // unknown? + 12 => false, // unknown? + 13 => false, // unknown? + 14 => 'mp3 8kHz', + 15 => 'Device-specific sound', + ); + return (isset($FLVaudioFormat[$id]) ? $FLVaudioFormat[$id] : false); + } + + public function FLVaudioRate($id) { + $FLVaudioRate = array( + 0 => 5500, + 1 => 11025, + 2 => 22050, + 3 => 44100, + ); + return (isset($FLVaudioRate[$id]) ? $FLVaudioRate[$id] : false); + } + + public function FLVaudioBitDepth($id) { + $FLVaudioBitDepth = array( + 0 => 8, + 1 => 16, + ); + return (isset($FLVaudioBitDepth[$id]) ? $FLVaudioBitDepth[$id] : false); + } + + public function FLVvideoCodec($id) { + $FLVvideoCodec = array( + GETID3_FLV_VIDEO_H263 => 'Sorenson H.263', + GETID3_FLV_VIDEO_SCREEN => 'Screen video', + GETID3_FLV_VIDEO_VP6FLV => 'On2 VP6', + GETID3_FLV_VIDEO_VP6FLV_ALPHA => 'On2 VP6 with alpha channel', + GETID3_FLV_VIDEO_SCREENV2 => 'Screen video v2', + GETID3_FLV_VIDEO_H264 => 'Sorenson H.264', + ); + return (isset($FLVvideoCodec[$id]) ? $FLVvideoCodec[$id] : false); + } +} + +class AMFStream { + public $bytes; + public $pos; + + public function AMFStream(&$bytes) { + $this->bytes =& $bytes; + $this->pos = 0; + } + + public function readByte() { + return getid3_lib::BigEndian2Int(substr($this->bytes, $this->pos++, 1)); + } + + public function readInt() { + return ($this->readByte() << 8) + $this->readByte(); + } + + public function readLong() { + return ($this->readByte() << 24) + ($this->readByte() << 16) + ($this->readByte() << 8) + $this->readByte(); + } + + public function readDouble() { + return getid3_lib::BigEndian2Float($this->read(8)); + } + + public function readUTF() { + $length = $this->readInt(); + return $this->read($length); + } + + public function readLongUTF() { + $length = $this->readLong(); + return $this->read($length); + } + + public function read($length) { + $val = substr($this->bytes, $this->pos, $length); + $this->pos += $length; + return $val; + } + + public function peekByte() { + $pos = $this->pos; + $val = $this->readByte(); + $this->pos = $pos; + return $val; + } + + public function peekInt() { + $pos = $this->pos; + $val = $this->readInt(); + $this->pos = $pos; + return $val; + } + + public function peekLong() { + $pos = $this->pos; + $val = $this->readLong(); + $this->pos = $pos; + return $val; + } + + public function peekDouble() { + $pos = $this->pos; + $val = $this->readDouble(); + $this->pos = $pos; + return $val; + } + + public function peekUTF() { + $pos = $this->pos; + $val = $this->readUTF(); + $this->pos = $pos; + return $val; + } + + public function peekLongUTF() { + $pos = $this->pos; + $val = $this->readLongUTF(); + $this->pos = $pos; + return $val; + } +} + +class AMFReader { + public $stream; + + public function AMFReader(&$stream) { + $this->stream =& $stream; + } + + public function readData() { + $value = null; + + $type = $this->stream->readByte(); + switch ($type) { + + // Double + case 0: + $value = $this->readDouble(); + break; + + // Boolean + case 1: + $value = $this->readBoolean(); + break; + + // String + case 2: + $value = $this->readString(); + break; + + // Object + case 3: + $value = $this->readObject(); + break; + + // null + case 6: + return null; + break; + + // Mixed array + case 8: + $value = $this->readMixedArray(); + break; + + // Array + case 10: + $value = $this->readArray(); + break; + + // Date + case 11: + $value = $this->readDate(); + break; + + // Long string + case 13: + $value = $this->readLongString(); + break; + + // XML (handled as string) + case 15: + $value = $this->readXML(); + break; + + // Typed object (handled as object) + case 16: + $value = $this->readTypedObject(); + break; + + // Long string + default: + $value = '(unknown or unsupported data type)'; + break; + } + + return $value; + } + + public function readDouble() { + return $this->stream->readDouble(); + } + + public function readBoolean() { + return $this->stream->readByte() == 1; + } + + public function readString() { + return $this->stream->readUTF(); + } + + public function readObject() { + // Get highest numerical index - ignored +// $highestIndex = $this->stream->readLong(); + + $data = array(); + + while ($key = $this->stream->readUTF()) { + $data[$key] = $this->readData(); + } + // Mixed array record ends with empty string (0x00 0x00) and 0x09 + if (($key == '') && ($this->stream->peekByte() == 0x09)) { + // Consume byte + $this->stream->readByte(); + } + return $data; + } + + public function readMixedArray() { + // Get highest numerical index - ignored + $highestIndex = $this->stream->readLong(); + + $data = array(); + + while ($key = $this->stream->readUTF()) { + if (is_numeric($key)) { + $key = (float) $key; + } + $data[$key] = $this->readData(); + } + // Mixed array record ends with empty string (0x00 0x00) and 0x09 + if (($key == '') && ($this->stream->peekByte() == 0x09)) { + // Consume byte + $this->stream->readByte(); + } + + return $data; + } + + public function readArray() { + $length = $this->stream->readLong(); + $data = array(); + + for ($i = 0; $i < $length; $i++) { + $data[] = $this->readData(); + } + return $data; + } + + public function readDate() { + $timestamp = $this->stream->readDouble(); + $timezone = $this->stream->readInt(); + return $timestamp; + } + + public function readLongString() { + return $this->stream->readLongUTF(); + } + + public function readXML() { + return $this->stream->readLongUTF(); + } + + public function readTypedObject() { + $className = $this->stream->readUTF(); + return $this->readObject(); + } +} + +class AVCSequenceParameterSetReader { + public $sps; + public $start = 0; + public $currentBytes = 0; + public $currentBits = 0; + public $width; + public $height; + + public function AVCSequenceParameterSetReader($sps) { + $this->sps = $sps; + } + + public function readData() { + $this->skipBits(8); + $this->skipBits(8); + $profile = $this->getBits(8); // read profile + $this->skipBits(16); + $this->expGolombUe(); // read sps id + if (in_array($profile, array(H264_PROFILE_HIGH, H264_PROFILE_HIGH10, H264_PROFILE_HIGH422, H264_PROFILE_HIGH444, H264_PROFILE_HIGH444_PREDICTIVE))) { + if ($this->expGolombUe() == 3) { + $this->skipBits(1); + } + $this->expGolombUe(); + $this->expGolombUe(); + $this->skipBits(1); + if ($this->getBit()) { + for ($i = 0; $i < 8; $i++) { + if ($this->getBit()) { + $size = $i < 6 ? 16 : 64; + $lastScale = 8; + $nextScale = 8; + for ($j = 0; $j < $size; $j++) { + if ($nextScale != 0) { + $deltaScale = $this->expGolombUe(); + $nextScale = ($lastScale + $deltaScale + 256) % 256; + } + if ($nextScale != 0) { + $lastScale = $nextScale; + } + } + } + } + } + } + $this->expGolombUe(); + $pocType = $this->expGolombUe(); + if ($pocType == 0) { + $this->expGolombUe(); + } elseif ($pocType == 1) { + $this->skipBits(1); + $this->expGolombSe(); + $this->expGolombSe(); + $pocCycleLength = $this->expGolombUe(); + for ($i = 0; $i < $pocCycleLength; $i++) { + $this->expGolombSe(); + } + } + $this->expGolombUe(); + $this->skipBits(1); + $this->width = ($this->expGolombUe() + 1) * 16; + $heightMap = $this->expGolombUe() + 1; + $this->height = (2 - $this->getBit()) * $heightMap * 16; + } + + public function skipBits($bits) { + $newBits = $this->currentBits + $bits; + $this->currentBytes += (int)floor($newBits / 8); + $this->currentBits = $newBits % 8; + } + + public function getBit() { + $result = (getid3_lib::BigEndian2Int(substr($this->sps, $this->currentBytes, 1)) >> (7 - $this->currentBits)) & 0x01; + $this->skipBits(1); + return $result; + } + + public function getBits($bits) { + $result = 0; + for ($i = 0; $i < $bits; $i++) { + $result = ($result << 1) + $this->getBit(); + } + return $result; + } + + public function expGolombUe() { + $significantBits = 0; + $bit = $this->getBit(); + while ($bit == 0) { + $significantBits++; + $bit = $this->getBit(); + + if ($significantBits > 31) { + // something is broken, this is an emergency escape to prevent infinite loops + return 0; + } + } + return (1 << $significantBits) + $this->getBits($significantBits) - 1; + } + + public function expGolombSe() { + $result = $this->expGolombUe(); + if (($result & 0x01) == 0) { + return -($result >> 1); + } else { + return ($result + 1) >> 1; + } + } + + public function getWidth() { + return $this->width; + } + + public function getHeight() { + return $this->height; + } +} diff --git a/app/libs/vendor/getid3/module.audio-video.matroska.php b/app/libs/vendor/getid3/module.audio-video.matroska.php index c2834e06..8fe89a55 100644 --- a/app/libs/vendor/getid3/module.audio-video.matroska.php +++ b/app/libs/vendor/getid3/module.audio-video.matroska.php @@ -1,1765 +1,1765 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.matriska.php // -// module for analyzing Matroska containers // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation. -define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements. -define('EBML_ID_TAGS', 0x0254C367); // [12][54][C3][67] -- Element containing elements specific to Tracks/Chapters. A list of valid tags can be found . -define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file. -define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described. -define('EBML_ID_SEGMENT', 0x08538067); // [18][53][80][67] -- This element contains all other top-level (level 1) elements. Typically a Matroska file is composed of 1 segment. -define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files. -define('EBML_ID_EBML', 0x0A45DFA3); // [1A][45][DF][A3] -- Set the EBML characteristics of the data to follow. Each EBML document has to start with this. -define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment. -define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure. -define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form. -define('EBML_ID_TRACKTIMECODESCALE', 0x03314F); // [23][31][4F] -- The scale to apply on this track to work at normal speed in relation with other tracks (mostly used to adjust video speed when the audio length differs). -define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame. -define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec. -define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used. -define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds). -define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits). -define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value. -define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used. -define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used. -define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment. -define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits). -define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment. -define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits). -define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are: -define('EBML_ID_CONTENTCOMPSETTINGS', 0x0255); // [42][55] -- Settings that might be needed by the decompressor. For Header Stripping (ContentCompAlgo=3), the bytes that were removed from the beggining of each frames of the track. -define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case). -define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file. -define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file. -define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file. -define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska). -define('EBML_ID_EBMLMAXSIZELENGTH', 0x02F3); // [42][F3] -- The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not override the element size indicated at the beginning of an element. Elements that have an indicated size which is larger than what is allowed by EBMLMaxSizeLength shall be considered invalid. -define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file. -define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form. -define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains. -define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits). -define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date. -define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form. -define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag. -define('EBML_ID_TAGBINARY', 0x0485); // [44][85] -- The values of the Tag if it is binary. Note that this cannot be used in the same SimpleTag as TagString. -define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag. -define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale). -define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent. -define('EBML_ID_CHAPTERFLAGENABLED', 0x0598); // [45][98] -- Specify wether the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the movie should skip all the content between the TimeStart and TimeEnd of this chapter. -define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored. -define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition. -define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition. -define('EBML_ID_EDITIONFLAGHIDDEN', 0x05BD); // [45][BD] -- If an edition is hidden (1), it should not be available to the user interface (but still to Control Tracks). -define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one. -define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced. -define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file. -define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file. -define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file. -define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed. -define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file. -define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible. -define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values: -define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with. -define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents. -define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with. -define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values: -define('EBML_ID_CONTENTSIGHASHALGO', 0x07E6); // [47][E6] -- The hash algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values: -define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3"). -define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element. -define('EBML_ID_CONTENTENCODINGORDER', 0x1031); // [50][31] -- Tells when this modification was used during encoding/muxing starting with 0 and counting upwards. The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to be unique over all ContentEncodingOrder elements in the segment. -define('EBML_ID_CONTENTENCODINGSCOPE', 0x1032); // [50][32] -- A bit field that describes which elements have been modified in this way. Values (big endian) can be OR'ed. Possible values: -define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values: -define('EBML_ID_CONTENTCOMPRESSION', 0x1034); // [50][34] -- Settings describing the compression used. Must be present if the value of ContentEncodingType is 0 and absent otherwise. Each block must be decompressable even if no previous block is available in order not to prevent seeking. -define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise. -define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster. -define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name. -define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster. -define('EBML_ID_TRACKOFFSET', 0x137F); // [53][7F] -- A value to add to the Block's Timecode. This can be used to adjust the playback offset of a track. -define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name. -define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element). -define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode. -define('EBML_ID_OLDSTEREOMODE', 0x13B9); // [53][B9] -- Bogus StereoMode value used in old versions of libmatroska. DO NOT USE. (0: mono, 1: right eye, 2: left eye, 3: both eyes). -define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content). -define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display. -define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). -define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). -define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display. -define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image. -define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image. -define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image. -define('EBML_ID_FLAGFORCED', 0x15AA); // [55][AA] -- Set if that track MUST be used during playback. There can be many forced track for a kind (audio, video or subs), the player should select the one which language matches the user preference or the default + forced track. Overlay MAY happen between a forced and non-forced track of the same kind. -define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track. -define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3"). -define('EBML_ID_CLUSTERSILENTTRACKS', 0x1854); // [58][54] -- The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks on seeking. Then you should decide what track to use. -define('EBML_ID_CLUSTERSILENTTRACKNUMBER', 0x18D7); // [58][D7] -- One of the track number that are not used from now on in the stream. It could change later if not specified as silent in a further Cluster. -define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file. -define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption. -define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM. -define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec. -define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment. -define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values. -define('EBML_ID_TAGCHAPTERUID', 0x23C4); // [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment. -define('EBML_ID_TAGTRACKUID', 0x23C5); // [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment. -define('EBML_ID_TAGATTACHMENTUID', 0x23C6); // [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment. -define('EBML_ID_TAGEDITIONUID', 0x23C9); // [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment. -define('EBML_ID_TARGETTYPE', 0x23CA); // [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType). -define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec. -define('EBML_ID_TRACKTRANSLATETRACKID', 0x26A5); // [66][A5] -- The binary value used to represent this track in the chapter codec data. The format depends on the ChapProcessCodecID used. -define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu). -define('EBML_ID_TRACKTRANSLATEEDITIONUID', 0x26FC); // [66][FC] -- Specify an edition UID on which this translation applies. When not specified, it means for all editions found in the segment. -define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target. -define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType). -define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom. -define('EBML_ID_CHAPPROCESSTIME', 0x2922); // [69][22] -- Defines when the process command should be handled (0: during the whole chapter, 1: before starting playback, 2: after playback of the chapter). -define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment. -define('EBML_ID_CHAPPROCESSDATA', 0x2933); // [69][33] -- Contains the command information. The data should be interpreted depending on the ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post commands. -define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom. -define('EBML_ID_CHAPPROCESSCODECID', 0x2955); // [69][55] -- Contains the type of the codec used for the processing. A value of 0 means native Matroska processing (to be defined), a value of 1 means the DVD command set is used. More codec IDs can be added later. -define('EBML_ID_CHAPTERTRANSLATEID', 0x29A5); // [69][A5] -- The binary value used to represent this segment in the chapter codec data. The format depends on the ChapProcessCodecID used. -define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu). -define('EBML_ID_CHAPTERTRANSLATEEDITIONUID', 0x29FC); // [69][FC] -- Specify an edition UID on which this correspondance applies. When not specified, it means for all editions found in the segment. -define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption. -define('EBML_ID_MINCACHE', 0x2DE7); // [6D][E7] -- The minimum number of frames a player should be able to cache during playback. If set to 0, the reference pseudo-cache system is not used. -define('EBML_ID_MAXCACHE', 0x2DF8); // [6D][F8] -- The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. -define('EBML_ID_CHAPTERSEGMENTUID', 0x2E67); // [6E][67] -- A segment to play in place of this chapter. Edition ChapterSegmentEditionUID should be used for this segment, otherwise no edition is used. -define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID. -define('EBML_ID_TRACKOVERLAY', 0x2FAB); // [6F][AB] -- Specify that this track is an overlay track for the Track specified (in the u-integer). That means when this track has a gap (see SilentTracks) the overlay track should be used instead. The order of multiple TrackOverlay matters, the first one is the one that should be used. If not found it should be the second, etc. -define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters. -define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment. -define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits). -define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter. -define('EBML_ID_TRACKUID', 0x33C5); // [73][C5] -- A unique ID to identify the Track. This should be kept the same when making a direct stream copy of the Track to another file. -define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec. -define('EBML_ID_CLUSTERBLOCKADDITIONS', 0x35A1); // [75][A1] -- Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block structure could still see and use/skip these data. -define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix. -define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques). -define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment. -define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display. -define('EBML_ID_TRACKTYPE', 0x03); // [83] -- A set of track types coded on 8 bits (1: video, 2: audio, 3: complex, 0x10: logo, 0x11: subtitle, 0x12: buttons, 0x20: control). -define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom. -define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info. -define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference. -define('EBML_ID_CHAPTERTRACKNUMBER', 0x09); // [89] -- UID of the Track to apply this chapter too. In the absense of a control track, choosing this chapter will select the listed Tracks and deselect unlisted tracks. Absense of this element indicates that the Chapter should be applied to any currently used Tracks. -define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description. -define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply -define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled). -define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled). -define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block. -define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block. -define('EBML_ID_CHAPTERFLAGHIDDEN', 0x18); // [98] -- If a chapter is hidden (1), it should not be available to the user interface (but still to Control Tracks). -define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced. -define('EBML_ID_CLUSTERBLOCKDURATION', 0x1B); // [9B] -- The duration of the Block (based on TimecodeScale). This element is mandatory when DefaultDuration is set for the track. When not written and with no DefaultDuration, the value is assumed to be the difference between the timecode of this Block and the timecode of the next Block in "display" order (not coding order). This element can be useful at the end of a Track (as there is not other Block available), or when there is a break in a track like for subtitle tracks. -define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing. -define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track. -define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock. -define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode. -define('EBML_ID_CLUSTERBLOCKVIRTUAL', 0x22); // [A2] -- A Block with no data. It must be stored in the stream at the place the real Block should be in display order. -define('EBML_ID_CLUSTERSIMPLEBLOCK', 0x23); // [A3] -- Similar to Block but without all the extra information, mostly used to reduced overhead when no extra feature is needed. -define('EBML_ID_CLUSTERCODECSTATE', 0x24); // [A4] -- The new codec state to use. Data interpretation is private to the codec. This information should always be referenced by a seek entry. -define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID). -define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters. -define('EBML_ID_CLUSTERPOSITION', 0x27); // [A7] -- Position of the Cluster in the segment (0 in live broadcast streams). It might help to resynchronise offset on damaged streams. -define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data. -define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing. -define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements. -define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed). -define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels. -define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base. -define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz. -define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks). -define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode. -define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used. -define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels. -define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment. -define('EBML_ID_CRC32', 0x3F); // [BF] -- The CRC is computed on all the data of the Master element it's in, regardless of its position. It's recommended to put the CRC value at the beggining of the Master element for easier reading. All level 1 elements should include a CRC-32. -define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block). -define('EBML_ID_CLUSTERLACENUMBER', 0x4C); // [CC] -- The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback. -define('EBML_ID_CLUSTERFRAMENUMBER', 0x4D); // [CD] -- The number of the frame to generate from this lace with this delay (allow you to generate many frames from the same Block/Frame). -define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element. -define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element. -define('EBML_ID_TRACKNUMBER', 0x57); // [D7] -- The track number as used in the Block Header (using more than 127 tracks is not encouraged, though the design allows an unlimited number). -define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks. -define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings. -define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings. -define('EBML_ID_CLUSTERTIMESLICE', 0x68); // [E8] -- Contains extra time information about the data contained in the Block. While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback. -define('EBML_ID_CUECODECSTATE', 0x6A); // [EA] -- The position of the Codec State corresponding to this Cue element. 0 means that the data is taken from the initial Track Entry. -define('EBML_ID_CUEREFCODECSTATE', 0x6B); // [EB] -- The position of the Codec State corresponding to this referenced element. 0 means that the data is taken from the initial Track Entry. -define('EBML_ID_VOID', 0x6C); // [EC] -- Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is discarded. Also used to reserve space in a sub-element for later use. -define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale). -define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level. -define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block. -define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given. -define('EBML_ID_CLUSTERREFERENCEPRIORITY', 0x7A); // [FA] -- This frame is referenced and has the specified cache priority. In cache only a frame of the same or higher priority can replace this frame. A value of 0 means the frame is not referenced. -define('EBML_ID_CLUSTERREFERENCEBLOCK', 0x7B); // [FB] -- Timecode of another frame used as a reference (ie: B or P frame). The timecode is relative to the block it's attached to. -define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] -- Relative position of the data that should be in position of the virtual block. - - -/** -* @tutorial http://www.matroska.org/technical/specs/index.html -* -* @todo Rewrite EBML parser to reduce it's size and honor default element values -* @todo After rewrite implement stream size calculation, that will provide additional useful info and enable AAC/FLAC audio bitrate detection -*/ -class getid3_matroska extends getid3_handler -{ - // public options - public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE] - public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE] - - // private parser settings/placeholders - private $EBMLbuffer = ''; - private $EBMLbuffer_offset = 0; - private $EBMLbuffer_length = 0; - private $current_offset = 0; - private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID); - - public function Analyze() - { - $info = &$this->getid3->info; - - // parse container - try { - $this->parseEBML($info); - } catch (Exception $e) { - $info['error'][] = 'EBML parser: '.$e->getMessage(); - } - - // calculate playtime - if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { - foreach ($info['matroska']['info'] as $key => $infoarray) { - if (isset($infoarray['Duration'])) { - // TimecodeScale is how many nanoseconds each Duration unit is - $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000); - break; - } - } - } - - // extract tags - if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) { - foreach ($info['matroska']['tags'] as $key => $infoarray) { - $this->ExtractCommentsSimpleTag($infoarray); - } - } - - // process tracks - if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { - foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) { - - $track_info = array(); - $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']); - $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true); - if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; } - - switch ($trackarray['TrackType']) { - - case 1: // Video - $track_info['resolution_x'] = $trackarray['PixelWidth']; - $track_info['resolution_y'] = $trackarray['PixelHeight']; - $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0); - $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']); - $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']); - - if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } - if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } - if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } - if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } - if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } - if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } - - switch ($trackarray['CodecID']) { - case 'V_MS/VFW/FOURCC': - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) { - $this->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"'); - break; - } - $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']); - $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']); - $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; - break; - - /*case 'V_MPEG4/ISO/AVC': - $h264['profile'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1)); - $h264['level'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1)); - $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1)); - $h264['NALUlength'] = ($rn & 3) + 1; - $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1)); - $nsps = ($rn & 31); - $offset = 6; - for ($i = 0; $i < $nsps; $i ++) { - $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); - $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); - $offset += 2 + $length; - } - $npps = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1)); - $offset += 1; - for ($i = 0; $i < $npps; $i ++) { - $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); - $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); - $offset += 2 + $length; - } - $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264; - break;*/ - } - - $info['video']['streams'][] = $track_info; - break; - - case 2: // Audio - $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0); - $track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1); - $track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng'); - if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; } - if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } - - switch ($trackarray['CodecID']) { - case 'A_PCM/INT/LIT': - case 'A_PCM/INT/BIG': - $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth']; - break; - - case 'A_AC3': - case 'A_DTS': - case 'A_MPEG/L3': - case 'A_MPEG/L2': - case 'A_FLAC': - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, false)) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"'); - break; - } - - if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set'); - break; - } - - // create temp instance - $getid3_temp = new getID3(); - if ($track_info['dataformat'] != 'flac') { - $getid3_temp->openfile($this->getid3->filename); - } - $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset']; - if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') { - $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length']; - } - - // analyze - $class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']); - $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat']; - $getid3_audio = new $class($getid3_temp, __CLASS__); - if ($track_info['dataformat'] == 'flac') { - $getid3_audio->AnalyzeString($trackarray['CodecPrivate']); - } - else { - $getid3_audio->Analyze(); - } - if (!empty($getid3_temp->info[$header_data_key])) { - $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key]; - if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { - foreach ($getid3_temp->info['audio'] as $key => $value) { - $track_info[$key] = $value; - } - } - } - else { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']); - } - - // copy errors and warnings - if (!empty($getid3_temp->info['error'])) { - foreach ($getid3_temp->info['error'] as $newerror) { - $this->warning($class.'() says: ['.$newerror.']'); - } - } - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $newerror) { - if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) { - // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning - continue; - } - $this->warning($class.'() says: ['.$newerror.']'); - } - } - unset($getid3_temp, $getid3_audio); - break; - - case 'A_AAC': - case 'A_AAC/MPEG2/LC': - case 'A_AAC/MPEG2/LC/SBR': - case 'A_AAC/MPEG4/LC': - case 'A_AAC/MPEG4/LC/SBR': - $this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated'); - break; - - case 'A_VORBIS': - if (!isset($trackarray['CodecPrivate'])) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set'); - break; - } - $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1); - if ($vorbis_offset === false) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword'); - break; - } - $vorbis_offset -= 1; - - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"'); - break; - } - - // create temp instance - $getid3_temp = new getID3(); - - // analyze - $getid3_ogg = new getid3_ogg($getid3_temp); - $oggpageinfo['page_seqno'] = 0; - $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo); - if (!empty($getid3_temp->info['ogg'])) { - $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg']; - if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { - foreach ($getid3_temp->info['audio'] as $key => $value) { - $track_info[$key] = $value; - } - } - } - - // copy errors and warnings - if (!empty($getid3_temp->info['error'])) { - foreach ($getid3_temp->info['error'] as $newerror) { - $this->warning('getid3_ogg() says: ['.$newerror.']'); - } - } - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $newerror) { - $this->warning('getid3_ogg() says: ['.$newerror.']'); - } - } - - if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) { - $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal']; - } - unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset); - break; - - case 'A_MS/ACM': - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) { - $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"'); - break; - } - - $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']); - foreach ($parsed as $key => $value) { - if ($key != 'raw') { - $track_info[$key] = $value; - } - } - $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; - break; - - default: - $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"'); - } - - $info['audio']['streams'][] = $track_info; - break; - } - } - - if (!empty($info['video']['streams'])) { - $info['video'] = self::getDefaultStreamInfo($info['video']['streams']); - } - if (!empty($info['audio']['streams'])) { - $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']); - } - } - - // process attachments - if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) { - foreach ($info['matroska']['attachments'] as $i => $entry) { - if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) { - $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']); - } - } - } - - // determine mime type - if (!empty($info['video']['streams'])) { - $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska'); - } elseif (!empty($info['audio']['streams'])) { - $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska'); - } elseif (isset($info['mime_type'])) { - unset($info['mime_type']); - } - - return true; - } - - private function parseEBML(&$info) { - // http://www.matroska.org/technical/specs/index.html#EBMLBasics - $this->current_offset = $info['avdataoffset']; - - while ($this->getEBMLelement($top_element, $info['avdataend'])) { - switch ($top_element['id']) { - - case EBML_ID_EBML: - $info['fileformat'] = 'matroska'; - $info['matroska']['header']['offset'] = $top_element['offset']; - $info['matroska']['header']['length'] = $top_element['length']; - - while ($this->getEBMLelement($element_data, $top_element['end'], true)) { - switch ($element_data['id']) { - - case EBML_ID_EBMLVERSION: - case EBML_ID_EBMLREADVERSION: - case EBML_ID_EBMLMAXIDLENGTH: - case EBML_ID_EBMLMAXSIZELENGTH: - case EBML_ID_DOCTYPEVERSION: - case EBML_ID_DOCTYPEREADVERSION: - $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']); - break; - - case EBML_ID_DOCTYPE: - $element_data['data'] = getid3_lib::trimNullByte($element_data['data']); - $info['matroska']['doctype'] = $element_data['data']; - break; - - default: - $this->unhandledElement('header', __LINE__, $element_data); - } - - unset($element_data['offset'], $element_data['end']); - $info['matroska']['header']['elements'][] = $element_data; - } - break; - - case EBML_ID_SEGMENT: - $info['matroska']['segment'][0]['offset'] = $top_element['offset']; - $info['matroska']['segment'][0]['length'] = $top_element['length']; - - while ($this->getEBMLelement($element_data, $top_element['end'])) { - if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required - $info['matroska']['segments'][] = $element_data; - } - switch ($element_data['id']) { - - case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements. - - while ($this->getEBMLelement($seek_entry, $element_data['end'])) { - switch ($seek_entry['id']) { - - case EBML_ID_SEEK: // Contains a single seek entry to an EBML element - while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) { - - switch ($sub_seek_entry['id']) { - - case EBML_ID_SEEKID: - $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']); - $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']); - break; - - case EBML_ID_SEEKPOSITION: - $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']); - break; - - default: - $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); } - } - - if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required - $info['matroska']['seek'][] = $seek_entry; - } - break; - - default: - $this->unhandledElement('seekhead', __LINE__, $seek_entry); - } - } - break; - - case EBML_ID_TRACKS: // A top-level block of information with many tracks described. - $info['matroska']['tracks'] = $element_data; - - while ($this->getEBMLelement($track_entry, $element_data['end'])) { - switch ($track_entry['id']) { - - case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements. - - while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) { - switch ($subelement['id']) { - - case EBML_ID_TRACKNUMBER: - case EBML_ID_TRACKUID: - case EBML_ID_TRACKTYPE: - case EBML_ID_MINCACHE: - case EBML_ID_MAXCACHE: - case EBML_ID_MAXBLOCKADDITIONID: - case EBML_ID_DEFAULTDURATION: // nanoseconds per frame - $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); - break; - - case EBML_ID_TRACKTIMECODESCALE: - $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']); - break; - - case EBML_ID_CODECID: - case EBML_ID_LANGUAGE: - case EBML_ID_NAME: - case EBML_ID_CODECNAME: - $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); - break; - - case EBML_ID_CODECPRIVATE: - $track_entry[$subelement['id_name']] = $this->readEBMLelementData($subelement['length'], true); - break; - - case EBML_ID_FLAGENABLED: - case EBML_ID_FLAGDEFAULT: - case EBML_ID_FLAGFORCED: - case EBML_ID_FLAGLACING: - case EBML_ID_CODECDECODEALL: - $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']); - break; - - case EBML_ID_VIDEO: - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { - switch ($sub_subelement['id']) { - - case EBML_ID_PIXELWIDTH: - case EBML_ID_PIXELHEIGHT: - case EBML_ID_PIXELCROPBOTTOM: - case EBML_ID_PIXELCROPTOP: - case EBML_ID_PIXELCROPLEFT: - case EBML_ID_PIXELCROPRIGHT: - case EBML_ID_DISPLAYWIDTH: - case EBML_ID_DISPLAYHEIGHT: - case EBML_ID_DISPLAYUNIT: - case EBML_ID_ASPECTRATIOTYPE: - case EBML_ID_STEREOMODE: - case EBML_ID_OLDSTEREOMODE: - $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_FLAGINTERLACED: - $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_GAMMAVALUE: - $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']); - break; - - case EBML_ID_COLOURSPACE: - $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); - break; - - default: - $this->unhandledElement('track.video', __LINE__, $sub_subelement); - } - } - break; - - case EBML_ID_AUDIO: - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { - switch ($sub_subelement['id']) { - - case EBML_ID_CHANNELS: - case EBML_ID_BITDEPTH: - $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_SAMPLINGFREQUENCY: - case EBML_ID_OUTPUTSAMPLINGFREQUENCY: - $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']); - break; - - case EBML_ID_CHANNELPOSITIONS: - $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); - break; - - default: - $this->unhandledElement('track.audio', __LINE__, $sub_subelement); - } - } - break; - - case EBML_ID_CONTENTENCODINGS: - - while ($this->getEBMLelement($sub_subelement, $subelement['end'])) { - switch ($sub_subelement['id']) { - - case EBML_ID_CONTENTENCODING: - - while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) { - switch ($sub_sub_subelement['id']) { - - case EBML_ID_CONTENTENCODINGORDER: - case EBML_ID_CONTENTENCODINGSCOPE: - case EBML_ID_CONTENTENCODINGTYPE: - $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - break; - - case EBML_ID_CONTENTCOMPRESSION: - - while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { - switch ($sub_sub_sub_subelement['id']) { - - case EBML_ID_CONTENTCOMPALGO: - $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); - break; - - case EBML_ID_CONTENTCOMPSETTINGS: - $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; - break; - - default: - $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); - } - } - break; - - case EBML_ID_CONTENTENCRYPTION: - - while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { - switch ($sub_sub_sub_subelement['id']) { - - case EBML_ID_CONTENTENCALGO: - case EBML_ID_CONTENTSIGALGO: - case EBML_ID_CONTENTSIGHASHALGO: - $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); - break; - - case EBML_ID_CONTENTENCKEYID: - case EBML_ID_CONTENTSIGNATURE: - case EBML_ID_CONTENTSIGKEYID: - $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; - break; - - default: - $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); - } - } - break; - - default: - $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement); - } - } - break; - - default: - $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement); - } - } - break; - - default: - $this->unhandledElement('track', __LINE__, $subelement); - } - } - - $info['matroska']['tracks']['tracks'][] = $track_entry; - break; - - default: - $this->unhandledElement('tracks', __LINE__, $track_entry); - } - } - break; - - case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file. - $info_entry = array(); - - while ($this->getEBMLelement($subelement, $element_data['end'], true)) { - switch ($subelement['id']) { - - case EBML_ID_TIMECODESCALE: - $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); - break; - - case EBML_ID_DURATION: - $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']); - break; - - case EBML_ID_DATEUTC: - $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); - $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]); - break; - - case EBML_ID_SEGMENTUID: - case EBML_ID_PREVUID: - case EBML_ID_NEXTUID: - $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); - break; - - case EBML_ID_SEGMENTFAMILY: - $info_entry[$subelement['id_name']][] = getid3_lib::trimNullByte($subelement['data']); - break; - - case EBML_ID_SEGMENTFILENAME: - case EBML_ID_PREVFILENAME: - case EBML_ID_NEXTFILENAME: - case EBML_ID_TITLE: - case EBML_ID_MUXINGAPP: - case EBML_ID_WRITINGAPP: - $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); - $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']]; - break; - - case EBML_ID_CHAPTERTRANSLATE: - $chaptertranslate_entry = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { - switch ($sub_subelement['id']) { - - case EBML_ID_CHAPTERTRANSLATEEDITIONUID: - $chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_CHAPTERTRANSLATECODEC: - $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_CHAPTERTRANSLATEID: - $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); - break; - - default: - $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement); - } - } - $info_entry[$subelement['id_name']] = $chaptertranslate_entry; - break; - - default: - $this->unhandledElement('info', __LINE__, $subelement); - } - } - $info['matroska']['info'][] = $info_entry; - break; - - case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams. - if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway - $this->current_offset = $element_data['end']; - break; - } - $cues_entry = array(); - - while ($this->getEBMLelement($subelement, $element_data['end'])) { - switch ($subelement['id']) { - - case EBML_ID_CUEPOINT: - $cuepoint_entry = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) { - switch ($sub_subelement['id']) { - - case EBML_ID_CUETRACKPOSITIONS: - $cuetrackpositions_entry = array(); - - while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) { - switch ($sub_sub_subelement['id']) { - - case EBML_ID_CUETRACK: - case EBML_ID_CUECLUSTERPOSITION: - case EBML_ID_CUEBLOCKNUMBER: - case EBML_ID_CUECODECSTATE: - $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - break; - - default: - $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement); - } - } - $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry; - break; - - case EBML_ID_CUETIME: - $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - default: - $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement); - } - } - $cues_entry[] = $cuepoint_entry; - break; - - default: - $this->unhandledElement('cues', __LINE__, $subelement); - } - } - $info['matroska']['cues'] = $cues_entry; - break; - - case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters. - $tags_entry = array(); - - while ($this->getEBMLelement($subelement, $element_data['end'], false)) { - switch ($subelement['id']) { - - case EBML_ID_TAG: - $tag_entry = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) { - switch ($sub_subelement['id']) { - - case EBML_ID_TARGETS: - $targets_entry = array(); - - while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) { - switch ($sub_sub_subelement['id']) { - - case EBML_ID_TARGETTYPEVALUE: - $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]); - break; - - case EBML_ID_TARGETTYPE: - $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data']; - break; - - case EBML_ID_TAGTRACKUID: - case EBML_ID_TAGEDITIONUID: - case EBML_ID_TAGCHAPTERUID: - case EBML_ID_TAGATTACHMENTUID: - $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - break; - - default: - $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement); - } - } - $tag_entry[$sub_subelement['id_name']] = $targets_entry; - break; - - case EBML_ID_SIMPLETAG: - $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']); - break; - - default: - $this->unhandledElement('tags.tag', __LINE__, $sub_subelement); - } - } - $tags_entry[] = $tag_entry; - break; - - default: - $this->unhandledElement('tags', __LINE__, $subelement); - } - } - $info['matroska']['tags'] = $tags_entry; - break; - - case EBML_ID_ATTACHMENTS: // Contain attached files. - - while ($this->getEBMLelement($subelement, $element_data['end'])) { - switch ($subelement['id']) { - - case EBML_ID_ATTACHEDFILE: - $attachedfile_entry = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) { - switch ($sub_subelement['id']) { - - case EBML_ID_FILEDESCRIPTION: - case EBML_ID_FILENAME: - case EBML_ID_FILEMIMETYPE: - $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data']; - break; - - case EBML_ID_FILEDATA: - $attachedfile_entry['data_offset'] = $this->current_offset; - $attachedfile_entry['data_length'] = $sub_subelement['length']; - - $attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment( - $attachedfile_entry['FileName'], - $attachedfile_entry['data_offset'], - $attachedfile_entry['data_length']); - - $this->current_offset = $sub_subelement['end']; - break; - - case EBML_ID_FILEUID: - $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - default: - $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement); - } - } - $info['matroska']['attachments'][] = $attachedfile_entry; - break; - - default: - $this->unhandledElement('attachments', __LINE__, $subelement); - } - } - break; - - case EBML_ID_CHAPTERS: - - while ($this->getEBMLelement($subelement, $element_data['end'])) { - switch ($subelement['id']) { - - case EBML_ID_EDITIONENTRY: - $editionentry_entry = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) { - switch ($sub_subelement['id']) { - - case EBML_ID_EDITIONUID: - $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_EDITIONFLAGHIDDEN: - case EBML_ID_EDITIONFLAGDEFAULT: - case EBML_ID_EDITIONFLAGORDERED: - $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_CHAPTERATOM: - $chapteratom_entry = array(); - - while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) { - switch ($sub_sub_subelement['id']) { - - case EBML_ID_CHAPTERSEGMENTUID: - case EBML_ID_CHAPTERSEGMENTEDITIONUID: - $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data']; - break; - - case EBML_ID_CHAPTERFLAGENABLED: - case EBML_ID_CHAPTERFLAGHIDDEN: - $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - break; - - case EBML_ID_CHAPTERUID: - case EBML_ID_CHAPTERTIMESTART: - case EBML_ID_CHAPTERTIMEEND: - $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); - break; - - case EBML_ID_CHAPTERTRACK: - $chaptertrack_entry = array(); - - while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { - switch ($sub_sub_sub_subelement['id']) { - - case EBML_ID_CHAPTERTRACKNUMBER: - $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); - break; - - default: - $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement); - } - } - $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry; - break; - - case EBML_ID_CHAPTERDISPLAY: - $chapterdisplay_entry = array(); - - while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { - switch ($sub_sub_sub_subelement['id']) { - - case EBML_ID_CHAPSTRING: - case EBML_ID_CHAPLANGUAGE: - case EBML_ID_CHAPCOUNTRY: - $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; - break; - - default: - $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement); - } - } - $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry; - break; - - default: - $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement); - } - } - $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry; - break; - - default: - $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement); - } - } - $info['matroska']['chapters'][] = $editionentry_entry; - break; - - default: - $this->unhandledElement('chapters', __LINE__, $subelement); - } - } - break; - - case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure. - $cluster_entry = array(); - - while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) { - switch ($subelement['id']) { - - case EBML_ID_CLUSTERTIMECODE: - case EBML_ID_CLUSTERPOSITION: - case EBML_ID_CLUSTERPREVSIZE: - $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); - break; - - case EBML_ID_CLUSTERSILENTTRACKS: - $cluster_silent_tracks = array(); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { - switch ($sub_subelement['id']) { - - case EBML_ID_CLUSTERSILENTTRACKNUMBER: - $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - default: - $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement); - } - } - $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks; - break; - - case EBML_ID_CLUSTERBLOCKGROUP: - $cluster_block_group = array('offset' => $this->current_offset); - - while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) { - switch ($sub_subelement['id']) { - - case EBML_ID_CLUSTERBLOCK: - $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info); - break; - - case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int - case EBML_ID_CLUSTERBLOCKDURATION: // unsigned-int - $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); - break; - - case EBML_ID_CLUSTERREFERENCEBLOCK: // signed-int - $cluster_block_group[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true); - break; - - case EBML_ID_CLUSTERCODECSTATE: - $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); - break; - - default: - $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement); - } - } - $cluster_entry[$subelement['id_name']][] = $cluster_block_group; - break; - - case EBML_ID_CLUSTERSIMPLEBLOCK: - $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info); - break; - - default: - $this->unhandledElement('cluster', __LINE__, $subelement); - } - $this->current_offset = $subelement['end']; - } - if (!self::$hide_clusters) { - $info['matroska']['cluster'][] = $cluster_entry; - } - - // check to see if all the data we need exists already, if so, break out of the loop - if (!self::$parse_whole_file) { - if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { - if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { - if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) { - return; - } - } - } - } - break; - - default: - $this->unhandledElement('segment', __LINE__, $element_data); - } - } - break; - - default: - $this->unhandledElement('root', __LINE__, $top_element); - } - } - } - - private function EnsureBufferHasEnoughData($min_data=1024) { - if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) { - $read_bytes = max($min_data, $this->getid3->fread_buffer_size()); - - try { - $this->fseek($this->current_offset); - $this->EBMLbuffer_offset = $this->current_offset; - $this->EBMLbuffer = $this->fread($read_bytes); - $this->EBMLbuffer_length = strlen($this->EBMLbuffer); - } catch (getid3_exception $e) { - $this->warning('EBML parser: '.$e->getMessage()); - return false; - } - - if ($this->EBMLbuffer_length == 0 && $this->feof()) { - return $this->error('EBML parser: ran out of file at offset '.$this->current_offset); - } - } - return true; - } - - private function readEBMLint() { - $actual_offset = $this->current_offset - $this->EBMLbuffer_offset; - - // get length of integer - $first_byte_int = ord($this->EBMLbuffer[$actual_offset]); - if (0x80 & $first_byte_int) { - $length = 1; - } elseif (0x40 & $first_byte_int) { - $length = 2; - } elseif (0x20 & $first_byte_int) { - $length = 3; - } elseif (0x10 & $first_byte_int) { - $length = 4; - } elseif (0x08 & $first_byte_int) { - $length = 5; - } elseif (0x04 & $first_byte_int) { - $length = 6; - } elseif (0x02 & $first_byte_int) { - $length = 7; - } elseif (0x01 & $first_byte_int) { - $length = 8; - } else { - throw new Exception('invalid EBML integer (leading 0x00) at '.$this->current_offset); - } - - // read - $int_value = self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length)); - $this->current_offset += $length; - - return $int_value; - } - - private function readEBMLelementData($length, $check_buffer=false) { - if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) { - return false; - } - $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length); - $this->current_offset += $length; - return $data; - } - - private function getEBMLelement(&$element, $parent_end, $get_data=false) { - if ($this->current_offset >= $parent_end) { - return false; - } - - if (!$this->EnsureBufferHasEnoughData()) { - $this->current_offset = PHP_INT_MAX; // do not exit parser right now, allow to finish current loop to gather maximum information - return false; - } - - $element = array(); - - // set offset - $element['offset'] = $this->current_offset; - - // get ID - $element['id'] = $this->readEBMLint(); - - // get name - $element['id_name'] = self::EBMLidName($element['id']); - - // get length - $element['length'] = $this->readEBMLint(); - - // get end offset - $element['end'] = $this->current_offset + $element['length']; - - // get raw data - $dont_parse = (in_array($element['id'], $this->unuseful_elements) || $element['id_name'] == dechex($element['id'])); - if (($get_data === true || (is_array($get_data) && !in_array($element['id'], $get_data))) && !$dont_parse) { - $element['data'] = $this->readEBMLelementData($element['length'], $element); - } - - return true; - } - - private function unhandledElement($type, $line, $element) { - // warn only about unknown and missed elements, not about unuseful - if (!in_array($element['id'], $this->unuseful_elements)) { - $this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']); - } - - // increase offset for unparsed elements - if (!isset($element['data'])) { - $this->current_offset = $element['end']; - } - } - - private function ExtractCommentsSimpleTag($SimpleTagArray) { - if (!empty($SimpleTagArray['SimpleTag'])) { - foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) { - if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) { - $this->getid3->info['matroska']['comments'][strtolower($SimpleTagData['TagName'])][] = $SimpleTagData['TagString']; - } - if (!empty($SimpleTagData['SimpleTag'])) { - $this->ExtractCommentsSimpleTag($SimpleTagData); - } - } - } - - return true; - } - - private function HandleEMBLSimpleTag($parent_end) { - $simpletag_entry = array(); - - while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) { - switch ($element['id']) { - - case EBML_ID_TAGNAME: - case EBML_ID_TAGLANGUAGE: - case EBML_ID_TAGSTRING: - case EBML_ID_TAGBINARY: - $simpletag_entry[$element['id_name']] = $element['data']; - break; - - case EBML_ID_SIMPLETAG: - $simpletag_entry[$element['id_name']][] = $this->HandleEMBLSimpleTag($element['end']); - break; - - case EBML_ID_TAGDEFAULT: - $simpletag_entry[$element['id_name']] = (bool)getid3_lib::BigEndian2Int($element['data']); - break; - - default: - $this->unhandledElement('tag.simpletag', __LINE__, $element); - } - } - - return $simpletag_entry; - } - - private function HandleEMBLClusterBlock($element, $block_type, &$info) { - // http://www.matroska.org/technical/specs/index.html#block_structure - // http://www.matroska.org/technical/specs/index.html#simpleblock_structure - - $block_data = array(); - $block_data['tracknumber'] = $this->readEBMLint(); - $block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true); - $block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)); - - if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) { - $block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7); - //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4); - } - else { - //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4); - } - $block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3); - $block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing - if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) { - $block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01)); - } - else { - //$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0); - } - $block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']); - - // Lace (when lacing bit is set) - if ($block_data['flags']['lacing'] > 0) { - $block_data['lace_frames'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)) + 1; // Number of frames in the lace-1 (uint8) - if ($block_data['flags']['lacing'] != 0x02) { - for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace). - if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing - $block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing. - } - else { // Xiph lacing - $block_data['lace_frames_size'][$i] = 0; - do { - $size = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)); - $block_data['lace_frames_size'][$i] += $size; - } - while ($size == 255); - } - } - if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly - $block_data['lace_frames_size'][] = $element['end'] - $this->current_offset - array_sum($block_data['lace_frames_size']); - } - } - } - - if (!isset($info['matroska']['track_data_offsets'][$block_data['tracknumber']])) { - $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['offset'] = $this->current_offset; - $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'] = $element['end'] - $this->current_offset; - //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] = 0; - } - //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] += $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length']; - //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['duration'] = $block_data['timecode'] * ((isset($info['matroska']['info'][0]['TimecodeScale']) ? $info['matroska']['info'][0]['TimecodeScale'] : 1000000) / 1000000000); - - // set offset manually - $this->current_offset = $element['end']; - - return $block_data; - } - - private static function EBML2Int($EBMLstring) { - // http://matroska.org/specs/ - - // Element ID coded with an UTF-8 like system: - // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X) - // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX) - // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX) - // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX) - // Values with all x at 0 and 1 are reserved (hence the -2). - - // Data size, in octets, is also coded with an UTF-8 like system : - // 1xxx xxxx - value 0 to 2^7-2 - // 01xx xxxx xxxx xxxx - value 0 to 2^14-2 - // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 - // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 - // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 - // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 - // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 - // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 - - $first_byte_int = ord($EBMLstring[0]); - if (0x80 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x7F); - } elseif (0x40 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x3F); - } elseif (0x20 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x1F); - } elseif (0x10 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x0F); - } elseif (0x08 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x07); - } elseif (0x04 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x03); - } elseif (0x02 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x01); - } elseif (0x01 & $first_byte_int) { - $EBMLstring[0] = chr($first_byte_int & 0x00); - } - - return getid3_lib::BigEndian2Int($EBMLstring); - } - - private static function EBMLdate2unix($EBMLdatestamp) { - // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC) - // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC - return round(($EBMLdatestamp / 1000000000) + 978307200); - } - - public static function TargetTypeValue($target_type) { - // http://www.matroska.org/technical/specs/tagging/index.html - static $TargetTypeValue = array(); - if (empty($TargetTypeValue)) { - $TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies - $TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement) - $TargetTypeValue[30] = 'A:track/song ~ V:chapter'; // the common parts of an album or a movie - $TargetTypeValue[40] = 'A:part/session ~ V:part/session'; // when an album or episode has different logical parts - $TargetTypeValue[50] = 'A:album/opera/concert ~ V:movie/episode/concert'; // the most common grouping level of music and video (equals to an episode for TV series) - $TargetTypeValue[60] = 'A:edition/issue/volume/opus ~ V:season/sequel/volume'; // a list of lower levels grouped together - $TargetTypeValue[70] = 'A:collection ~ V:collection'; // the high hierarchy consisting of many different lower items - } - return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type); - } - - public static function BlockLacingType($lacingtype) { - // http://matroska.org/technical/specs/index.html#block_structure - static $BlockLacingType = array(); - if (empty($BlockLacingType)) { - $BlockLacingType[0x00] = 'no lacing'; - $BlockLacingType[0x01] = 'Xiph lacing'; - $BlockLacingType[0x02] = 'fixed-size lacing'; - $BlockLacingType[0x03] = 'EBML lacing'; - } - return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype); - } - - public static function CodecIDtoCommonName($codecid) { - // http://www.matroska.org/technical/specs/codecid/index.html - static $CodecIDlist = array(); - if (empty($CodecIDlist)) { - $CodecIDlist['A_AAC'] = 'aac'; - $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac'; - $CodecIDlist['A_AC3'] = 'ac3'; - $CodecIDlist['A_DTS'] = 'dts'; - $CodecIDlist['A_FLAC'] = 'flac'; - $CodecIDlist['A_MPEG/L1'] = 'mp1'; - $CodecIDlist['A_MPEG/L2'] = 'mp2'; - $CodecIDlist['A_MPEG/L3'] = 'mp3'; - $CodecIDlist['A_PCM/INT/LIT'] = 'pcm'; // PCM Integer Little Endian - $CodecIDlist['A_PCM/INT/BIG'] = 'pcm'; // PCM Integer Big Endian - $CodecIDlist['A_QUICKTIME/QDMC'] = 'quicktime'; // Quicktime: QDesign Music - $CodecIDlist['A_QUICKTIME/QDM2'] = 'quicktime'; // Quicktime: QDesign Music v2 - $CodecIDlist['A_VORBIS'] = 'vorbis'; - $CodecIDlist['V_MPEG1'] = 'mpeg'; - $CodecIDlist['V_THEORA'] = 'theora'; - $CodecIDlist['V_REAL/RV40'] = 'real'; - $CodecIDlist['V_REAL/RV10'] = 'real'; - $CodecIDlist['V_REAL/RV20'] = 'real'; - $CodecIDlist['V_REAL/RV30'] = 'real'; - $CodecIDlist['V_QUICKTIME'] = 'quicktime'; // Quicktime - $CodecIDlist['V_MPEG4/ISO/AP'] = 'mpeg4'; - $CodecIDlist['V_MPEG4/ISO/ASP'] = 'mpeg4'; - $CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264'; - $CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4'; - $CodecIDlist['V_VP8'] = 'vp8'; - $CodecIDlist['V_MS/VFW/FOURCC'] = 'riff'; - $CodecIDlist['A_MS/ACM'] = 'riff'; - } - return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid); - } - - private static function EBMLidName($value) { - static $EBMLidList = array(); - if (empty($EBMLidList)) { - $EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType'; - $EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile'; - $EBMLidList[EBML_ID_ATTACHMENTLINK] = 'AttachmentLink'; - $EBMLidList[EBML_ID_ATTACHMENTS] = 'Attachments'; - $EBMLidList[EBML_ID_AUDIO] = 'Audio'; - $EBMLidList[EBML_ID_BITDEPTH] = 'BitDepth'; - $EBMLidList[EBML_ID_CHANNELPOSITIONS] = 'ChannelPositions'; - $EBMLidList[EBML_ID_CHANNELS] = 'Channels'; - $EBMLidList[EBML_ID_CHAPCOUNTRY] = 'ChapCountry'; - $EBMLidList[EBML_ID_CHAPLANGUAGE] = 'ChapLanguage'; - $EBMLidList[EBML_ID_CHAPPROCESS] = 'ChapProcess'; - $EBMLidList[EBML_ID_CHAPPROCESSCODECID] = 'ChapProcessCodecID'; - $EBMLidList[EBML_ID_CHAPPROCESSCOMMAND] = 'ChapProcessCommand'; - $EBMLidList[EBML_ID_CHAPPROCESSDATA] = 'ChapProcessData'; - $EBMLidList[EBML_ID_CHAPPROCESSPRIVATE] = 'ChapProcessPrivate'; - $EBMLidList[EBML_ID_CHAPPROCESSTIME] = 'ChapProcessTime'; - $EBMLidList[EBML_ID_CHAPSTRING] = 'ChapString'; - $EBMLidList[EBML_ID_CHAPTERATOM] = 'ChapterAtom'; - $EBMLidList[EBML_ID_CHAPTERDISPLAY] = 'ChapterDisplay'; - $EBMLidList[EBML_ID_CHAPTERFLAGENABLED] = 'ChapterFlagEnabled'; - $EBMLidList[EBML_ID_CHAPTERFLAGHIDDEN] = 'ChapterFlagHidden'; - $EBMLidList[EBML_ID_CHAPTERPHYSICALEQUIV] = 'ChapterPhysicalEquiv'; - $EBMLidList[EBML_ID_CHAPTERS] = 'Chapters'; - $EBMLidList[EBML_ID_CHAPTERSEGMENTEDITIONUID] = 'ChapterSegmentEditionUID'; - $EBMLidList[EBML_ID_CHAPTERSEGMENTUID] = 'ChapterSegmentUID'; - $EBMLidList[EBML_ID_CHAPTERTIMEEND] = 'ChapterTimeEnd'; - $EBMLidList[EBML_ID_CHAPTERTIMESTART] = 'ChapterTimeStart'; - $EBMLidList[EBML_ID_CHAPTERTRACK] = 'ChapterTrack'; - $EBMLidList[EBML_ID_CHAPTERTRACKNUMBER] = 'ChapterTrackNumber'; - $EBMLidList[EBML_ID_CHAPTERTRANSLATE] = 'ChapterTranslate'; - $EBMLidList[EBML_ID_CHAPTERTRANSLATECODEC] = 'ChapterTranslateCodec'; - $EBMLidList[EBML_ID_CHAPTERTRANSLATEEDITIONUID] = 'ChapterTranslateEditionUID'; - $EBMLidList[EBML_ID_CHAPTERTRANSLATEID] = 'ChapterTranslateID'; - $EBMLidList[EBML_ID_CHAPTERUID] = 'ChapterUID'; - $EBMLidList[EBML_ID_CLUSTER] = 'Cluster'; - $EBMLidList[EBML_ID_CLUSTERBLOCK] = 'ClusterBlock'; - $EBMLidList[EBML_ID_CLUSTERBLOCKADDID] = 'ClusterBlockAddID'; - $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONAL] = 'ClusterBlockAdditional'; - $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONID] = 'ClusterBlockAdditionID'; - $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONS] = 'ClusterBlockAdditions'; - $EBMLidList[EBML_ID_CLUSTERBLOCKDURATION] = 'ClusterBlockDuration'; - $EBMLidList[EBML_ID_CLUSTERBLOCKGROUP] = 'ClusterBlockGroup'; - $EBMLidList[EBML_ID_CLUSTERBLOCKMORE] = 'ClusterBlockMore'; - $EBMLidList[EBML_ID_CLUSTERBLOCKVIRTUAL] = 'ClusterBlockVirtual'; - $EBMLidList[EBML_ID_CLUSTERCODECSTATE] = 'ClusterCodecState'; - $EBMLidList[EBML_ID_CLUSTERDELAY] = 'ClusterDelay'; - $EBMLidList[EBML_ID_CLUSTERDURATION] = 'ClusterDuration'; - $EBMLidList[EBML_ID_CLUSTERENCRYPTEDBLOCK] = 'ClusterEncryptedBlock'; - $EBMLidList[EBML_ID_CLUSTERFRAMENUMBER] = 'ClusterFrameNumber'; - $EBMLidList[EBML_ID_CLUSTERLACENUMBER] = 'ClusterLaceNumber'; - $EBMLidList[EBML_ID_CLUSTERPOSITION] = 'ClusterPosition'; - $EBMLidList[EBML_ID_CLUSTERPREVSIZE] = 'ClusterPrevSize'; - $EBMLidList[EBML_ID_CLUSTERREFERENCEBLOCK] = 'ClusterReferenceBlock'; - $EBMLidList[EBML_ID_CLUSTERREFERENCEPRIORITY] = 'ClusterReferencePriority'; - $EBMLidList[EBML_ID_CLUSTERREFERENCEVIRTUAL] = 'ClusterReferenceVirtual'; - $EBMLidList[EBML_ID_CLUSTERSILENTTRACKNUMBER] = 'ClusterSilentTrackNumber'; - $EBMLidList[EBML_ID_CLUSTERSILENTTRACKS] = 'ClusterSilentTracks'; - $EBMLidList[EBML_ID_CLUSTERSIMPLEBLOCK] = 'ClusterSimpleBlock'; - $EBMLidList[EBML_ID_CLUSTERTIMECODE] = 'ClusterTimecode'; - $EBMLidList[EBML_ID_CLUSTERTIMESLICE] = 'ClusterTimeSlice'; - $EBMLidList[EBML_ID_CODECDECODEALL] = 'CodecDecodeAll'; - $EBMLidList[EBML_ID_CODECDOWNLOADURL] = 'CodecDownloadURL'; - $EBMLidList[EBML_ID_CODECID] = 'CodecID'; - $EBMLidList[EBML_ID_CODECINFOURL] = 'CodecInfoURL'; - $EBMLidList[EBML_ID_CODECNAME] = 'CodecName'; - $EBMLidList[EBML_ID_CODECPRIVATE] = 'CodecPrivate'; - $EBMLidList[EBML_ID_CODECSETTINGS] = 'CodecSettings'; - $EBMLidList[EBML_ID_COLOURSPACE] = 'ColourSpace'; - $EBMLidList[EBML_ID_CONTENTCOMPALGO] = 'ContentCompAlgo'; - $EBMLidList[EBML_ID_CONTENTCOMPRESSION] = 'ContentCompression'; - $EBMLidList[EBML_ID_CONTENTCOMPSETTINGS] = 'ContentCompSettings'; - $EBMLidList[EBML_ID_CONTENTENCALGO] = 'ContentEncAlgo'; - $EBMLidList[EBML_ID_CONTENTENCKEYID] = 'ContentEncKeyID'; - $EBMLidList[EBML_ID_CONTENTENCODING] = 'ContentEncoding'; - $EBMLidList[EBML_ID_CONTENTENCODINGORDER] = 'ContentEncodingOrder'; - $EBMLidList[EBML_ID_CONTENTENCODINGS] = 'ContentEncodings'; - $EBMLidList[EBML_ID_CONTENTENCODINGSCOPE] = 'ContentEncodingScope'; - $EBMLidList[EBML_ID_CONTENTENCODINGTYPE] = 'ContentEncodingType'; - $EBMLidList[EBML_ID_CONTENTENCRYPTION] = 'ContentEncryption'; - $EBMLidList[EBML_ID_CONTENTSIGALGO] = 'ContentSigAlgo'; - $EBMLidList[EBML_ID_CONTENTSIGHASHALGO] = 'ContentSigHashAlgo'; - $EBMLidList[EBML_ID_CONTENTSIGKEYID] = 'ContentSigKeyID'; - $EBMLidList[EBML_ID_CONTENTSIGNATURE] = 'ContentSignature'; - $EBMLidList[EBML_ID_CRC32] = 'CRC32'; - $EBMLidList[EBML_ID_CUEBLOCKNUMBER] = 'CueBlockNumber'; - $EBMLidList[EBML_ID_CUECLUSTERPOSITION] = 'CueClusterPosition'; - $EBMLidList[EBML_ID_CUECODECSTATE] = 'CueCodecState'; - $EBMLidList[EBML_ID_CUEPOINT] = 'CuePoint'; - $EBMLidList[EBML_ID_CUEREFCLUSTER] = 'CueRefCluster'; - $EBMLidList[EBML_ID_CUEREFCODECSTATE] = 'CueRefCodecState'; - $EBMLidList[EBML_ID_CUEREFERENCE] = 'CueReference'; - $EBMLidList[EBML_ID_CUEREFNUMBER] = 'CueRefNumber'; - $EBMLidList[EBML_ID_CUEREFTIME] = 'CueRefTime'; - $EBMLidList[EBML_ID_CUES] = 'Cues'; - $EBMLidList[EBML_ID_CUETIME] = 'CueTime'; - $EBMLidList[EBML_ID_CUETRACK] = 'CueTrack'; - $EBMLidList[EBML_ID_CUETRACKPOSITIONS] = 'CueTrackPositions'; - $EBMLidList[EBML_ID_DATEUTC] = 'DateUTC'; - $EBMLidList[EBML_ID_DEFAULTDURATION] = 'DefaultDuration'; - $EBMLidList[EBML_ID_DISPLAYHEIGHT] = 'DisplayHeight'; - $EBMLidList[EBML_ID_DISPLAYUNIT] = 'DisplayUnit'; - $EBMLidList[EBML_ID_DISPLAYWIDTH] = 'DisplayWidth'; - $EBMLidList[EBML_ID_DOCTYPE] = 'DocType'; - $EBMLidList[EBML_ID_DOCTYPEREADVERSION] = 'DocTypeReadVersion'; - $EBMLidList[EBML_ID_DOCTYPEVERSION] = 'DocTypeVersion'; - $EBMLidList[EBML_ID_DURATION] = 'Duration'; - $EBMLidList[EBML_ID_EBML] = 'EBML'; - $EBMLidList[EBML_ID_EBMLMAXIDLENGTH] = 'EBMLMaxIDLength'; - $EBMLidList[EBML_ID_EBMLMAXSIZELENGTH] = 'EBMLMaxSizeLength'; - $EBMLidList[EBML_ID_EBMLREADVERSION] = 'EBMLReadVersion'; - $EBMLidList[EBML_ID_EBMLVERSION] = 'EBMLVersion'; - $EBMLidList[EBML_ID_EDITIONENTRY] = 'EditionEntry'; - $EBMLidList[EBML_ID_EDITIONFLAGDEFAULT] = 'EditionFlagDefault'; - $EBMLidList[EBML_ID_EDITIONFLAGHIDDEN] = 'EditionFlagHidden'; - $EBMLidList[EBML_ID_EDITIONFLAGORDERED] = 'EditionFlagOrdered'; - $EBMLidList[EBML_ID_EDITIONUID] = 'EditionUID'; - $EBMLidList[EBML_ID_FILEDATA] = 'FileData'; - $EBMLidList[EBML_ID_FILEDESCRIPTION] = 'FileDescription'; - $EBMLidList[EBML_ID_FILEMIMETYPE] = 'FileMimeType'; - $EBMLidList[EBML_ID_FILENAME] = 'FileName'; - $EBMLidList[EBML_ID_FILEREFERRAL] = 'FileReferral'; - $EBMLidList[EBML_ID_FILEUID] = 'FileUID'; - $EBMLidList[EBML_ID_FLAGDEFAULT] = 'FlagDefault'; - $EBMLidList[EBML_ID_FLAGENABLED] = 'FlagEnabled'; - $EBMLidList[EBML_ID_FLAGFORCED] = 'FlagForced'; - $EBMLidList[EBML_ID_FLAGINTERLACED] = 'FlagInterlaced'; - $EBMLidList[EBML_ID_FLAGLACING] = 'FlagLacing'; - $EBMLidList[EBML_ID_GAMMAVALUE] = 'GammaValue'; - $EBMLidList[EBML_ID_INFO] = 'Info'; - $EBMLidList[EBML_ID_LANGUAGE] = 'Language'; - $EBMLidList[EBML_ID_MAXBLOCKADDITIONID] = 'MaxBlockAdditionID'; - $EBMLidList[EBML_ID_MAXCACHE] = 'MaxCache'; - $EBMLidList[EBML_ID_MINCACHE] = 'MinCache'; - $EBMLidList[EBML_ID_MUXINGAPP] = 'MuxingApp'; - $EBMLidList[EBML_ID_NAME] = 'Name'; - $EBMLidList[EBML_ID_NEXTFILENAME] = 'NextFilename'; - $EBMLidList[EBML_ID_NEXTUID] = 'NextUID'; - $EBMLidList[EBML_ID_OUTPUTSAMPLINGFREQUENCY] = 'OutputSamplingFrequency'; - $EBMLidList[EBML_ID_PIXELCROPBOTTOM] = 'PixelCropBottom'; - $EBMLidList[EBML_ID_PIXELCROPLEFT] = 'PixelCropLeft'; - $EBMLidList[EBML_ID_PIXELCROPRIGHT] = 'PixelCropRight'; - $EBMLidList[EBML_ID_PIXELCROPTOP] = 'PixelCropTop'; - $EBMLidList[EBML_ID_PIXELHEIGHT] = 'PixelHeight'; - $EBMLidList[EBML_ID_PIXELWIDTH] = 'PixelWidth'; - $EBMLidList[EBML_ID_PREVFILENAME] = 'PrevFilename'; - $EBMLidList[EBML_ID_PREVUID] = 'PrevUID'; - $EBMLidList[EBML_ID_SAMPLINGFREQUENCY] = 'SamplingFrequency'; - $EBMLidList[EBML_ID_SEEK] = 'Seek'; - $EBMLidList[EBML_ID_SEEKHEAD] = 'SeekHead'; - $EBMLidList[EBML_ID_SEEKID] = 'SeekID'; - $EBMLidList[EBML_ID_SEEKPOSITION] = 'SeekPosition'; - $EBMLidList[EBML_ID_SEGMENT] = 'Segment'; - $EBMLidList[EBML_ID_SEGMENTFAMILY] = 'SegmentFamily'; - $EBMLidList[EBML_ID_SEGMENTFILENAME] = 'SegmentFilename'; - $EBMLidList[EBML_ID_SEGMENTUID] = 'SegmentUID'; - $EBMLidList[EBML_ID_SIMPLETAG] = 'SimpleTag'; - $EBMLidList[EBML_ID_CLUSTERSLICES] = 'ClusterSlices'; - $EBMLidList[EBML_ID_STEREOMODE] = 'StereoMode'; - $EBMLidList[EBML_ID_OLDSTEREOMODE] = 'OldStereoMode'; - $EBMLidList[EBML_ID_TAG] = 'Tag'; - $EBMLidList[EBML_ID_TAGATTACHMENTUID] = 'TagAttachmentUID'; - $EBMLidList[EBML_ID_TAGBINARY] = 'TagBinary'; - $EBMLidList[EBML_ID_TAGCHAPTERUID] = 'TagChapterUID'; - $EBMLidList[EBML_ID_TAGDEFAULT] = 'TagDefault'; - $EBMLidList[EBML_ID_TAGEDITIONUID] = 'TagEditionUID'; - $EBMLidList[EBML_ID_TAGLANGUAGE] = 'TagLanguage'; - $EBMLidList[EBML_ID_TAGNAME] = 'TagName'; - $EBMLidList[EBML_ID_TAGTRACKUID] = 'TagTrackUID'; - $EBMLidList[EBML_ID_TAGS] = 'Tags'; - $EBMLidList[EBML_ID_TAGSTRING] = 'TagString'; - $EBMLidList[EBML_ID_TARGETS] = 'Targets'; - $EBMLidList[EBML_ID_TARGETTYPE] = 'TargetType'; - $EBMLidList[EBML_ID_TARGETTYPEVALUE] = 'TargetTypeValue'; - $EBMLidList[EBML_ID_TIMECODESCALE] = 'TimecodeScale'; - $EBMLidList[EBML_ID_TITLE] = 'Title'; - $EBMLidList[EBML_ID_TRACKENTRY] = 'TrackEntry'; - $EBMLidList[EBML_ID_TRACKNUMBER] = 'TrackNumber'; - $EBMLidList[EBML_ID_TRACKOFFSET] = 'TrackOffset'; - $EBMLidList[EBML_ID_TRACKOVERLAY] = 'TrackOverlay'; - $EBMLidList[EBML_ID_TRACKS] = 'Tracks'; - $EBMLidList[EBML_ID_TRACKTIMECODESCALE] = 'TrackTimecodeScale'; - $EBMLidList[EBML_ID_TRACKTRANSLATE] = 'TrackTranslate'; - $EBMLidList[EBML_ID_TRACKTRANSLATECODEC] = 'TrackTranslateCodec'; - $EBMLidList[EBML_ID_TRACKTRANSLATEEDITIONUID] = 'TrackTranslateEditionUID'; - $EBMLidList[EBML_ID_TRACKTRANSLATETRACKID] = 'TrackTranslateTrackID'; - $EBMLidList[EBML_ID_TRACKTYPE] = 'TrackType'; - $EBMLidList[EBML_ID_TRACKUID] = 'TrackUID'; - $EBMLidList[EBML_ID_VIDEO] = 'Video'; - $EBMLidList[EBML_ID_VOID] = 'Void'; - $EBMLidList[EBML_ID_WRITINGAPP] = 'WritingApp'; - } - - return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value)); - } - - public static function displayUnit($value) { - // http://www.matroska.org/technical/specs/index.html#DisplayUnit - static $units = array( - 0 => 'pixels', - 1 => 'centimeters', - 2 => 'inches', - 3 => 'Display Aspect Ratio'); - - return (isset($units[$value]) ? $units[$value] : 'unknown'); - } - - private static function getDefaultStreamInfo($streams) - { - foreach (array_reverse($streams) as $stream) { - if ($stream['default']) { - break; - } - } - - $unset = array('default', 'name'); - foreach ($unset as $u) { - if (isset($stream[$u])) { - unset($stream[$u]); - } - } - - $info = $stream; - $info['streams'] = $streams; - - return $info; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.matriska.php // +// module for analyzing Matroska containers // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +define('EBML_ID_CHAPTERS', 0x0043A770); // [10][43][A7][70] -- A system to define basic menus and partition data. For more detailed information, look at the Chapters Explanation. +define('EBML_ID_SEEKHEAD', 0x014D9B74); // [11][4D][9B][74] -- Contains the position of other level 1 elements. +define('EBML_ID_TAGS', 0x0254C367); // [12][54][C3][67] -- Element containing elements specific to Tracks/Chapters. A list of valid tags can be found . +define('EBML_ID_INFO', 0x0549A966); // [15][49][A9][66] -- Contains miscellaneous general information and statistics on the file. +define('EBML_ID_TRACKS', 0x0654AE6B); // [16][54][AE][6B] -- A top-level block of information with many tracks described. +define('EBML_ID_SEGMENT', 0x08538067); // [18][53][80][67] -- This element contains all other top-level (level 1) elements. Typically a Matroska file is composed of 1 segment. +define('EBML_ID_ATTACHMENTS', 0x0941A469); // [19][41][A4][69] -- Contain attached files. +define('EBML_ID_EBML', 0x0A45DFA3); // [1A][45][DF][A3] -- Set the EBML characteristics of the data to follow. Each EBML document has to start with this. +define('EBML_ID_CUES', 0x0C53BB6B); // [1C][53][BB][6B] -- A top-level element to speed seeking access. All entries are local to the segment. +define('EBML_ID_CLUSTER', 0x0F43B675); // [1F][43][B6][75] -- The lower level element containing the (monolithic) Block structure. +define('EBML_ID_LANGUAGE', 0x02B59C); // [22][B5][9C] -- Specifies the language of the track in the Matroska languages form. +define('EBML_ID_TRACKTIMECODESCALE', 0x03314F); // [23][31][4F] -- The scale to apply on this track to work at normal speed in relation with other tracks (mostly used to adjust video speed when the audio length differs). +define('EBML_ID_DEFAULTDURATION', 0x03E383); // [23][E3][83] -- Number of nanoseconds (i.e. not scaled) per frame. +define('EBML_ID_CODECNAME', 0x058688); // [25][86][88] -- A human-readable string specifying the codec. +define('EBML_ID_CODECDOWNLOADURL', 0x06B240); // [26][B2][40] -- A URL to download about the codec used. +define('EBML_ID_TIMECODESCALE', 0x0AD7B1); // [2A][D7][B1] -- Timecode scale in nanoseconds (1.000.000 means all timecodes in the segment are expressed in milliseconds). +define('EBML_ID_COLOURSPACE', 0x0EB524); // [2E][B5][24] -- Same value as in AVI (32 bits). +define('EBML_ID_GAMMAVALUE', 0x0FB523); // [2F][B5][23] -- Gamma Value. +define('EBML_ID_CODECSETTINGS', 0x1A9697); // [3A][96][97] -- A string describing the encoding setting used. +define('EBML_ID_CODECINFOURL', 0x1B4040); // [3B][40][40] -- A URL to find information about the codec used. +define('EBML_ID_PREVFILENAME', 0x1C83AB); // [3C][83][AB] -- An escaped filename corresponding to the previous segment. +define('EBML_ID_PREVUID', 0x1CB923); // [3C][B9][23] -- A unique ID to identify the previous chained segment (128 bits). +define('EBML_ID_NEXTFILENAME', 0x1E83BB); // [3E][83][BB] -- An escaped filename corresponding to the next segment. +define('EBML_ID_NEXTUID', 0x1EB923); // [3E][B9][23] -- A unique ID to identify the next chained segment (128 bits). +define('EBML_ID_CONTENTCOMPALGO', 0x0254); // [42][54] -- The compression algorithm used. Algorithms that have been specified so far are: +define('EBML_ID_CONTENTCOMPSETTINGS', 0x0255); // [42][55] -- Settings that might be needed by the decompressor. For Header Stripping (ContentCompAlgo=3), the bytes that were removed from the beggining of each frames of the track. +define('EBML_ID_DOCTYPE', 0x0282); // [42][82] -- A string that describes the type of document that follows this EBML header ('matroska' in our case). +define('EBML_ID_DOCTYPEREADVERSION', 0x0285); // [42][85] -- The minimum DocType version an interpreter has to support to read this file. +define('EBML_ID_EBMLVERSION', 0x0286); // [42][86] -- The version of EBML parser used to create the file. +define('EBML_ID_DOCTYPEVERSION', 0x0287); // [42][87] -- The version of DocType interpreter used to create the file. +define('EBML_ID_EBMLMAXIDLENGTH', 0x02F2); // [42][F2] -- The maximum length of the IDs you'll find in this file (4 or less in Matroska). +define('EBML_ID_EBMLMAXSIZELENGTH', 0x02F3); // [42][F3] -- The maximum length of the sizes you'll find in this file (8 or less in Matroska). This does not override the element size indicated at the beginning of an element. Elements that have an indicated size which is larger than what is allowed by EBMLMaxSizeLength shall be considered invalid. +define('EBML_ID_EBMLREADVERSION', 0x02F7); // [42][F7] -- The minimum EBML version a parser has to support to read this file. +define('EBML_ID_CHAPLANGUAGE', 0x037C); // [43][7C] -- The languages corresponding to the string, in the bibliographic ISO-639-2 form. +define('EBML_ID_CHAPCOUNTRY', 0x037E); // [43][7E] -- The countries corresponding to the string, same 2 octets as in Internet domains. +define('EBML_ID_SEGMENTFAMILY', 0x0444); // [44][44] -- A randomly generated unique ID that all segments related to each other must use (128 bits). +define('EBML_ID_DATEUTC', 0x0461); // [44][61] -- Date of the origin of timecode (value 0), i.e. production date. +define('EBML_ID_TAGLANGUAGE', 0x047A); // [44][7A] -- Specifies the language of the tag specified, in the Matroska languages form. +define('EBML_ID_TAGDEFAULT', 0x0484); // [44][84] -- Indication to know if this is the default/original language to use for the given tag. +define('EBML_ID_TAGBINARY', 0x0485); // [44][85] -- The values of the Tag if it is binary. Note that this cannot be used in the same SimpleTag as TagString. +define('EBML_ID_TAGSTRING', 0x0487); // [44][87] -- The value of the Tag. +define('EBML_ID_DURATION', 0x0489); // [44][89] -- Duration of the segment (based on TimecodeScale). +define('EBML_ID_CHAPPROCESSPRIVATE', 0x050D); // [45][0D] -- Some optional data attached to the ChapProcessCodecID information. For ChapProcessCodecID = 1, it is the "DVD level" equivalent. +define('EBML_ID_CHAPTERFLAGENABLED', 0x0598); // [45][98] -- Specify wether the chapter is enabled. It can be enabled/disabled by a Control Track. When disabled, the movie should skip all the content between the TimeStart and TimeEnd of this chapter. +define('EBML_ID_TAGNAME', 0x05A3); // [45][A3] -- The name of the Tag that is going to be stored. +define('EBML_ID_EDITIONENTRY', 0x05B9); // [45][B9] -- Contains all information about a segment edition. +define('EBML_ID_EDITIONUID', 0x05BC); // [45][BC] -- A unique ID to identify the edition. It's useful for tagging an edition. +define('EBML_ID_EDITIONFLAGHIDDEN', 0x05BD); // [45][BD] -- If an edition is hidden (1), it should not be available to the user interface (but still to Control Tracks). +define('EBML_ID_EDITIONFLAGDEFAULT', 0x05DB); // [45][DB] -- If a flag is set (1) the edition should be used as the default one. +define('EBML_ID_EDITIONFLAGORDERED', 0x05DD); // [45][DD] -- Specify if the chapters can be defined multiple times and the order to play them is enforced. +define('EBML_ID_FILEDATA', 0x065C); // [46][5C] -- The data of the file. +define('EBML_ID_FILEMIMETYPE', 0x0660); // [46][60] -- MIME type of the file. +define('EBML_ID_FILENAME', 0x066E); // [46][6E] -- Filename of the attached file. +define('EBML_ID_FILEREFERRAL', 0x0675); // [46][75] -- A binary value that a track/codec can refer to when the attachment is needed. +define('EBML_ID_FILEDESCRIPTION', 0x067E); // [46][7E] -- A human-friendly name for the attached file. +define('EBML_ID_FILEUID', 0x06AE); // [46][AE] -- Unique ID representing the file, as random as possible. +define('EBML_ID_CONTENTENCALGO', 0x07E1); // [47][E1] -- The encryption algorithm used. The value '0' means that the contents have not been encrypted but only signed. Predefined values: +define('EBML_ID_CONTENTENCKEYID', 0x07E2); // [47][E2] -- For public key algorithms this is the ID of the public key the the data was encrypted with. +define('EBML_ID_CONTENTSIGNATURE', 0x07E3); // [47][E3] -- A cryptographic signature of the contents. +define('EBML_ID_CONTENTSIGKEYID', 0x07E4); // [47][E4] -- This is the ID of the private key the data was signed with. +define('EBML_ID_CONTENTSIGALGO', 0x07E5); // [47][E5] -- The algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values: +define('EBML_ID_CONTENTSIGHASHALGO', 0x07E6); // [47][E6] -- The hash algorithm used for the signature. A value of '0' means that the contents have not been signed but only encrypted. Predefined values: +define('EBML_ID_MUXINGAPP', 0x0D80); // [4D][80] -- Muxing application or library ("libmatroska-0.4.3"). +define('EBML_ID_SEEK', 0x0DBB); // [4D][BB] -- Contains a single seek entry to an EBML element. +define('EBML_ID_CONTENTENCODINGORDER', 0x1031); // [50][31] -- Tells when this modification was used during encoding/muxing starting with 0 and counting upwards. The decoder/demuxer has to start with the highest order number it finds and work its way down. This value has to be unique over all ContentEncodingOrder elements in the segment. +define('EBML_ID_CONTENTENCODINGSCOPE', 0x1032); // [50][32] -- A bit field that describes which elements have been modified in this way. Values (big endian) can be OR'ed. Possible values: +define('EBML_ID_CONTENTENCODINGTYPE', 0x1033); // [50][33] -- A value describing what kind of transformation has been done. Possible values: +define('EBML_ID_CONTENTCOMPRESSION', 0x1034); // [50][34] -- Settings describing the compression used. Must be present if the value of ContentEncodingType is 0 and absent otherwise. Each block must be decompressable even if no previous block is available in order not to prevent seeking. +define('EBML_ID_CONTENTENCRYPTION', 0x1035); // [50][35] -- Settings describing the encryption used. Must be present if the value of ContentEncodingType is 1 and absent otherwise. +define('EBML_ID_CUEREFNUMBER', 0x135F); // [53][5F] -- Number of the referenced Block of Track X in the specified Cluster. +define('EBML_ID_NAME', 0x136E); // [53][6E] -- A human-readable track name. +define('EBML_ID_CUEBLOCKNUMBER', 0x1378); // [53][78] -- Number of the Block in the specified Cluster. +define('EBML_ID_TRACKOFFSET', 0x137F); // [53][7F] -- A value to add to the Block's Timecode. This can be used to adjust the playback offset of a track. +define('EBML_ID_SEEKID', 0x13AB); // [53][AB] -- The binary ID corresponding to the element name. +define('EBML_ID_SEEKPOSITION', 0x13AC); // [53][AC] -- The position of the element in the segment in octets (0 = first level 1 element). +define('EBML_ID_STEREOMODE', 0x13B8); // [53][B8] -- Stereo-3D video mode. +define('EBML_ID_OLDSTEREOMODE', 0x13B9); // [53][B9] -- Bogus StereoMode value used in old versions of libmatroska. DO NOT USE. (0: mono, 1: right eye, 2: left eye, 3: both eyes). +define('EBML_ID_PIXELCROPBOTTOM', 0x14AA); // [54][AA] -- The number of video pixels to remove at the bottom of the image (for HDTV content). +define('EBML_ID_DISPLAYWIDTH', 0x14B0); // [54][B0] -- Width of the video frames to display. +define('EBML_ID_DISPLAYUNIT', 0x14B2); // [54][B2] -- Type of the unit for DisplayWidth/Height (0: pixels, 1: centimeters, 2: inches). +define('EBML_ID_ASPECTRATIOTYPE', 0x14B3); // [54][B3] -- Specify the possible modifications to the aspect ratio (0: free resizing, 1: keep aspect ratio, 2: fixed). +define('EBML_ID_DISPLAYHEIGHT', 0x14BA); // [54][BA] -- Height of the video frames to display. +define('EBML_ID_PIXELCROPTOP', 0x14BB); // [54][BB] -- The number of video pixels to remove at the top of the image. +define('EBML_ID_PIXELCROPLEFT', 0x14CC); // [54][CC] -- The number of video pixels to remove on the left of the image. +define('EBML_ID_PIXELCROPRIGHT', 0x14DD); // [54][DD] -- The number of video pixels to remove on the right of the image. +define('EBML_ID_FLAGFORCED', 0x15AA); // [55][AA] -- Set if that track MUST be used during playback. There can be many forced track for a kind (audio, video or subs), the player should select the one which language matches the user preference or the default + forced track. Overlay MAY happen between a forced and non-forced track of the same kind. +define('EBML_ID_MAXBLOCKADDITIONID', 0x15EE); // [55][EE] -- The maximum value of BlockAddID. A value 0 means there is no BlockAdditions for this track. +define('EBML_ID_WRITINGAPP', 0x1741); // [57][41] -- Writing application ("mkvmerge-0.3.3"). +define('EBML_ID_CLUSTERSILENTTRACKS', 0x1854); // [58][54] -- The list of tracks that are not used in that part of the stream. It is useful when using overlay tracks on seeking. Then you should decide what track to use. +define('EBML_ID_CLUSTERSILENTTRACKNUMBER', 0x18D7); // [58][D7] -- One of the track number that are not used from now on in the stream. It could change later if not specified as silent in a further Cluster. +define('EBML_ID_ATTACHEDFILE', 0x21A7); // [61][A7] -- An attached file. +define('EBML_ID_CONTENTENCODING', 0x2240); // [62][40] -- Settings for one content encoding like compression or encryption. +define('EBML_ID_BITDEPTH', 0x2264); // [62][64] -- Bits per sample, mostly used for PCM. +define('EBML_ID_CODECPRIVATE', 0x23A2); // [63][A2] -- Private data only known to the codec. +define('EBML_ID_TARGETS', 0x23C0); // [63][C0] -- Contain all UIDs where the specified meta data apply. It is void to describe everything in the segment. +define('EBML_ID_CHAPTERPHYSICALEQUIV', 0x23C3); // [63][C3] -- Specify the physical equivalent of this ChapterAtom like "DVD" (60) or "SIDE" (50), see complete list of values. +define('EBML_ID_TAGCHAPTERUID', 0x23C4); // [63][C4] -- A unique ID to identify the Chapter(s) the tags belong to. If the value is 0 at this level, the tags apply to all chapters in the Segment. +define('EBML_ID_TAGTRACKUID', 0x23C5); // [63][C5] -- A unique ID to identify the Track(s) the tags belong to. If the value is 0 at this level, the tags apply to all tracks in the Segment. +define('EBML_ID_TAGATTACHMENTUID', 0x23C6); // [63][C6] -- A unique ID to identify the Attachment(s) the tags belong to. If the value is 0 at this level, the tags apply to all the attachments in the Segment. +define('EBML_ID_TAGEDITIONUID', 0x23C9); // [63][C9] -- A unique ID to identify the EditionEntry(s) the tags belong to. If the value is 0 at this level, the tags apply to all editions in the Segment. +define('EBML_ID_TARGETTYPE', 0x23CA); // [63][CA] -- An informational string that can be used to display the logical level of the target like "ALBUM", "TRACK", "MOVIE", "CHAPTER", etc (see TargetType). +define('EBML_ID_TRACKTRANSLATE', 0x2624); // [66][24] -- The track identification for the given Chapter Codec. +define('EBML_ID_TRACKTRANSLATETRACKID', 0x26A5); // [66][A5] -- The binary value used to represent this track in the chapter codec data. The format depends on the ChapProcessCodecID used. +define('EBML_ID_TRACKTRANSLATECODEC', 0x26BF); // [66][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu). +define('EBML_ID_TRACKTRANSLATEEDITIONUID', 0x26FC); // [66][FC] -- Specify an edition UID on which this translation applies. When not specified, it means for all editions found in the segment. +define('EBML_ID_SIMPLETAG', 0x27C8); // [67][C8] -- Contains general information about the target. +define('EBML_ID_TARGETTYPEVALUE', 0x28CA); // [68][CA] -- A number to indicate the logical level of the target (see TargetType). +define('EBML_ID_CHAPPROCESSCOMMAND', 0x2911); // [69][11] -- Contains all the commands associated to the Atom. +define('EBML_ID_CHAPPROCESSTIME', 0x2922); // [69][22] -- Defines when the process command should be handled (0: during the whole chapter, 1: before starting playback, 2: after playback of the chapter). +define('EBML_ID_CHAPTERTRANSLATE', 0x2924); // [69][24] -- A tuple of corresponding ID used by chapter codecs to represent this segment. +define('EBML_ID_CHAPPROCESSDATA', 0x2933); // [69][33] -- Contains the command information. The data should be interpreted depending on the ChapProcessCodecID value. For ChapProcessCodecID = 1, the data correspond to the binary DVD cell pre/post commands. +define('EBML_ID_CHAPPROCESS', 0x2944); // [69][44] -- Contains all the commands associated to the Atom. +define('EBML_ID_CHAPPROCESSCODECID', 0x2955); // [69][55] -- Contains the type of the codec used for the processing. A value of 0 means native Matroska processing (to be defined), a value of 1 means the DVD command set is used. More codec IDs can be added later. +define('EBML_ID_CHAPTERTRANSLATEID', 0x29A5); // [69][A5] -- The binary value used to represent this segment in the chapter codec data. The format depends on the ChapProcessCodecID used. +define('EBML_ID_CHAPTERTRANSLATECODEC', 0x29BF); // [69][BF] -- The chapter codec using this ID (0: Matroska Script, 1: DVD-menu). +define('EBML_ID_CHAPTERTRANSLATEEDITIONUID', 0x29FC); // [69][FC] -- Specify an edition UID on which this correspondance applies. When not specified, it means for all editions found in the segment. +define('EBML_ID_CONTENTENCODINGS', 0x2D80); // [6D][80] -- Settings for several content encoding mechanisms like compression or encryption. +define('EBML_ID_MINCACHE', 0x2DE7); // [6D][E7] -- The minimum number of frames a player should be able to cache during playback. If set to 0, the reference pseudo-cache system is not used. +define('EBML_ID_MAXCACHE', 0x2DF8); // [6D][F8] -- The maximum cache size required to store referenced frames in and the current frame. 0 means no cache is needed. +define('EBML_ID_CHAPTERSEGMENTUID', 0x2E67); // [6E][67] -- A segment to play in place of this chapter. Edition ChapterSegmentEditionUID should be used for this segment, otherwise no edition is used. +define('EBML_ID_CHAPTERSEGMENTEDITIONUID', 0x2EBC); // [6E][BC] -- The edition to play from the segment linked in ChapterSegmentUID. +define('EBML_ID_TRACKOVERLAY', 0x2FAB); // [6F][AB] -- Specify that this track is an overlay track for the Track specified (in the u-integer). That means when this track has a gap (see SilentTracks) the overlay track should be used instead. The order of multiple TrackOverlay matters, the first one is the one that should be used. If not found it should be the second, etc. +define('EBML_ID_TAG', 0x3373); // [73][73] -- Element containing elements specific to Tracks/Chapters. +define('EBML_ID_SEGMENTFILENAME', 0x3384); // [73][84] -- A filename corresponding to this segment. +define('EBML_ID_SEGMENTUID', 0x33A4); // [73][A4] -- A randomly generated unique ID to identify the current segment between many others (128 bits). +define('EBML_ID_CHAPTERUID', 0x33C4); // [73][C4] -- A unique ID to identify the Chapter. +define('EBML_ID_TRACKUID', 0x33C5); // [73][C5] -- A unique ID to identify the Track. This should be kept the same when making a direct stream copy of the Track to another file. +define('EBML_ID_ATTACHMENTLINK', 0x3446); // [74][46] -- The UID of an attachment that is used by this codec. +define('EBML_ID_CLUSTERBLOCKADDITIONS', 0x35A1); // [75][A1] -- Contain additional blocks to complete the main one. An EBML parser that has no knowledge of the Block structure could still see and use/skip these data. +define('EBML_ID_CHANNELPOSITIONS', 0x347B); // [7D][7B] -- Table of horizontal angles for each successive channel, see appendix. +define('EBML_ID_OUTPUTSAMPLINGFREQUENCY', 0x38B5); // [78][B5] -- Real output sampling frequency in Hz (used for SBR techniques). +define('EBML_ID_TITLE', 0x3BA9); // [7B][A9] -- General name of the segment. +define('EBML_ID_CHAPTERDISPLAY', 0x00); // [80] -- Contains all possible strings to use for the chapter display. +define('EBML_ID_TRACKTYPE', 0x03); // [83] -- A set of track types coded on 8 bits (1: video, 2: audio, 3: complex, 0x10: logo, 0x11: subtitle, 0x12: buttons, 0x20: control). +define('EBML_ID_CHAPSTRING', 0x05); // [85] -- Contains the string to use as the chapter atom. +define('EBML_ID_CODECID', 0x06); // [86] -- An ID corresponding to the codec, see the codec page for more info. +define('EBML_ID_FLAGDEFAULT', 0x08); // [88] -- Set if that track (audio, video or subs) SHOULD be used if no language found matches the user preference. +define('EBML_ID_CHAPTERTRACKNUMBER', 0x09); // [89] -- UID of the Track to apply this chapter too. In the absense of a control track, choosing this chapter will select the listed Tracks and deselect unlisted tracks. Absense of this element indicates that the Chapter should be applied to any currently used Tracks. +define('EBML_ID_CLUSTERSLICES', 0x0E); // [8E] -- Contains slices description. +define('EBML_ID_CHAPTERTRACK', 0x0F); // [8F] -- List of tracks on which the chapter applies. If this element is not present, all tracks apply +define('EBML_ID_CHAPTERTIMESTART', 0x11); // [91] -- Timecode of the start of Chapter (not scaled). +define('EBML_ID_CHAPTERTIMEEND', 0x12); // [92] -- Timecode of the end of Chapter (timecode excluded, not scaled). +define('EBML_ID_CUEREFTIME', 0x16); // [96] -- Timecode of the referenced Block. +define('EBML_ID_CUEREFCLUSTER', 0x17); // [97] -- Position of the Cluster containing the referenced Block. +define('EBML_ID_CHAPTERFLAGHIDDEN', 0x18); // [98] -- If a chapter is hidden (1), it should not be available to the user interface (but still to Control Tracks). +define('EBML_ID_FLAGINTERLACED', 0x1A); // [9A] -- Set if the video is interlaced. +define('EBML_ID_CLUSTERBLOCKDURATION', 0x1B); // [9B] -- The duration of the Block (based on TimecodeScale). This element is mandatory when DefaultDuration is set for the track. When not written and with no DefaultDuration, the value is assumed to be the difference between the timecode of this Block and the timecode of the next Block in "display" order (not coding order). This element can be useful at the end of a Track (as there is not other Block available), or when there is a break in a track like for subtitle tracks. +define('EBML_ID_FLAGLACING', 0x1C); // [9C] -- Set if the track may contain blocks using lacing. +define('EBML_ID_CHANNELS', 0x1F); // [9F] -- Numbers of channels in the track. +define('EBML_ID_CLUSTERBLOCKGROUP', 0x20); // [A0] -- Basic container of information containing a single Block or BlockVirtual, and information specific to that Block/VirtualBlock. +define('EBML_ID_CLUSTERBLOCK', 0x21); // [A1] -- Block containing the actual data to be rendered and a timecode relative to the Cluster Timecode. +define('EBML_ID_CLUSTERBLOCKVIRTUAL', 0x22); // [A2] -- A Block with no data. It must be stored in the stream at the place the real Block should be in display order. +define('EBML_ID_CLUSTERSIMPLEBLOCK', 0x23); // [A3] -- Similar to Block but without all the extra information, mostly used to reduced overhead when no extra feature is needed. +define('EBML_ID_CLUSTERCODECSTATE', 0x24); // [A4] -- The new codec state to use. Data interpretation is private to the codec. This information should always be referenced by a seek entry. +define('EBML_ID_CLUSTERBLOCKADDITIONAL', 0x25); // [A5] -- Interpreted by the codec as it wishes (using the BlockAddID). +define('EBML_ID_CLUSTERBLOCKMORE', 0x26); // [A6] -- Contain the BlockAdditional and some parameters. +define('EBML_ID_CLUSTERPOSITION', 0x27); // [A7] -- Position of the Cluster in the segment (0 in live broadcast streams). It might help to resynchronise offset on damaged streams. +define('EBML_ID_CODECDECODEALL', 0x2A); // [AA] -- The codec can decode potentially damaged data. +define('EBML_ID_CLUSTERPREVSIZE', 0x2B); // [AB] -- Size of the previous Cluster, in octets. Can be useful for backward playing. +define('EBML_ID_TRACKENTRY', 0x2E); // [AE] -- Describes a track with all elements. +define('EBML_ID_CLUSTERENCRYPTEDBLOCK', 0x2F); // [AF] -- Similar to SimpleBlock but the data inside the Block are Transformed (encrypt and/or signed). +define('EBML_ID_PIXELWIDTH', 0x30); // [B0] -- Width of the encoded video frames in pixels. +define('EBML_ID_CUETIME', 0x33); // [B3] -- Absolute timecode according to the segment time base. +define('EBML_ID_SAMPLINGFREQUENCY', 0x35); // [B5] -- Sampling frequency in Hz. +define('EBML_ID_CHAPTERATOM', 0x36); // [B6] -- Contains the atom information to use as the chapter atom (apply to all tracks). +define('EBML_ID_CUETRACKPOSITIONS', 0x37); // [B7] -- Contain positions for different tracks corresponding to the timecode. +define('EBML_ID_FLAGENABLED', 0x39); // [B9] -- Set if the track is used. +define('EBML_ID_PIXELHEIGHT', 0x3A); // [BA] -- Height of the encoded video frames in pixels. +define('EBML_ID_CUEPOINT', 0x3B); // [BB] -- Contains all information relative to a seek point in the segment. +define('EBML_ID_CRC32', 0x3F); // [BF] -- The CRC is computed on all the data of the Master element it's in, regardless of its position. It's recommended to put the CRC value at the beggining of the Master element for easier reading. All level 1 elements should include a CRC-32. +define('EBML_ID_CLUSTERBLOCKADDITIONID', 0x4B); // [CB] -- The ID of the BlockAdditional element (0 is the main Block). +define('EBML_ID_CLUSTERLACENUMBER', 0x4C); // [CC] -- The reverse number of the frame in the lace (0 is the last frame, 1 is the next to last, etc). While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback. +define('EBML_ID_CLUSTERFRAMENUMBER', 0x4D); // [CD] -- The number of the frame to generate from this lace with this delay (allow you to generate many frames from the same Block/Frame). +define('EBML_ID_CLUSTERDELAY', 0x4E); // [CE] -- The (scaled) delay to apply to the element. +define('EBML_ID_CLUSTERDURATION', 0x4F); // [CF] -- The (scaled) duration to apply to the element. +define('EBML_ID_TRACKNUMBER', 0x57); // [D7] -- The track number as used in the Block Header (using more than 127 tracks is not encouraged, though the design allows an unlimited number). +define('EBML_ID_CUEREFERENCE', 0x5B); // [DB] -- The Clusters containing the required referenced Blocks. +define('EBML_ID_VIDEO', 0x60); // [E0] -- Video settings. +define('EBML_ID_AUDIO', 0x61); // [E1] -- Audio settings. +define('EBML_ID_CLUSTERTIMESLICE', 0x68); // [E8] -- Contains extra time information about the data contained in the Block. While there are a few files in the wild with this element, it is no longer in use and has been deprecated. Being able to interpret this element is not required for playback. +define('EBML_ID_CUECODECSTATE', 0x6A); // [EA] -- The position of the Codec State corresponding to this Cue element. 0 means that the data is taken from the initial Track Entry. +define('EBML_ID_CUEREFCODECSTATE', 0x6B); // [EB] -- The position of the Codec State corresponding to this referenced element. 0 means that the data is taken from the initial Track Entry. +define('EBML_ID_VOID', 0x6C); // [EC] -- Used to void damaged data, to avoid unexpected behaviors when using damaged data. The content is discarded. Also used to reserve space in a sub-element for later use. +define('EBML_ID_CLUSTERTIMECODE', 0x67); // [E7] -- Absolute timecode of the cluster (based on TimecodeScale). +define('EBML_ID_CLUSTERBLOCKADDID', 0x6E); // [EE] -- An ID to identify the BlockAdditional level. +define('EBML_ID_CUECLUSTERPOSITION', 0x71); // [F1] -- The position of the Cluster containing the required Block. +define('EBML_ID_CUETRACK', 0x77); // [F7] -- The track for which a position is given. +define('EBML_ID_CLUSTERREFERENCEPRIORITY', 0x7A); // [FA] -- This frame is referenced and has the specified cache priority. In cache only a frame of the same or higher priority can replace this frame. A value of 0 means the frame is not referenced. +define('EBML_ID_CLUSTERREFERENCEBLOCK', 0x7B); // [FB] -- Timecode of another frame used as a reference (ie: B or P frame). The timecode is relative to the block it's attached to. +define('EBML_ID_CLUSTERREFERENCEVIRTUAL', 0x7D); // [FD] -- Relative position of the data that should be in position of the virtual block. + + +/** +* @tutorial http://www.matroska.org/technical/specs/index.html +* +* @todo Rewrite EBML parser to reduce it's size and honor default element values +* @todo After rewrite implement stream size calculation, that will provide additional useful info and enable AAC/FLAC audio bitrate detection +*/ +class getid3_matroska extends getid3_handler +{ + // public options + public static $hide_clusters = true; // if true, do not return information about CLUSTER chunks, since there's a lot of them and they're not usually useful [default: TRUE] + public static $parse_whole_file = false; // true to parse the whole file, not only header [default: FALSE] + + // private parser settings/placeholders + private $EBMLbuffer = ''; + private $EBMLbuffer_offset = 0; + private $EBMLbuffer_length = 0; + private $current_offset = 0; + private $unuseful_elements = array(EBML_ID_CRC32, EBML_ID_VOID); + + public function Analyze() + { + $info = &$this->getid3->info; + + // parse container + try { + $this->parseEBML($info); + } catch (Exception $e) { + $info['error'][] = 'EBML parser: '.$e->getMessage(); + } + + // calculate playtime + if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { + foreach ($info['matroska']['info'] as $key => $infoarray) { + if (isset($infoarray['Duration'])) { + // TimecodeScale is how many nanoseconds each Duration unit is + $info['playtime_seconds'] = $infoarray['Duration'] * ((isset($infoarray['TimecodeScale']) ? $infoarray['TimecodeScale'] : 1000000) / 1000000000); + break; + } + } + } + + // extract tags + if (isset($info['matroska']['tags']) && is_array($info['matroska']['tags'])) { + foreach ($info['matroska']['tags'] as $key => $infoarray) { + $this->ExtractCommentsSimpleTag($infoarray); + } + } + + // process tracks + if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { + foreach ($info['matroska']['tracks']['tracks'] as $key => $trackarray) { + + $track_info = array(); + $track_info['dataformat'] = self::CodecIDtoCommonName($trackarray['CodecID']); + $track_info['default'] = (isset($trackarray['FlagDefault']) ? $trackarray['FlagDefault'] : true); + if (isset($trackarray['Name'])) { $track_info['name'] = $trackarray['Name']; } + + switch ($trackarray['TrackType']) { + + case 1: // Video + $track_info['resolution_x'] = $trackarray['PixelWidth']; + $track_info['resolution_y'] = $trackarray['PixelHeight']; + $track_info['display_unit'] = self::displayUnit(isset($trackarray['DisplayUnit']) ? $trackarray['DisplayUnit'] : 0); + $track_info['display_x'] = (isset($trackarray['DisplayWidth']) ? $trackarray['DisplayWidth'] : $trackarray['PixelWidth']); + $track_info['display_y'] = (isset($trackarray['DisplayHeight']) ? $trackarray['DisplayHeight'] : $trackarray['PixelHeight']); + + if (isset($trackarray['PixelCropBottom'])) { $track_info['crop_bottom'] = $trackarray['PixelCropBottom']; } + if (isset($trackarray['PixelCropTop'])) { $track_info['crop_top'] = $trackarray['PixelCropTop']; } + if (isset($trackarray['PixelCropLeft'])) { $track_info['crop_left'] = $trackarray['PixelCropLeft']; } + if (isset($trackarray['PixelCropRight'])) { $track_info['crop_right'] = $trackarray['PixelCropRight']; } + if (isset($trackarray['DefaultDuration'])) { $track_info['frame_rate'] = round(1000000000 / $trackarray['DefaultDuration'], 3); } + if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } + + switch ($trackarray['CodecID']) { + case 'V_MS/VFW/FOURCC': + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) { + $this->warning('Unable to parse codec private data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"'); + break; + } + $parsed = getid3_riff::ParseBITMAPINFOHEADER($trackarray['CodecPrivate']); + $track_info['codec'] = getid3_riff::fourccLookup($parsed['fourcc']); + $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; + break; + + /*case 'V_MPEG4/ISO/AVC': + $h264['profile'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 1, 1)); + $h264['level'] = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 3, 1)); + $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 4, 1)); + $h264['NALUlength'] = ($rn & 3) + 1; + $rn = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], 5, 1)); + $nsps = ($rn & 31); + $offset = 6; + for ($i = 0; $i < $nsps; $i ++) { + $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); + $h264['SPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); + $offset += 2 + $length; + } + $npps = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 1)); + $offset += 1; + for ($i = 0; $i < $npps; $i ++) { + $length = getid3_lib::BigEndian2Int(substr($trackarray['CodecPrivate'], $offset, 2)); + $h264['PPS'][] = substr($trackarray['CodecPrivate'], $offset + 2, $length); + $offset += 2 + $length; + } + $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $h264; + break;*/ + } + + $info['video']['streams'][] = $track_info; + break; + + case 2: // Audio + $track_info['sample_rate'] = (isset($trackarray['SamplingFrequency']) ? $trackarray['SamplingFrequency'] : 8000.0); + $track_info['channels'] = (isset($trackarray['Channels']) ? $trackarray['Channels'] : 1); + $track_info['language'] = (isset($trackarray['Language']) ? $trackarray['Language'] : 'eng'); + if (isset($trackarray['BitDepth'])) { $track_info['bits_per_sample'] = $trackarray['BitDepth']; } + if (isset($trackarray['CodecName'])) { $track_info['codec'] = $trackarray['CodecName']; } + + switch ($trackarray['CodecID']) { + case 'A_PCM/INT/LIT': + case 'A_PCM/INT/BIG': + $track_info['bitrate'] = $trackarray['SamplingFrequency'] * $trackarray['Channels'] * $trackarray['BitDepth']; + break; + + case 'A_AC3': + case 'A_DTS': + case 'A_MPEG/L3': + case 'A_MPEG/L2': + case 'A_FLAC': + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']).'.php', __FILE__, false)) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.'.$track_info['dataformat'].'.php"'); + break; + } + + if (!isset($info['matroska']['track_data_offsets'][$trackarray['TrackNumber']])) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because $info[matroska][track_data_offsets]['.$trackarray['TrackNumber'].'] not set'); + break; + } + + // create temp instance + $getid3_temp = new getID3(); + if ($track_info['dataformat'] != 'flac') { + $getid3_temp->openfile($this->getid3->filename); + } + $getid3_temp->info['avdataoffset'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset']; + if ($track_info['dataformat'][0] == 'm' || $track_info['dataformat'] == 'flac') { + $getid3_temp->info['avdataend'] = $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['offset'] + $info['matroska']['track_data_offsets'][$trackarray['TrackNumber']]['length']; + } + + // analyze + $class = 'getid3_'.($track_info['dataformat'] == 'mp2' ? 'mp3' : $track_info['dataformat']); + $header_data_key = $track_info['dataformat'][0] == 'm' ? 'mpeg' : $track_info['dataformat']; + $getid3_audio = new $class($getid3_temp, __CLASS__); + if ($track_info['dataformat'] == 'flac') { + $getid3_audio->AnalyzeString($trackarray['CodecPrivate']); + } + else { + $getid3_audio->Analyze(); + } + if (!empty($getid3_temp->info[$header_data_key])) { + $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info[$header_data_key]; + if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { + foreach ($getid3_temp->info['audio'] as $key => $value) { + $track_info[$key] = $value; + } + } + } + else { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because '.$class.'::Analyze() failed at offset '.$getid3_temp->info['avdataoffset']); + } + + // copy errors and warnings + if (!empty($getid3_temp->info['error'])) { + foreach ($getid3_temp->info['error'] as $newerror) { + $this->warning($class.'() says: ['.$newerror.']'); + } + } + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $newerror) { + if ($track_info['dataformat'] == 'mp3' && preg_match('/^Probable truncated file: expecting \d+ bytes of audio data, only found \d+ \(short by \d+ bytes\)$/', $newerror)) { + // LAME/Xing header is probably set, but audio data is chunked into Matroska file and near-impossible to verify if audio stream is complete, so ignore useless warning + continue; + } + $this->warning($class.'() says: ['.$newerror.']'); + } + } + unset($getid3_temp, $getid3_audio); + break; + + case 'A_AAC': + case 'A_AAC/MPEG2/LC': + case 'A_AAC/MPEG2/LC/SBR': + case 'A_AAC/MPEG4/LC': + case 'A_AAC/MPEG4/LC/SBR': + $this->warning($trackarray['CodecID'].' audio data contains no header, audio/video bitrates can\'t be calculated'); + break; + + case 'A_VORBIS': + if (!isset($trackarray['CodecPrivate'])) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data not set'); + break; + } + $vorbis_offset = strpos($trackarray['CodecPrivate'], 'vorbis', 1); + if ($vorbis_offset === false) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because CodecPrivate data does not contain "vorbis" keyword'); + break; + } + $vorbis_offset -= 1; + + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, false)) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio.ogg.php"'); + break; + } + + // create temp instance + $getid3_temp = new getID3(); + + // analyze + $getid3_ogg = new getid3_ogg($getid3_temp); + $oggpageinfo['page_seqno'] = 0; + $getid3_ogg->ParseVorbisPageHeader($trackarray['CodecPrivate'], $vorbis_offset, $oggpageinfo); + if (!empty($getid3_temp->info['ogg'])) { + $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $getid3_temp->info['ogg']; + if (isset($getid3_temp->info['audio']) && is_array($getid3_temp->info['audio'])) { + foreach ($getid3_temp->info['audio'] as $key => $value) { + $track_info[$key] = $value; + } + } + } + + // copy errors and warnings + if (!empty($getid3_temp->info['error'])) { + foreach ($getid3_temp->info['error'] as $newerror) { + $this->warning('getid3_ogg() says: ['.$newerror.']'); + } + } + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $newerror) { + $this->warning('getid3_ogg() says: ['.$newerror.']'); + } + } + + if (!empty($getid3_temp->info['ogg']['bitrate_nominal'])) { + $track_info['bitrate'] = $getid3_temp->info['ogg']['bitrate_nominal']; + } + unset($getid3_temp, $getid3_ogg, $oggpageinfo, $vorbis_offset); + break; + + case 'A_MS/ACM': + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, false)) { + $this->warning('Unable to parse audio data ['.basename(__FILE__).':'.__LINE__.'] because cannot include "module.audio-video.riff.php"'); + break; + } + + $parsed = getid3_riff::parseWAVEFORMATex($trackarray['CodecPrivate']); + foreach ($parsed as $key => $value) { + if ($key != 'raw') { + $track_info[$key] = $value; + } + } + $info['matroska']['track_codec_parsed'][$trackarray['TrackNumber']] = $parsed; + break; + + default: + $this->warning('Unhandled audio type "'.(isset($trackarray['CodecID']) ? $trackarray['CodecID'] : '').'"'); + } + + $info['audio']['streams'][] = $track_info; + break; + } + } + + if (!empty($info['video']['streams'])) { + $info['video'] = self::getDefaultStreamInfo($info['video']['streams']); + } + if (!empty($info['audio']['streams'])) { + $info['audio'] = self::getDefaultStreamInfo($info['audio']['streams']); + } + } + + // process attachments + if (isset($info['matroska']['attachments']) && $this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE) { + foreach ($info['matroska']['attachments'] as $i => $entry) { + if (strpos($entry['FileMimeType'], 'image/') === 0 && !empty($entry['FileData'])) { + $info['matroska']['comments']['picture'][] = array('data' => $entry['FileData'], 'image_mime' => $entry['FileMimeType'], 'filename' => $entry['FileName']); + } + } + } + + // determine mime type + if (!empty($info['video']['streams'])) { + $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'video/webm' : 'video/x-matroska'); + } elseif (!empty($info['audio']['streams'])) { + $info['mime_type'] = ($info['matroska']['doctype'] == 'webm' ? 'audio/webm' : 'audio/x-matroska'); + } elseif (isset($info['mime_type'])) { + unset($info['mime_type']); + } + + return true; + } + + private function parseEBML(&$info) { + // http://www.matroska.org/technical/specs/index.html#EBMLBasics + $this->current_offset = $info['avdataoffset']; + + while ($this->getEBMLelement($top_element, $info['avdataend'])) { + switch ($top_element['id']) { + + case EBML_ID_EBML: + $info['fileformat'] = 'matroska'; + $info['matroska']['header']['offset'] = $top_element['offset']; + $info['matroska']['header']['length'] = $top_element['length']; + + while ($this->getEBMLelement($element_data, $top_element['end'], true)) { + switch ($element_data['id']) { + + case EBML_ID_EBMLVERSION: + case EBML_ID_EBMLREADVERSION: + case EBML_ID_EBMLMAXIDLENGTH: + case EBML_ID_EBMLMAXSIZELENGTH: + case EBML_ID_DOCTYPEVERSION: + case EBML_ID_DOCTYPEREADVERSION: + $element_data['data'] = getid3_lib::BigEndian2Int($element_data['data']); + break; + + case EBML_ID_DOCTYPE: + $element_data['data'] = getid3_lib::trimNullByte($element_data['data']); + $info['matroska']['doctype'] = $element_data['data']; + break; + + default: + $this->unhandledElement('header', __LINE__, $element_data); + } + + unset($element_data['offset'], $element_data['end']); + $info['matroska']['header']['elements'][] = $element_data; + } + break; + + case EBML_ID_SEGMENT: + $info['matroska']['segment'][0]['offset'] = $top_element['offset']; + $info['matroska']['segment'][0]['length'] = $top_element['length']; + + while ($this->getEBMLelement($element_data, $top_element['end'])) { + if ($element_data['id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required + $info['matroska']['segments'][] = $element_data; + } + switch ($element_data['id']) { + + case EBML_ID_SEEKHEAD: // Contains the position of other level 1 elements. + + while ($this->getEBMLelement($seek_entry, $element_data['end'])) { + switch ($seek_entry['id']) { + + case EBML_ID_SEEK: // Contains a single seek entry to an EBML element + while ($this->getEBMLelement($sub_seek_entry, $seek_entry['end'], true)) { + + switch ($sub_seek_entry['id']) { + + case EBML_ID_SEEKID: + $seek_entry['target_id'] = self::EBML2Int($sub_seek_entry['data']); + $seek_entry['target_name'] = self::EBMLidName($seek_entry['target_id']); + break; + + case EBML_ID_SEEKPOSITION: + $seek_entry['target_offset'] = $element_data['offset'] + getid3_lib::BigEndian2Int($sub_seek_entry['data']); + break; + + default: + $this->unhandledElement('seekhead.seek', __LINE__, $sub_seek_entry); } + } + + if ($seek_entry['target_id'] != EBML_ID_CLUSTER || !self::$hide_clusters) { // collect clusters only if required + $info['matroska']['seek'][] = $seek_entry; + } + break; + + default: + $this->unhandledElement('seekhead', __LINE__, $seek_entry); + } + } + break; + + case EBML_ID_TRACKS: // A top-level block of information with many tracks described. + $info['matroska']['tracks'] = $element_data; + + while ($this->getEBMLelement($track_entry, $element_data['end'])) { + switch ($track_entry['id']) { + + case EBML_ID_TRACKENTRY: //subelements: Describes a track with all elements. + + while ($this->getEBMLelement($subelement, $track_entry['end'], array(EBML_ID_VIDEO, EBML_ID_AUDIO, EBML_ID_CONTENTENCODINGS, EBML_ID_CODECPRIVATE))) { + switch ($subelement['id']) { + + case EBML_ID_TRACKNUMBER: + case EBML_ID_TRACKUID: + case EBML_ID_TRACKTYPE: + case EBML_ID_MINCACHE: + case EBML_ID_MAXCACHE: + case EBML_ID_MAXBLOCKADDITIONID: + case EBML_ID_DEFAULTDURATION: // nanoseconds per frame + $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); + break; + + case EBML_ID_TRACKTIMECODESCALE: + $track_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']); + break; + + case EBML_ID_CODECID: + case EBML_ID_LANGUAGE: + case EBML_ID_NAME: + case EBML_ID_CODECNAME: + $track_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); + break; + + case EBML_ID_CODECPRIVATE: + $track_entry[$subelement['id_name']] = $this->readEBMLelementData($subelement['length'], true); + break; + + case EBML_ID_FLAGENABLED: + case EBML_ID_FLAGDEFAULT: + case EBML_ID_FLAGFORCED: + case EBML_ID_FLAGLACING: + case EBML_ID_CODECDECODEALL: + $track_entry[$subelement['id_name']] = (bool) getid3_lib::BigEndian2Int($subelement['data']); + break; + + case EBML_ID_VIDEO: + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { + switch ($sub_subelement['id']) { + + case EBML_ID_PIXELWIDTH: + case EBML_ID_PIXELHEIGHT: + case EBML_ID_PIXELCROPBOTTOM: + case EBML_ID_PIXELCROPTOP: + case EBML_ID_PIXELCROPLEFT: + case EBML_ID_PIXELCROPRIGHT: + case EBML_ID_DISPLAYWIDTH: + case EBML_ID_DISPLAYHEIGHT: + case EBML_ID_DISPLAYUNIT: + case EBML_ID_ASPECTRATIOTYPE: + case EBML_ID_STEREOMODE: + case EBML_ID_OLDSTEREOMODE: + $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_FLAGINTERLACED: + $track_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_GAMMAVALUE: + $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']); + break; + + case EBML_ID_COLOURSPACE: + $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); + break; + + default: + $this->unhandledElement('track.video', __LINE__, $sub_subelement); + } + } + break; + + case EBML_ID_AUDIO: + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { + switch ($sub_subelement['id']) { + + case EBML_ID_CHANNELS: + case EBML_ID_BITDEPTH: + $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_SAMPLINGFREQUENCY: + case EBML_ID_OUTPUTSAMPLINGFREQUENCY: + $track_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Float($sub_subelement['data']); + break; + + case EBML_ID_CHANNELPOSITIONS: + $track_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); + break; + + default: + $this->unhandledElement('track.audio', __LINE__, $sub_subelement); + } + } + break; + + case EBML_ID_CONTENTENCODINGS: + + while ($this->getEBMLelement($sub_subelement, $subelement['end'])) { + switch ($sub_subelement['id']) { + + case EBML_ID_CONTENTENCODING: + + while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CONTENTCOMPRESSION, EBML_ID_CONTENTENCRYPTION))) { + switch ($sub_sub_subelement['id']) { + + case EBML_ID_CONTENTENCODINGORDER: + case EBML_ID_CONTENTENCODINGSCOPE: + case EBML_ID_CONTENTENCODINGTYPE: + $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + break; + + case EBML_ID_CONTENTCOMPRESSION: + + while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { + switch ($sub_sub_sub_subelement['id']) { + + case EBML_ID_CONTENTCOMPALGO: + $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); + break; + + case EBML_ID_CONTENTCOMPSETTINGS: + $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; + break; + + default: + $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); + } + } + break; + + case EBML_ID_CONTENTENCRYPTION: + + while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { + switch ($sub_sub_sub_subelement['id']) { + + case EBML_ID_CONTENTENCALGO: + case EBML_ID_CONTENTSIGALGO: + case EBML_ID_CONTENTSIGHASHALGO: + $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); + break; + + case EBML_ID_CONTENTENCKEYID: + case EBML_ID_CONTENTSIGNATURE: + case EBML_ID_CONTENTSIGKEYID: + $track_entry[$sub_subelement['id_name']][$sub_sub_subelement['id_name']][$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; + break; + + default: + $this->unhandledElement('track.contentencodings.contentencoding.contentcompression', __LINE__, $sub_sub_sub_subelement); + } + } + break; + + default: + $this->unhandledElement('track.contentencodings.contentencoding', __LINE__, $sub_sub_subelement); + } + } + break; + + default: + $this->unhandledElement('track.contentencodings', __LINE__, $sub_subelement); + } + } + break; + + default: + $this->unhandledElement('track', __LINE__, $subelement); + } + } + + $info['matroska']['tracks']['tracks'][] = $track_entry; + break; + + default: + $this->unhandledElement('tracks', __LINE__, $track_entry); + } + } + break; + + case EBML_ID_INFO: // Contains miscellaneous general information and statistics on the file. + $info_entry = array(); + + while ($this->getEBMLelement($subelement, $element_data['end'], true)) { + switch ($subelement['id']) { + + case EBML_ID_TIMECODESCALE: + $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); + break; + + case EBML_ID_DURATION: + $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Float($subelement['data']); + break; + + case EBML_ID_DATEUTC: + $info_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); + $info_entry[$subelement['id_name'].'_unix'] = self::EBMLdate2unix($info_entry[$subelement['id_name']]); + break; + + case EBML_ID_SEGMENTUID: + case EBML_ID_PREVUID: + case EBML_ID_NEXTUID: + $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); + break; + + case EBML_ID_SEGMENTFAMILY: + $info_entry[$subelement['id_name']][] = getid3_lib::trimNullByte($subelement['data']); + break; + + case EBML_ID_SEGMENTFILENAME: + case EBML_ID_PREVFILENAME: + case EBML_ID_NEXTFILENAME: + case EBML_ID_TITLE: + case EBML_ID_MUXINGAPP: + case EBML_ID_WRITINGAPP: + $info_entry[$subelement['id_name']] = getid3_lib::trimNullByte($subelement['data']); + $info['matroska']['comments'][strtolower($subelement['id_name'])][] = $info_entry[$subelement['id_name']]; + break; + + case EBML_ID_CHAPTERTRANSLATE: + $chaptertranslate_entry = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { + switch ($sub_subelement['id']) { + + case EBML_ID_CHAPTERTRANSLATEEDITIONUID: + $chaptertranslate_entry[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_CHAPTERTRANSLATECODEC: + $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_CHAPTERTRANSLATEID: + $chaptertranslate_entry[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); + break; + + default: + $this->unhandledElement('info.chaptertranslate', __LINE__, $sub_subelement); + } + } + $info_entry[$subelement['id_name']] = $chaptertranslate_entry; + break; + + default: + $this->unhandledElement('info', __LINE__, $subelement); + } + } + $info['matroska']['info'][] = $info_entry; + break; + + case EBML_ID_CUES: // A top-level element to speed seeking access. All entries are local to the segment. Should be mandatory for non "live" streams. + if (self::$hide_clusters) { // do not parse cues if hide clusters is "ON" till they point to clusters anyway + $this->current_offset = $element_data['end']; + break; + } + $cues_entry = array(); + + while ($this->getEBMLelement($subelement, $element_data['end'])) { + switch ($subelement['id']) { + + case EBML_ID_CUEPOINT: + $cuepoint_entry = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CUETRACKPOSITIONS))) { + switch ($sub_subelement['id']) { + + case EBML_ID_CUETRACKPOSITIONS: + $cuetrackpositions_entry = array(); + + while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) { + switch ($sub_sub_subelement['id']) { + + case EBML_ID_CUETRACK: + case EBML_ID_CUECLUSTERPOSITION: + case EBML_ID_CUEBLOCKNUMBER: + case EBML_ID_CUECODECSTATE: + $cuetrackpositions_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + break; + + default: + $this->unhandledElement('cues.cuepoint.cuetrackpositions', __LINE__, $sub_sub_subelement); + } + } + $cuepoint_entry[$sub_subelement['id_name']][] = $cuetrackpositions_entry; + break; + + case EBML_ID_CUETIME: + $cuepoint_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + default: + $this->unhandledElement('cues.cuepoint', __LINE__, $sub_subelement); + } + } + $cues_entry[] = $cuepoint_entry; + break; + + default: + $this->unhandledElement('cues', __LINE__, $subelement); + } + } + $info['matroska']['cues'] = $cues_entry; + break; + + case EBML_ID_TAGS: // Element containing elements specific to Tracks/Chapters. + $tags_entry = array(); + + while ($this->getEBMLelement($subelement, $element_data['end'], false)) { + switch ($subelement['id']) { + + case EBML_ID_TAG: + $tag_entry = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], false)) { + switch ($sub_subelement['id']) { + + case EBML_ID_TARGETS: + $targets_entry = array(); + + while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], true)) { + switch ($sub_sub_subelement['id']) { + + case EBML_ID_TARGETTYPEVALUE: + $targets_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + $targets_entry[strtolower($sub_sub_subelement['id_name']).'_long'] = self::TargetTypeValue($targets_entry[$sub_sub_subelement['id_name']]); + break; + + case EBML_ID_TARGETTYPE: + $targets_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data']; + break; + + case EBML_ID_TAGTRACKUID: + case EBML_ID_TAGEDITIONUID: + case EBML_ID_TAGCHAPTERUID: + case EBML_ID_TAGATTACHMENTUID: + $targets_entry[$sub_sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + break; + + default: + $this->unhandledElement('tags.tag.targets', __LINE__, $sub_sub_subelement); + } + } + $tag_entry[$sub_subelement['id_name']] = $targets_entry; + break; + + case EBML_ID_SIMPLETAG: + $tag_entry[$sub_subelement['id_name']][] = $this->HandleEMBLSimpleTag($sub_subelement['end']); + break; + + default: + $this->unhandledElement('tags.tag', __LINE__, $sub_subelement); + } + } + $tags_entry[] = $tag_entry; + break; + + default: + $this->unhandledElement('tags', __LINE__, $subelement); + } + } + $info['matroska']['tags'] = $tags_entry; + break; + + case EBML_ID_ATTACHMENTS: // Contain attached files. + + while ($this->getEBMLelement($subelement, $element_data['end'])) { + switch ($subelement['id']) { + + case EBML_ID_ATTACHEDFILE: + $attachedfile_entry = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_FILEDATA))) { + switch ($sub_subelement['id']) { + + case EBML_ID_FILEDESCRIPTION: + case EBML_ID_FILENAME: + case EBML_ID_FILEMIMETYPE: + $attachedfile_entry[$sub_subelement['id_name']] = $sub_subelement['data']; + break; + + case EBML_ID_FILEDATA: + $attachedfile_entry['data_offset'] = $this->current_offset; + $attachedfile_entry['data_length'] = $sub_subelement['length']; + + $attachedfile_entry[$sub_subelement['id_name']] = $this->saveAttachment( + $attachedfile_entry['FileName'], + $attachedfile_entry['data_offset'], + $attachedfile_entry['data_length']); + + $this->current_offset = $sub_subelement['end']; + break; + + case EBML_ID_FILEUID: + $attachedfile_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + default: + $this->unhandledElement('attachments.attachedfile', __LINE__, $sub_subelement); + } + } + $info['matroska']['attachments'][] = $attachedfile_entry; + break; + + default: + $this->unhandledElement('attachments', __LINE__, $subelement); + } + } + break; + + case EBML_ID_CHAPTERS: + + while ($this->getEBMLelement($subelement, $element_data['end'])) { + switch ($subelement['id']) { + + case EBML_ID_EDITIONENTRY: + $editionentry_entry = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CHAPTERATOM))) { + switch ($sub_subelement['id']) { + + case EBML_ID_EDITIONUID: + $editionentry_entry[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_EDITIONFLAGHIDDEN: + case EBML_ID_EDITIONFLAGDEFAULT: + case EBML_ID_EDITIONFLAGORDERED: + $editionentry_entry[$sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_CHAPTERATOM: + $chapteratom_entry = array(); + + while ($this->getEBMLelement($sub_sub_subelement, $sub_subelement['end'], array(EBML_ID_CHAPTERTRACK, EBML_ID_CHAPTERDISPLAY))) { + switch ($sub_sub_subelement['id']) { + + case EBML_ID_CHAPTERSEGMENTUID: + case EBML_ID_CHAPTERSEGMENTEDITIONUID: + $chapteratom_entry[$sub_sub_subelement['id_name']] = $sub_sub_subelement['data']; + break; + + case EBML_ID_CHAPTERFLAGENABLED: + case EBML_ID_CHAPTERFLAGHIDDEN: + $chapteratom_entry[$sub_sub_subelement['id_name']] = (bool)getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + break; + + case EBML_ID_CHAPTERUID: + case EBML_ID_CHAPTERTIMESTART: + case EBML_ID_CHAPTERTIMEEND: + $chapteratom_entry[$sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_subelement['data']); + break; + + case EBML_ID_CHAPTERTRACK: + $chaptertrack_entry = array(); + + while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { + switch ($sub_sub_sub_subelement['id']) { + + case EBML_ID_CHAPTERTRACKNUMBER: + $chaptertrack_entry[$sub_sub_sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_sub_sub_subelement['data']); + break; + + default: + $this->unhandledElement('chapters.editionentry.chapteratom.chaptertrack', __LINE__, $sub_sub_sub_subelement); + } + } + $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chaptertrack_entry; + break; + + case EBML_ID_CHAPTERDISPLAY: + $chapterdisplay_entry = array(); + + while ($this->getEBMLelement($sub_sub_sub_subelement, $sub_sub_subelement['end'], true)) { + switch ($sub_sub_sub_subelement['id']) { + + case EBML_ID_CHAPSTRING: + case EBML_ID_CHAPLANGUAGE: + case EBML_ID_CHAPCOUNTRY: + $chapterdisplay_entry[$sub_sub_sub_subelement['id_name']] = $sub_sub_sub_subelement['data']; + break; + + default: + $this->unhandledElement('chapters.editionentry.chapteratom.chapterdisplay', __LINE__, $sub_sub_sub_subelement); + } + } + $chapteratom_entry[$sub_sub_subelement['id_name']][] = $chapterdisplay_entry; + break; + + default: + $this->unhandledElement('chapters.editionentry.chapteratom', __LINE__, $sub_sub_subelement); + } + } + $editionentry_entry[$sub_subelement['id_name']][] = $chapteratom_entry; + break; + + default: + $this->unhandledElement('chapters.editionentry', __LINE__, $sub_subelement); + } + } + $info['matroska']['chapters'][] = $editionentry_entry; + break; + + default: + $this->unhandledElement('chapters', __LINE__, $subelement); + } + } + break; + + case EBML_ID_CLUSTER: // The lower level element containing the (monolithic) Block structure. + $cluster_entry = array(); + + while ($this->getEBMLelement($subelement, $element_data['end'], array(EBML_ID_CLUSTERSILENTTRACKS, EBML_ID_CLUSTERBLOCKGROUP, EBML_ID_CLUSTERSIMPLEBLOCK))) { + switch ($subelement['id']) { + + case EBML_ID_CLUSTERTIMECODE: + case EBML_ID_CLUSTERPOSITION: + case EBML_ID_CLUSTERPREVSIZE: + $cluster_entry[$subelement['id_name']] = getid3_lib::BigEndian2Int($subelement['data']); + break; + + case EBML_ID_CLUSTERSILENTTRACKS: + $cluster_silent_tracks = array(); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], true)) { + switch ($sub_subelement['id']) { + + case EBML_ID_CLUSTERSILENTTRACKNUMBER: + $cluster_silent_tracks[] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + default: + $this->unhandledElement('cluster.silenttracks', __LINE__, $sub_subelement); + } + } + $cluster_entry[$subelement['id_name']][] = $cluster_silent_tracks; + break; + + case EBML_ID_CLUSTERBLOCKGROUP: + $cluster_block_group = array('offset' => $this->current_offset); + + while ($this->getEBMLelement($sub_subelement, $subelement['end'], array(EBML_ID_CLUSTERBLOCK))) { + switch ($sub_subelement['id']) { + + case EBML_ID_CLUSTERBLOCK: + $cluster_block_group[$sub_subelement['id_name']] = $this->HandleEMBLClusterBlock($sub_subelement, EBML_ID_CLUSTERBLOCK, $info); + break; + + case EBML_ID_CLUSTERREFERENCEPRIORITY: // unsigned-int + case EBML_ID_CLUSTERBLOCKDURATION: // unsigned-int + $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::BigEndian2Int($sub_subelement['data']); + break; + + case EBML_ID_CLUSTERREFERENCEBLOCK: // signed-int + $cluster_block_group[$sub_subelement['id_name']][] = getid3_lib::BigEndian2Int($sub_subelement['data'], false, true); + break; + + case EBML_ID_CLUSTERCODECSTATE: + $cluster_block_group[$sub_subelement['id_name']] = getid3_lib::trimNullByte($sub_subelement['data']); + break; + + default: + $this->unhandledElement('clusters.blockgroup', __LINE__, $sub_subelement); + } + } + $cluster_entry[$subelement['id_name']][] = $cluster_block_group; + break; + + case EBML_ID_CLUSTERSIMPLEBLOCK: + $cluster_entry[$subelement['id_name']][] = $this->HandleEMBLClusterBlock($subelement, EBML_ID_CLUSTERSIMPLEBLOCK, $info); + break; + + default: + $this->unhandledElement('cluster', __LINE__, $subelement); + } + $this->current_offset = $subelement['end']; + } + if (!self::$hide_clusters) { + $info['matroska']['cluster'][] = $cluster_entry; + } + + // check to see if all the data we need exists already, if so, break out of the loop + if (!self::$parse_whole_file) { + if (isset($info['matroska']['info']) && is_array($info['matroska']['info'])) { + if (isset($info['matroska']['tracks']['tracks']) && is_array($info['matroska']['tracks']['tracks'])) { + if (count($info['matroska']['track_data_offsets']) == count($info['matroska']['tracks']['tracks'])) { + return; + } + } + } + } + break; + + default: + $this->unhandledElement('segment', __LINE__, $element_data); + } + } + break; + + default: + $this->unhandledElement('root', __LINE__, $top_element); + } + } + } + + private function EnsureBufferHasEnoughData($min_data=1024) { + if (($this->current_offset - $this->EBMLbuffer_offset) >= ($this->EBMLbuffer_length - $min_data)) { + $read_bytes = max($min_data, $this->getid3->fread_buffer_size()); + + try { + $this->fseek($this->current_offset); + $this->EBMLbuffer_offset = $this->current_offset; + $this->EBMLbuffer = $this->fread($read_bytes); + $this->EBMLbuffer_length = strlen($this->EBMLbuffer); + } catch (getid3_exception $e) { + $this->warning('EBML parser: '.$e->getMessage()); + return false; + } + + if ($this->EBMLbuffer_length == 0 && $this->feof()) { + return $this->error('EBML parser: ran out of file at offset '.$this->current_offset); + } + } + return true; + } + + private function readEBMLint() { + $actual_offset = $this->current_offset - $this->EBMLbuffer_offset; + + // get length of integer + $first_byte_int = ord($this->EBMLbuffer[$actual_offset]); + if (0x80 & $first_byte_int) { + $length = 1; + } elseif (0x40 & $first_byte_int) { + $length = 2; + } elseif (0x20 & $first_byte_int) { + $length = 3; + } elseif (0x10 & $first_byte_int) { + $length = 4; + } elseif (0x08 & $first_byte_int) { + $length = 5; + } elseif (0x04 & $first_byte_int) { + $length = 6; + } elseif (0x02 & $first_byte_int) { + $length = 7; + } elseif (0x01 & $first_byte_int) { + $length = 8; + } else { + throw new Exception('invalid EBML integer (leading 0x00) at '.$this->current_offset); + } + + // read + $int_value = self::EBML2Int(substr($this->EBMLbuffer, $actual_offset, $length)); + $this->current_offset += $length; + + return $int_value; + } + + private function readEBMLelementData($length, $check_buffer=false) { + if ($check_buffer && !$this->EnsureBufferHasEnoughData($length)) { + return false; + } + $data = substr($this->EBMLbuffer, $this->current_offset - $this->EBMLbuffer_offset, $length); + $this->current_offset += $length; + return $data; + } + + private function getEBMLelement(&$element, $parent_end, $get_data=false) { + if ($this->current_offset >= $parent_end) { + return false; + } + + if (!$this->EnsureBufferHasEnoughData()) { + $this->current_offset = PHP_INT_MAX; // do not exit parser right now, allow to finish current loop to gather maximum information + return false; + } + + $element = array(); + + // set offset + $element['offset'] = $this->current_offset; + + // get ID + $element['id'] = $this->readEBMLint(); + + // get name + $element['id_name'] = self::EBMLidName($element['id']); + + // get length + $element['length'] = $this->readEBMLint(); + + // get end offset + $element['end'] = $this->current_offset + $element['length']; + + // get raw data + $dont_parse = (in_array($element['id'], $this->unuseful_elements) || $element['id_name'] == dechex($element['id'])); + if (($get_data === true || (is_array($get_data) && !in_array($element['id'], $get_data))) && !$dont_parse) { + $element['data'] = $this->readEBMLelementData($element['length'], $element); + } + + return true; + } + + private function unhandledElement($type, $line, $element) { + // warn only about unknown and missed elements, not about unuseful + if (!in_array($element['id'], $this->unuseful_elements)) { + $this->warning('Unhandled '.$type.' element ['.basename(__FILE__).':'.$line.'] ('.$element['id'].'::'.$element['id_name'].' ['.$element['length'].' bytes]) at '.$element['offset']); + } + + // increase offset for unparsed elements + if (!isset($element['data'])) { + $this->current_offset = $element['end']; + } + } + + private function ExtractCommentsSimpleTag($SimpleTagArray) { + if (!empty($SimpleTagArray['SimpleTag'])) { + foreach ($SimpleTagArray['SimpleTag'] as $SimpleTagKey => $SimpleTagData) { + if (!empty($SimpleTagData['TagName']) && !empty($SimpleTagData['TagString'])) { + $this->getid3->info['matroska']['comments'][strtolower($SimpleTagData['TagName'])][] = $SimpleTagData['TagString']; + } + if (!empty($SimpleTagData['SimpleTag'])) { + $this->ExtractCommentsSimpleTag($SimpleTagData); + } + } + } + + return true; + } + + private function HandleEMBLSimpleTag($parent_end) { + $simpletag_entry = array(); + + while ($this->getEBMLelement($element, $parent_end, array(EBML_ID_SIMPLETAG))) { + switch ($element['id']) { + + case EBML_ID_TAGNAME: + case EBML_ID_TAGLANGUAGE: + case EBML_ID_TAGSTRING: + case EBML_ID_TAGBINARY: + $simpletag_entry[$element['id_name']] = $element['data']; + break; + + case EBML_ID_SIMPLETAG: + $simpletag_entry[$element['id_name']][] = $this->HandleEMBLSimpleTag($element['end']); + break; + + case EBML_ID_TAGDEFAULT: + $simpletag_entry[$element['id_name']] = (bool)getid3_lib::BigEndian2Int($element['data']); + break; + + default: + $this->unhandledElement('tag.simpletag', __LINE__, $element); + } + } + + return $simpletag_entry; + } + + private function HandleEMBLClusterBlock($element, $block_type, &$info) { + // http://www.matroska.org/technical/specs/index.html#block_structure + // http://www.matroska.org/technical/specs/index.html#simpleblock_structure + + $block_data = array(); + $block_data['tracknumber'] = $this->readEBMLint(); + $block_data['timecode'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(2), false, true); + $block_data['flags_raw'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)); + + if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) { + $block_data['flags']['keyframe'] = (($block_data['flags_raw'] & 0x80) >> 7); + //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0x70) >> 4); + } + else { + //$block_data['flags']['reserved1'] = (($block_data['flags_raw'] & 0xF0) >> 4); + } + $block_data['flags']['invisible'] = (bool)(($block_data['flags_raw'] & 0x08) >> 3); + $block_data['flags']['lacing'] = (($block_data['flags_raw'] & 0x06) >> 1); // 00=no lacing; 01=Xiph lacing; 11=EBML lacing; 10=fixed-size lacing + if ($block_type == EBML_ID_CLUSTERSIMPLEBLOCK) { + $block_data['flags']['discardable'] = (($block_data['flags_raw'] & 0x01)); + } + else { + //$block_data['flags']['reserved2'] = (($block_data['flags_raw'] & 0x01) >> 0); + } + $block_data['flags']['lacing_type'] = self::BlockLacingType($block_data['flags']['lacing']); + + // Lace (when lacing bit is set) + if ($block_data['flags']['lacing'] > 0) { + $block_data['lace_frames'] = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)) + 1; // Number of frames in the lace-1 (uint8) + if ($block_data['flags']['lacing'] != 0x02) { + for ($i = 1; $i < $block_data['lace_frames']; $i ++) { // Lace-coded size of each frame of the lace, except for the last one (multiple uint8). *This is not used with Fixed-size lacing as it is calculated automatically from (total size of lace) / (number of frames in lace). + if ($block_data['flags']['lacing'] == 0x03) { // EBML lacing + $block_data['lace_frames_size'][$i] = $this->readEBMLint(); // TODO: read size correctly, calc size for the last frame. For now offsets are deteminded OK with readEBMLint() and that's the most important thing. + } + else { // Xiph lacing + $block_data['lace_frames_size'][$i] = 0; + do { + $size = getid3_lib::BigEndian2Int($this->readEBMLelementData(1)); + $block_data['lace_frames_size'][$i] += $size; + } + while ($size == 255); + } + } + if ($block_data['flags']['lacing'] == 0x01) { // calc size of the last frame only for Xiph lacing, till EBML sizes are now anyway determined incorrectly + $block_data['lace_frames_size'][] = $element['end'] - $this->current_offset - array_sum($block_data['lace_frames_size']); + } + } + } + + if (!isset($info['matroska']['track_data_offsets'][$block_data['tracknumber']])) { + $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['offset'] = $this->current_offset; + $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length'] = $element['end'] - $this->current_offset; + //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] = 0; + } + //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['total_length'] += $info['matroska']['track_data_offsets'][$block_data['tracknumber']]['length']; + //$info['matroska']['track_data_offsets'][$block_data['tracknumber']]['duration'] = $block_data['timecode'] * ((isset($info['matroska']['info'][0]['TimecodeScale']) ? $info['matroska']['info'][0]['TimecodeScale'] : 1000000) / 1000000000); + + // set offset manually + $this->current_offset = $element['end']; + + return $block_data; + } + + private static function EBML2Int($EBMLstring) { + // http://matroska.org/specs/ + + // Element ID coded with an UTF-8 like system: + // 1xxx xxxx - Class A IDs (2^7 -2 possible values) (base 0x8X) + // 01xx xxxx xxxx xxxx - Class B IDs (2^14-2 possible values) (base 0x4X 0xXX) + // 001x xxxx xxxx xxxx xxxx xxxx - Class C IDs (2^21-2 possible values) (base 0x2X 0xXX 0xXX) + // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - Class D IDs (2^28-2 possible values) (base 0x1X 0xXX 0xXX 0xXX) + // Values with all x at 0 and 1 are reserved (hence the -2). + + // Data size, in octets, is also coded with an UTF-8 like system : + // 1xxx xxxx - value 0 to 2^7-2 + // 01xx xxxx xxxx xxxx - value 0 to 2^14-2 + // 001x xxxx xxxx xxxx xxxx xxxx - value 0 to 2^21-2 + // 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^28-2 + // 0000 1xxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^35-2 + // 0000 01xx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^42-2 + // 0000 001x xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^49-2 + // 0000 0001 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx - value 0 to 2^56-2 + + $first_byte_int = ord($EBMLstring[0]); + if (0x80 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x7F); + } elseif (0x40 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x3F); + } elseif (0x20 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x1F); + } elseif (0x10 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x0F); + } elseif (0x08 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x07); + } elseif (0x04 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x03); + } elseif (0x02 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x01); + } elseif (0x01 & $first_byte_int) { + $EBMLstring[0] = chr($first_byte_int & 0x00); + } + + return getid3_lib::BigEndian2Int($EBMLstring); + } + + private static function EBMLdate2unix($EBMLdatestamp) { + // Date - signed 8 octets integer in nanoseconds with 0 indicating the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC) + // 978307200 == mktime(0, 0, 0, 1, 1, 2001) == January 1, 2001 12:00:00am UTC + return round(($EBMLdatestamp / 1000000000) + 978307200); + } + + public static function TargetTypeValue($target_type) { + // http://www.matroska.org/technical/specs/tagging/index.html + static $TargetTypeValue = array(); + if (empty($TargetTypeValue)) { + $TargetTypeValue[10] = 'A: ~ V:shot'; // the lowest hierarchy found in music or movies + $TargetTypeValue[20] = 'A:subtrack/part/movement ~ V:scene'; // corresponds to parts of a track for audio (like a movement) + $TargetTypeValue[30] = 'A:track/song ~ V:chapter'; // the common parts of an album or a movie + $TargetTypeValue[40] = 'A:part/session ~ V:part/session'; // when an album or episode has different logical parts + $TargetTypeValue[50] = 'A:album/opera/concert ~ V:movie/episode/concert'; // the most common grouping level of music and video (equals to an episode for TV series) + $TargetTypeValue[60] = 'A:edition/issue/volume/opus ~ V:season/sequel/volume'; // a list of lower levels grouped together + $TargetTypeValue[70] = 'A:collection ~ V:collection'; // the high hierarchy consisting of many different lower items + } + return (isset($TargetTypeValue[$target_type]) ? $TargetTypeValue[$target_type] : $target_type); + } + + public static function BlockLacingType($lacingtype) { + // http://matroska.org/technical/specs/index.html#block_structure + static $BlockLacingType = array(); + if (empty($BlockLacingType)) { + $BlockLacingType[0x00] = 'no lacing'; + $BlockLacingType[0x01] = 'Xiph lacing'; + $BlockLacingType[0x02] = 'fixed-size lacing'; + $BlockLacingType[0x03] = 'EBML lacing'; + } + return (isset($BlockLacingType[$lacingtype]) ? $BlockLacingType[$lacingtype] : $lacingtype); + } + + public static function CodecIDtoCommonName($codecid) { + // http://www.matroska.org/technical/specs/codecid/index.html + static $CodecIDlist = array(); + if (empty($CodecIDlist)) { + $CodecIDlist['A_AAC'] = 'aac'; + $CodecIDlist['A_AAC/MPEG2/LC'] = 'aac'; + $CodecIDlist['A_AC3'] = 'ac3'; + $CodecIDlist['A_DTS'] = 'dts'; + $CodecIDlist['A_FLAC'] = 'flac'; + $CodecIDlist['A_MPEG/L1'] = 'mp1'; + $CodecIDlist['A_MPEG/L2'] = 'mp2'; + $CodecIDlist['A_MPEG/L3'] = 'mp3'; + $CodecIDlist['A_PCM/INT/LIT'] = 'pcm'; // PCM Integer Little Endian + $CodecIDlist['A_PCM/INT/BIG'] = 'pcm'; // PCM Integer Big Endian + $CodecIDlist['A_QUICKTIME/QDMC'] = 'quicktime'; // Quicktime: QDesign Music + $CodecIDlist['A_QUICKTIME/QDM2'] = 'quicktime'; // Quicktime: QDesign Music v2 + $CodecIDlist['A_VORBIS'] = 'vorbis'; + $CodecIDlist['V_MPEG1'] = 'mpeg'; + $CodecIDlist['V_THEORA'] = 'theora'; + $CodecIDlist['V_REAL/RV40'] = 'real'; + $CodecIDlist['V_REAL/RV10'] = 'real'; + $CodecIDlist['V_REAL/RV20'] = 'real'; + $CodecIDlist['V_REAL/RV30'] = 'real'; + $CodecIDlist['V_QUICKTIME'] = 'quicktime'; // Quicktime + $CodecIDlist['V_MPEG4/ISO/AP'] = 'mpeg4'; + $CodecIDlist['V_MPEG4/ISO/ASP'] = 'mpeg4'; + $CodecIDlist['V_MPEG4/ISO/AVC'] = 'h264'; + $CodecIDlist['V_MPEG4/ISO/SP'] = 'mpeg4'; + $CodecIDlist['V_VP8'] = 'vp8'; + $CodecIDlist['V_MS/VFW/FOURCC'] = 'riff'; + $CodecIDlist['A_MS/ACM'] = 'riff'; + } + return (isset($CodecIDlist[$codecid]) ? $CodecIDlist[$codecid] : $codecid); + } + + private static function EBMLidName($value) { + static $EBMLidList = array(); + if (empty($EBMLidList)) { + $EBMLidList[EBML_ID_ASPECTRATIOTYPE] = 'AspectRatioType'; + $EBMLidList[EBML_ID_ATTACHEDFILE] = 'AttachedFile'; + $EBMLidList[EBML_ID_ATTACHMENTLINK] = 'AttachmentLink'; + $EBMLidList[EBML_ID_ATTACHMENTS] = 'Attachments'; + $EBMLidList[EBML_ID_AUDIO] = 'Audio'; + $EBMLidList[EBML_ID_BITDEPTH] = 'BitDepth'; + $EBMLidList[EBML_ID_CHANNELPOSITIONS] = 'ChannelPositions'; + $EBMLidList[EBML_ID_CHANNELS] = 'Channels'; + $EBMLidList[EBML_ID_CHAPCOUNTRY] = 'ChapCountry'; + $EBMLidList[EBML_ID_CHAPLANGUAGE] = 'ChapLanguage'; + $EBMLidList[EBML_ID_CHAPPROCESS] = 'ChapProcess'; + $EBMLidList[EBML_ID_CHAPPROCESSCODECID] = 'ChapProcessCodecID'; + $EBMLidList[EBML_ID_CHAPPROCESSCOMMAND] = 'ChapProcessCommand'; + $EBMLidList[EBML_ID_CHAPPROCESSDATA] = 'ChapProcessData'; + $EBMLidList[EBML_ID_CHAPPROCESSPRIVATE] = 'ChapProcessPrivate'; + $EBMLidList[EBML_ID_CHAPPROCESSTIME] = 'ChapProcessTime'; + $EBMLidList[EBML_ID_CHAPSTRING] = 'ChapString'; + $EBMLidList[EBML_ID_CHAPTERATOM] = 'ChapterAtom'; + $EBMLidList[EBML_ID_CHAPTERDISPLAY] = 'ChapterDisplay'; + $EBMLidList[EBML_ID_CHAPTERFLAGENABLED] = 'ChapterFlagEnabled'; + $EBMLidList[EBML_ID_CHAPTERFLAGHIDDEN] = 'ChapterFlagHidden'; + $EBMLidList[EBML_ID_CHAPTERPHYSICALEQUIV] = 'ChapterPhysicalEquiv'; + $EBMLidList[EBML_ID_CHAPTERS] = 'Chapters'; + $EBMLidList[EBML_ID_CHAPTERSEGMENTEDITIONUID] = 'ChapterSegmentEditionUID'; + $EBMLidList[EBML_ID_CHAPTERSEGMENTUID] = 'ChapterSegmentUID'; + $EBMLidList[EBML_ID_CHAPTERTIMEEND] = 'ChapterTimeEnd'; + $EBMLidList[EBML_ID_CHAPTERTIMESTART] = 'ChapterTimeStart'; + $EBMLidList[EBML_ID_CHAPTERTRACK] = 'ChapterTrack'; + $EBMLidList[EBML_ID_CHAPTERTRACKNUMBER] = 'ChapterTrackNumber'; + $EBMLidList[EBML_ID_CHAPTERTRANSLATE] = 'ChapterTranslate'; + $EBMLidList[EBML_ID_CHAPTERTRANSLATECODEC] = 'ChapterTranslateCodec'; + $EBMLidList[EBML_ID_CHAPTERTRANSLATEEDITIONUID] = 'ChapterTranslateEditionUID'; + $EBMLidList[EBML_ID_CHAPTERTRANSLATEID] = 'ChapterTranslateID'; + $EBMLidList[EBML_ID_CHAPTERUID] = 'ChapterUID'; + $EBMLidList[EBML_ID_CLUSTER] = 'Cluster'; + $EBMLidList[EBML_ID_CLUSTERBLOCK] = 'ClusterBlock'; + $EBMLidList[EBML_ID_CLUSTERBLOCKADDID] = 'ClusterBlockAddID'; + $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONAL] = 'ClusterBlockAdditional'; + $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONID] = 'ClusterBlockAdditionID'; + $EBMLidList[EBML_ID_CLUSTERBLOCKADDITIONS] = 'ClusterBlockAdditions'; + $EBMLidList[EBML_ID_CLUSTERBLOCKDURATION] = 'ClusterBlockDuration'; + $EBMLidList[EBML_ID_CLUSTERBLOCKGROUP] = 'ClusterBlockGroup'; + $EBMLidList[EBML_ID_CLUSTERBLOCKMORE] = 'ClusterBlockMore'; + $EBMLidList[EBML_ID_CLUSTERBLOCKVIRTUAL] = 'ClusterBlockVirtual'; + $EBMLidList[EBML_ID_CLUSTERCODECSTATE] = 'ClusterCodecState'; + $EBMLidList[EBML_ID_CLUSTERDELAY] = 'ClusterDelay'; + $EBMLidList[EBML_ID_CLUSTERDURATION] = 'ClusterDuration'; + $EBMLidList[EBML_ID_CLUSTERENCRYPTEDBLOCK] = 'ClusterEncryptedBlock'; + $EBMLidList[EBML_ID_CLUSTERFRAMENUMBER] = 'ClusterFrameNumber'; + $EBMLidList[EBML_ID_CLUSTERLACENUMBER] = 'ClusterLaceNumber'; + $EBMLidList[EBML_ID_CLUSTERPOSITION] = 'ClusterPosition'; + $EBMLidList[EBML_ID_CLUSTERPREVSIZE] = 'ClusterPrevSize'; + $EBMLidList[EBML_ID_CLUSTERREFERENCEBLOCK] = 'ClusterReferenceBlock'; + $EBMLidList[EBML_ID_CLUSTERREFERENCEPRIORITY] = 'ClusterReferencePriority'; + $EBMLidList[EBML_ID_CLUSTERREFERENCEVIRTUAL] = 'ClusterReferenceVirtual'; + $EBMLidList[EBML_ID_CLUSTERSILENTTRACKNUMBER] = 'ClusterSilentTrackNumber'; + $EBMLidList[EBML_ID_CLUSTERSILENTTRACKS] = 'ClusterSilentTracks'; + $EBMLidList[EBML_ID_CLUSTERSIMPLEBLOCK] = 'ClusterSimpleBlock'; + $EBMLidList[EBML_ID_CLUSTERTIMECODE] = 'ClusterTimecode'; + $EBMLidList[EBML_ID_CLUSTERTIMESLICE] = 'ClusterTimeSlice'; + $EBMLidList[EBML_ID_CODECDECODEALL] = 'CodecDecodeAll'; + $EBMLidList[EBML_ID_CODECDOWNLOADURL] = 'CodecDownloadURL'; + $EBMLidList[EBML_ID_CODECID] = 'CodecID'; + $EBMLidList[EBML_ID_CODECINFOURL] = 'CodecInfoURL'; + $EBMLidList[EBML_ID_CODECNAME] = 'CodecName'; + $EBMLidList[EBML_ID_CODECPRIVATE] = 'CodecPrivate'; + $EBMLidList[EBML_ID_CODECSETTINGS] = 'CodecSettings'; + $EBMLidList[EBML_ID_COLOURSPACE] = 'ColourSpace'; + $EBMLidList[EBML_ID_CONTENTCOMPALGO] = 'ContentCompAlgo'; + $EBMLidList[EBML_ID_CONTENTCOMPRESSION] = 'ContentCompression'; + $EBMLidList[EBML_ID_CONTENTCOMPSETTINGS] = 'ContentCompSettings'; + $EBMLidList[EBML_ID_CONTENTENCALGO] = 'ContentEncAlgo'; + $EBMLidList[EBML_ID_CONTENTENCKEYID] = 'ContentEncKeyID'; + $EBMLidList[EBML_ID_CONTENTENCODING] = 'ContentEncoding'; + $EBMLidList[EBML_ID_CONTENTENCODINGORDER] = 'ContentEncodingOrder'; + $EBMLidList[EBML_ID_CONTENTENCODINGS] = 'ContentEncodings'; + $EBMLidList[EBML_ID_CONTENTENCODINGSCOPE] = 'ContentEncodingScope'; + $EBMLidList[EBML_ID_CONTENTENCODINGTYPE] = 'ContentEncodingType'; + $EBMLidList[EBML_ID_CONTENTENCRYPTION] = 'ContentEncryption'; + $EBMLidList[EBML_ID_CONTENTSIGALGO] = 'ContentSigAlgo'; + $EBMLidList[EBML_ID_CONTENTSIGHASHALGO] = 'ContentSigHashAlgo'; + $EBMLidList[EBML_ID_CONTENTSIGKEYID] = 'ContentSigKeyID'; + $EBMLidList[EBML_ID_CONTENTSIGNATURE] = 'ContentSignature'; + $EBMLidList[EBML_ID_CRC32] = 'CRC32'; + $EBMLidList[EBML_ID_CUEBLOCKNUMBER] = 'CueBlockNumber'; + $EBMLidList[EBML_ID_CUECLUSTERPOSITION] = 'CueClusterPosition'; + $EBMLidList[EBML_ID_CUECODECSTATE] = 'CueCodecState'; + $EBMLidList[EBML_ID_CUEPOINT] = 'CuePoint'; + $EBMLidList[EBML_ID_CUEREFCLUSTER] = 'CueRefCluster'; + $EBMLidList[EBML_ID_CUEREFCODECSTATE] = 'CueRefCodecState'; + $EBMLidList[EBML_ID_CUEREFERENCE] = 'CueReference'; + $EBMLidList[EBML_ID_CUEREFNUMBER] = 'CueRefNumber'; + $EBMLidList[EBML_ID_CUEREFTIME] = 'CueRefTime'; + $EBMLidList[EBML_ID_CUES] = 'Cues'; + $EBMLidList[EBML_ID_CUETIME] = 'CueTime'; + $EBMLidList[EBML_ID_CUETRACK] = 'CueTrack'; + $EBMLidList[EBML_ID_CUETRACKPOSITIONS] = 'CueTrackPositions'; + $EBMLidList[EBML_ID_DATEUTC] = 'DateUTC'; + $EBMLidList[EBML_ID_DEFAULTDURATION] = 'DefaultDuration'; + $EBMLidList[EBML_ID_DISPLAYHEIGHT] = 'DisplayHeight'; + $EBMLidList[EBML_ID_DISPLAYUNIT] = 'DisplayUnit'; + $EBMLidList[EBML_ID_DISPLAYWIDTH] = 'DisplayWidth'; + $EBMLidList[EBML_ID_DOCTYPE] = 'DocType'; + $EBMLidList[EBML_ID_DOCTYPEREADVERSION] = 'DocTypeReadVersion'; + $EBMLidList[EBML_ID_DOCTYPEVERSION] = 'DocTypeVersion'; + $EBMLidList[EBML_ID_DURATION] = 'Duration'; + $EBMLidList[EBML_ID_EBML] = 'EBML'; + $EBMLidList[EBML_ID_EBMLMAXIDLENGTH] = 'EBMLMaxIDLength'; + $EBMLidList[EBML_ID_EBMLMAXSIZELENGTH] = 'EBMLMaxSizeLength'; + $EBMLidList[EBML_ID_EBMLREADVERSION] = 'EBMLReadVersion'; + $EBMLidList[EBML_ID_EBMLVERSION] = 'EBMLVersion'; + $EBMLidList[EBML_ID_EDITIONENTRY] = 'EditionEntry'; + $EBMLidList[EBML_ID_EDITIONFLAGDEFAULT] = 'EditionFlagDefault'; + $EBMLidList[EBML_ID_EDITIONFLAGHIDDEN] = 'EditionFlagHidden'; + $EBMLidList[EBML_ID_EDITIONFLAGORDERED] = 'EditionFlagOrdered'; + $EBMLidList[EBML_ID_EDITIONUID] = 'EditionUID'; + $EBMLidList[EBML_ID_FILEDATA] = 'FileData'; + $EBMLidList[EBML_ID_FILEDESCRIPTION] = 'FileDescription'; + $EBMLidList[EBML_ID_FILEMIMETYPE] = 'FileMimeType'; + $EBMLidList[EBML_ID_FILENAME] = 'FileName'; + $EBMLidList[EBML_ID_FILEREFERRAL] = 'FileReferral'; + $EBMLidList[EBML_ID_FILEUID] = 'FileUID'; + $EBMLidList[EBML_ID_FLAGDEFAULT] = 'FlagDefault'; + $EBMLidList[EBML_ID_FLAGENABLED] = 'FlagEnabled'; + $EBMLidList[EBML_ID_FLAGFORCED] = 'FlagForced'; + $EBMLidList[EBML_ID_FLAGINTERLACED] = 'FlagInterlaced'; + $EBMLidList[EBML_ID_FLAGLACING] = 'FlagLacing'; + $EBMLidList[EBML_ID_GAMMAVALUE] = 'GammaValue'; + $EBMLidList[EBML_ID_INFO] = 'Info'; + $EBMLidList[EBML_ID_LANGUAGE] = 'Language'; + $EBMLidList[EBML_ID_MAXBLOCKADDITIONID] = 'MaxBlockAdditionID'; + $EBMLidList[EBML_ID_MAXCACHE] = 'MaxCache'; + $EBMLidList[EBML_ID_MINCACHE] = 'MinCache'; + $EBMLidList[EBML_ID_MUXINGAPP] = 'MuxingApp'; + $EBMLidList[EBML_ID_NAME] = 'Name'; + $EBMLidList[EBML_ID_NEXTFILENAME] = 'NextFilename'; + $EBMLidList[EBML_ID_NEXTUID] = 'NextUID'; + $EBMLidList[EBML_ID_OUTPUTSAMPLINGFREQUENCY] = 'OutputSamplingFrequency'; + $EBMLidList[EBML_ID_PIXELCROPBOTTOM] = 'PixelCropBottom'; + $EBMLidList[EBML_ID_PIXELCROPLEFT] = 'PixelCropLeft'; + $EBMLidList[EBML_ID_PIXELCROPRIGHT] = 'PixelCropRight'; + $EBMLidList[EBML_ID_PIXELCROPTOP] = 'PixelCropTop'; + $EBMLidList[EBML_ID_PIXELHEIGHT] = 'PixelHeight'; + $EBMLidList[EBML_ID_PIXELWIDTH] = 'PixelWidth'; + $EBMLidList[EBML_ID_PREVFILENAME] = 'PrevFilename'; + $EBMLidList[EBML_ID_PREVUID] = 'PrevUID'; + $EBMLidList[EBML_ID_SAMPLINGFREQUENCY] = 'SamplingFrequency'; + $EBMLidList[EBML_ID_SEEK] = 'Seek'; + $EBMLidList[EBML_ID_SEEKHEAD] = 'SeekHead'; + $EBMLidList[EBML_ID_SEEKID] = 'SeekID'; + $EBMLidList[EBML_ID_SEEKPOSITION] = 'SeekPosition'; + $EBMLidList[EBML_ID_SEGMENT] = 'Segment'; + $EBMLidList[EBML_ID_SEGMENTFAMILY] = 'SegmentFamily'; + $EBMLidList[EBML_ID_SEGMENTFILENAME] = 'SegmentFilename'; + $EBMLidList[EBML_ID_SEGMENTUID] = 'SegmentUID'; + $EBMLidList[EBML_ID_SIMPLETAG] = 'SimpleTag'; + $EBMLidList[EBML_ID_CLUSTERSLICES] = 'ClusterSlices'; + $EBMLidList[EBML_ID_STEREOMODE] = 'StereoMode'; + $EBMLidList[EBML_ID_OLDSTEREOMODE] = 'OldStereoMode'; + $EBMLidList[EBML_ID_TAG] = 'Tag'; + $EBMLidList[EBML_ID_TAGATTACHMENTUID] = 'TagAttachmentUID'; + $EBMLidList[EBML_ID_TAGBINARY] = 'TagBinary'; + $EBMLidList[EBML_ID_TAGCHAPTERUID] = 'TagChapterUID'; + $EBMLidList[EBML_ID_TAGDEFAULT] = 'TagDefault'; + $EBMLidList[EBML_ID_TAGEDITIONUID] = 'TagEditionUID'; + $EBMLidList[EBML_ID_TAGLANGUAGE] = 'TagLanguage'; + $EBMLidList[EBML_ID_TAGNAME] = 'TagName'; + $EBMLidList[EBML_ID_TAGTRACKUID] = 'TagTrackUID'; + $EBMLidList[EBML_ID_TAGS] = 'Tags'; + $EBMLidList[EBML_ID_TAGSTRING] = 'TagString'; + $EBMLidList[EBML_ID_TARGETS] = 'Targets'; + $EBMLidList[EBML_ID_TARGETTYPE] = 'TargetType'; + $EBMLidList[EBML_ID_TARGETTYPEVALUE] = 'TargetTypeValue'; + $EBMLidList[EBML_ID_TIMECODESCALE] = 'TimecodeScale'; + $EBMLidList[EBML_ID_TITLE] = 'Title'; + $EBMLidList[EBML_ID_TRACKENTRY] = 'TrackEntry'; + $EBMLidList[EBML_ID_TRACKNUMBER] = 'TrackNumber'; + $EBMLidList[EBML_ID_TRACKOFFSET] = 'TrackOffset'; + $EBMLidList[EBML_ID_TRACKOVERLAY] = 'TrackOverlay'; + $EBMLidList[EBML_ID_TRACKS] = 'Tracks'; + $EBMLidList[EBML_ID_TRACKTIMECODESCALE] = 'TrackTimecodeScale'; + $EBMLidList[EBML_ID_TRACKTRANSLATE] = 'TrackTranslate'; + $EBMLidList[EBML_ID_TRACKTRANSLATECODEC] = 'TrackTranslateCodec'; + $EBMLidList[EBML_ID_TRACKTRANSLATEEDITIONUID] = 'TrackTranslateEditionUID'; + $EBMLidList[EBML_ID_TRACKTRANSLATETRACKID] = 'TrackTranslateTrackID'; + $EBMLidList[EBML_ID_TRACKTYPE] = 'TrackType'; + $EBMLidList[EBML_ID_TRACKUID] = 'TrackUID'; + $EBMLidList[EBML_ID_VIDEO] = 'Video'; + $EBMLidList[EBML_ID_VOID] = 'Void'; + $EBMLidList[EBML_ID_WRITINGAPP] = 'WritingApp'; + } + + return (isset($EBMLidList[$value]) ? $EBMLidList[$value] : dechex($value)); + } + + public static function displayUnit($value) { + // http://www.matroska.org/technical/specs/index.html#DisplayUnit + static $units = array( + 0 => 'pixels', + 1 => 'centimeters', + 2 => 'inches', + 3 => 'Display Aspect Ratio'); + + return (isset($units[$value]) ? $units[$value] : 'unknown'); + } + + private static function getDefaultStreamInfo($streams) + { + foreach (array_reverse($streams) as $stream) { + if ($stream['default']) { + break; + } + } + + $unset = array('default', 'name'); + foreach ($unset as $u) { + if (isset($stream[$u])) { + unset($stream[$u]); + } + } + + $info = $stream; + $info['streams'] = $streams; + + return $info; + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.mpeg.php b/app/libs/vendor/getid3/module.audio-video.mpeg.php index fd46f11b..999c5d9a 100644 --- a/app/libs/vendor/getid3/module.audio-video.mpeg.php +++ b/app/libs/vendor/getid3/module.audio-video.mpeg.php @@ -1,296 +1,296 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.mpeg.php // -// module for analyzing MPEG files // -// dependencies: module.audio.mp3.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); - -define('GETID3_MPEG_VIDEO_PICTURE_START', "\x00\x00\x01\x00"); -define('GETID3_MPEG_VIDEO_USER_DATA_START', "\x00\x00\x01\xB2"); -define('GETID3_MPEG_VIDEO_SEQUENCE_HEADER', "\x00\x00\x01\xB3"); -define('GETID3_MPEG_VIDEO_SEQUENCE_ERROR', "\x00\x00\x01\xB4"); -define('GETID3_MPEG_VIDEO_EXTENSION_START', "\x00\x00\x01\xB5"); -define('GETID3_MPEG_VIDEO_SEQUENCE_END', "\x00\x00\x01\xB7"); -define('GETID3_MPEG_VIDEO_GROUP_START', "\x00\x00\x01\xB8"); -define('GETID3_MPEG_AUDIO_START', "\x00\x00\x01\xC0"); - - -class getid3_mpeg extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - if ($info['avdataend'] <= $info['avdataoffset']) { - $info['error'][] = '"avdataend" ('.$info['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$info['avdataoffset'].')'; - return false; - } - $info['fileformat'] = 'mpeg'; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $MPEGstreamData = fread($this->getid3->fp, min(100000, $info['avdataend'] - $info['avdataoffset'])); - $MPEGstreamDataLength = strlen($MPEGstreamData); - - $foundVideo = true; - $VideoChunkOffset = 0; - while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== GETID3_MPEG_VIDEO_SEQUENCE_HEADER) { - if ($VideoChunkOffset >= $MPEGstreamDataLength) { - $foundVideo = false; - break; - } - } - if ($foundVideo) { - - // Start code 32 bits - // horizontal frame size 12 bits - // vertical frame size 12 bits - // pixel aspect ratio 4 bits - // frame rate 4 bits - // bitrate 18 bits - // marker bit 1 bit - // VBV buffer size 10 bits - // constrained parameter flag 1 bit - // intra quant. matrix flag 1 bit - // intra quant. matrix values 512 bits (present if matrix flag == 1) - // non-intra quant. matrix flag 1 bit - // non-intra quant. matrix values 512 bits (present if matrix flag == 1) - - $info['video']['dataformat'] = 'mpeg'; - - $VideoChunkOffset += (strlen(GETID3_MPEG_VIDEO_SEQUENCE_HEADER) - 1); - - $FrameSizeDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3)); - $VideoChunkOffset += 3; - - $AspectRatioFrameRateDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1)); - $VideoChunkOffset += 1; - - $assortedinformation = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4)); - $VideoChunkOffset += 4; - - $info['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size - $info['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size - $info['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4; - $info['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F); - - $info['mpeg']['video']['framesize_horizontal'] = $info['mpeg']['video']['raw']['framesize_horizontal']; - $info['mpeg']['video']['framesize_vertical'] = $info['mpeg']['video']['raw']['framesize_vertical']; - - $info['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']); - $info['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']); - $info['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($info['mpeg']['video']['raw']['frame_rate']); - - $info['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18)); - $info['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1)); - $info['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10)); - $info['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1)); - $info['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1)); - if ($info['mpeg']['video']['raw']['intra_quant_flag']) { - - // read 512 bits - $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)); - $VideoChunkOffset += 64; - - $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($info['mpeg']['video']['raw']['intra_quant'], 511, 1)); - $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511); - - if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) { - $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64); - $VideoChunkOffset += 64; - } - - } else { - - $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)); - if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) { - $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64); - $VideoChunkOffset += 64; - } - - } - - if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits - - $info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files'; - $info['mpeg']['video']['bitrate_mode'] = 'vbr'; - - } else { - - $info['mpeg']['video']['bitrate'] = $info['mpeg']['video']['raw']['bitrate'] * 400; - $info['mpeg']['video']['bitrate_mode'] = 'cbr'; - $info['video']['bitrate'] = $info['mpeg']['video']['bitrate']; - - } - - $info['video']['resolution_x'] = $info['mpeg']['video']['framesize_horizontal']; - $info['video']['resolution_y'] = $info['mpeg']['video']['framesize_vertical']; - $info['video']['frame_rate'] = $info['mpeg']['video']['frame_rate']; - $info['video']['bitrate_mode'] = $info['mpeg']['video']['bitrate_mode']; - $info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio']; - $info['video']['lossless'] = false; - $info['video']['bits_per_sample'] = 24; - - } else { - - $info['error'][] = 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?'; - - } - - //0x000001B3 begins the sequence_header of every MPEG video stream. - //But in MPEG-2, this header must immediately be followed by an - //extension_start_code (0x000001B5) with a sequence_extension ID (1). - //(This extension contains all the additional MPEG-2 stuff.) - //MPEG-1 doesn't have this extension, so that's a sure way to tell the - //difference between MPEG-1 and MPEG-2 video streams. - - if (substr($MPEGstreamData, $VideoChunkOffset, 4) == GETID3_MPEG_VIDEO_EXTENSION_START) { - $info['video']['codec'] = 'MPEG-2'; - } else { - $info['video']['codec'] = 'MPEG-1'; - } - - - $AudioChunkOffset = 0; - while (true) { - while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) { - if ($AudioChunkOffset >= $MPEGstreamDataLength) { - break 2; - } - } - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info = $info; - $getid3_mp3 = new getid3_mp3($getid3_temp); - for ($i = 0; $i <= 7; $i++) { - // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after - // I have no idea why or what the difference is, so this is a stupid hack. - // If anybody has any better idea of what's going on, please let me know - info@getid3.org - fseek($getid3_temp->fp, ftell($this->getid3->fp), SEEK_SET); - $getid3_temp->info = $info; // only overwrite real data if valid header found - if ($getid3_mp3->decodeMPEGaudioHeader(($AudioChunkOffset + 3) + 8 + $i, $getid3_temp->info, false)) { - $info = $getid3_temp->info; - $info['audio']['bitrate_mode'] = 'cbr'; - $info['audio']['lossless'] = false; - unset($getid3_temp, $getid3_mp3); - break 2; - } - } - unset($getid3_temp, $getid3_mp3); - } - - // Temporary hack to account for interleaving overhead: - if (!empty($info['video']['bitrate']) && !empty($info['audio']['bitrate'])) { - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['video']['bitrate'] + $info['audio']['bitrate']); - - // Interleaved MPEG audio/video files have a certain amount of overhead that varies - // by both video and audio bitrates, and not in any sensible, linear/logarithmic patter - // Use interpolated lookup tables to approximately guess how much is overhead, because - // playtime is calculated as filesize / total-bitrate - $info['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($info['video']['bitrate'], $info['audio']['bitrate']); - - //switch ($info['video']['bitrate']) { - // case('5000000'): - // $multiplier = 0.93292642112380355828048824319889; - // break; - // case('5500000'): - // $multiplier = 0.93582895375200989965359777343219; - // break; - // case('6000000'): - // $multiplier = 0.93796247714820932532911373859139; - // break; - // case('7000000'): - // $multiplier = 0.9413264083635103463010117778776; - // break; - // default: - // $multiplier = 1; - // break; - //} - //$info['playtime_seconds'] *= $multiplier; - //$info['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.'; - if ($info['video']['bitrate'] < 50000) { - $info['warning'][] = 'Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.'; - } - } - - return true; - } - - - public function MPEGsystemNonOverheadPercentage($VideoBitrate, $AudioBitrate) { - $OverheadPercentage = 0; - - $AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?) - $VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss) - - - //OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps) - $OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940); - $OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960); - $OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340); - $OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470); - $OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690); - $OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050); - $OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570); - $OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620); - $OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480); - $OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790); - $OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190); - $OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890); - - $BitrateToUseMin = 32; - $BitrateToUseMax = 32; - $previousBitrate = 32; - foreach ($OverheadMultiplierByBitrate as $key => $value) { - if ($AudioBitrate >= $previousBitrate) { - $BitrateToUseMin = $previousBitrate; - } - if ($AudioBitrate < $key) { - $BitrateToUseMax = $key; - break; - } - $previousBitrate = $key; - } - $FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin); - - $VideoBitrateLog10 = log10($VideoBitrate); - $VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)]; - $VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)]; - $VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)]; - $VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)]; - $FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10); - - $OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV; - $OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV; - $OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV); - $OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV); - - return $OverheadPercentage; - } - - - public function MPEGvideoFramerateLookup($rawframerate) { - $MPEGvideoFramerateLookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60); - return (isset($MPEGvideoFramerateLookup[$rawframerate]) ? (float) $MPEGvideoFramerateLookup[$rawframerate] : (float) 0); - } - - public function MPEGvideoAspectRatioLookup($rawaspectratio) { - $MPEGvideoAspectRatioLookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0); - return (isset($MPEGvideoAspectRatioLookup[$rawaspectratio]) ? (float) $MPEGvideoAspectRatioLookup[$rawaspectratio] : (float) 0); - } - - public function MPEGvideoAspectRatioTextLookup($rawaspectratio) { - $MPEGvideoAspectRatioTextLookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved'); - return (isset($MPEGvideoAspectRatioTextLookup[$rawaspectratio]) ? $MPEGvideoAspectRatioTextLookup[$rawaspectratio] : ''); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.mpeg.php // +// module for analyzing MPEG files // +// dependencies: module.audio.mp3.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); + +define('GETID3_MPEG_VIDEO_PICTURE_START', "\x00\x00\x01\x00"); +define('GETID3_MPEG_VIDEO_USER_DATA_START', "\x00\x00\x01\xB2"); +define('GETID3_MPEG_VIDEO_SEQUENCE_HEADER', "\x00\x00\x01\xB3"); +define('GETID3_MPEG_VIDEO_SEQUENCE_ERROR', "\x00\x00\x01\xB4"); +define('GETID3_MPEG_VIDEO_EXTENSION_START', "\x00\x00\x01\xB5"); +define('GETID3_MPEG_VIDEO_SEQUENCE_END', "\x00\x00\x01\xB7"); +define('GETID3_MPEG_VIDEO_GROUP_START', "\x00\x00\x01\xB8"); +define('GETID3_MPEG_AUDIO_START', "\x00\x00\x01\xC0"); + + +class getid3_mpeg extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + if ($info['avdataend'] <= $info['avdataoffset']) { + $info['error'][] = '"avdataend" ('.$info['avdataend'].') is unexpectedly less-than-or-equal-to "avdataoffset" ('.$info['avdataoffset'].')'; + return false; + } + $info['fileformat'] = 'mpeg'; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $MPEGstreamData = fread($this->getid3->fp, min(100000, $info['avdataend'] - $info['avdataoffset'])); + $MPEGstreamDataLength = strlen($MPEGstreamData); + + $foundVideo = true; + $VideoChunkOffset = 0; + while (substr($MPEGstreamData, $VideoChunkOffset++, 4) !== GETID3_MPEG_VIDEO_SEQUENCE_HEADER) { + if ($VideoChunkOffset >= $MPEGstreamDataLength) { + $foundVideo = false; + break; + } + } + if ($foundVideo) { + + // Start code 32 bits + // horizontal frame size 12 bits + // vertical frame size 12 bits + // pixel aspect ratio 4 bits + // frame rate 4 bits + // bitrate 18 bits + // marker bit 1 bit + // VBV buffer size 10 bits + // constrained parameter flag 1 bit + // intra quant. matrix flag 1 bit + // intra quant. matrix values 512 bits (present if matrix flag == 1) + // non-intra quant. matrix flag 1 bit + // non-intra quant. matrix values 512 bits (present if matrix flag == 1) + + $info['video']['dataformat'] = 'mpeg'; + + $VideoChunkOffset += (strlen(GETID3_MPEG_VIDEO_SEQUENCE_HEADER) - 1); + + $FrameSizeDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 3)); + $VideoChunkOffset += 3; + + $AspectRatioFrameRateDWORD = getid3_lib::BigEndian2Int(substr($MPEGstreamData, $VideoChunkOffset, 1)); + $VideoChunkOffset += 1; + + $assortedinformation = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 4)); + $VideoChunkOffset += 4; + + $info['mpeg']['video']['raw']['framesize_horizontal'] = ($FrameSizeDWORD & 0xFFF000) >> 12; // 12 bits for horizontal frame size + $info['mpeg']['video']['raw']['framesize_vertical'] = ($FrameSizeDWORD & 0x000FFF); // 12 bits for vertical frame size + $info['mpeg']['video']['raw']['pixel_aspect_ratio'] = ($AspectRatioFrameRateDWORD & 0xF0) >> 4; + $info['mpeg']['video']['raw']['frame_rate'] = ($AspectRatioFrameRateDWORD & 0x0F); + + $info['mpeg']['video']['framesize_horizontal'] = $info['mpeg']['video']['raw']['framesize_horizontal']; + $info['mpeg']['video']['framesize_vertical'] = $info['mpeg']['video']['raw']['framesize_vertical']; + + $info['mpeg']['video']['pixel_aspect_ratio'] = $this->MPEGvideoAspectRatioLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']); + $info['mpeg']['video']['pixel_aspect_ratio_text'] = $this->MPEGvideoAspectRatioTextLookup($info['mpeg']['video']['raw']['pixel_aspect_ratio']); + $info['mpeg']['video']['frame_rate'] = $this->MPEGvideoFramerateLookup($info['mpeg']['video']['raw']['frame_rate']); + + $info['mpeg']['video']['raw']['bitrate'] = getid3_lib::Bin2Dec(substr($assortedinformation, 0, 18)); + $info['mpeg']['video']['raw']['marker_bit'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 18, 1)); + $info['mpeg']['video']['raw']['vbv_buffer_size'] = getid3_lib::Bin2Dec(substr($assortedinformation, 19, 10)); + $info['mpeg']['video']['raw']['constrained_param_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 29, 1)); + $info['mpeg']['video']['raw']['intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 30, 1)); + if ($info['mpeg']['video']['raw']['intra_quant_flag']) { + + // read 512 bits + $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)); + $VideoChunkOffset += 64; + + $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($info['mpeg']['video']['raw']['intra_quant'], 511, 1)); + $info['mpeg']['video']['raw']['intra_quant'] = getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)).substr(getid3_lib::BigEndian2Bin(substr($MPEGstreamData, $VideoChunkOffset, 64)), 0, 511); + + if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) { + $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64); + $VideoChunkOffset += 64; + } + + } else { + + $info['mpeg']['video']['raw']['non_intra_quant_flag'] = (bool) getid3_lib::Bin2Dec(substr($assortedinformation, 31, 1)); + if ($info['mpeg']['video']['raw']['non_intra_quant_flag']) { + $info['mpeg']['video']['raw']['non_intra_quant'] = substr($MPEGstreamData, $VideoChunkOffset, 64); + $VideoChunkOffset += 64; + } + + } + + if ($info['mpeg']['video']['raw']['bitrate'] == 0x3FFFF) { // 18 set bits + + $info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] cannot determine average bitrate of VBR MPEG video files'; + $info['mpeg']['video']['bitrate_mode'] = 'vbr'; + + } else { + + $info['mpeg']['video']['bitrate'] = $info['mpeg']['video']['raw']['bitrate'] * 400; + $info['mpeg']['video']['bitrate_mode'] = 'cbr'; + $info['video']['bitrate'] = $info['mpeg']['video']['bitrate']; + + } + + $info['video']['resolution_x'] = $info['mpeg']['video']['framesize_horizontal']; + $info['video']['resolution_y'] = $info['mpeg']['video']['framesize_vertical']; + $info['video']['frame_rate'] = $info['mpeg']['video']['frame_rate']; + $info['video']['bitrate_mode'] = $info['mpeg']['video']['bitrate_mode']; + $info['video']['pixel_aspect_ratio'] = $info['mpeg']['video']['pixel_aspect_ratio']; + $info['video']['lossless'] = false; + $info['video']['bits_per_sample'] = 24; + + } else { + + $info['error'][] = 'Could not find start of video block in the first 100,000 bytes (or before end of file) - this might not be an MPEG-video file?'; + + } + + //0x000001B3 begins the sequence_header of every MPEG video stream. + //But in MPEG-2, this header must immediately be followed by an + //extension_start_code (0x000001B5) with a sequence_extension ID (1). + //(This extension contains all the additional MPEG-2 stuff.) + //MPEG-1 doesn't have this extension, so that's a sure way to tell the + //difference between MPEG-1 and MPEG-2 video streams. + + if (substr($MPEGstreamData, $VideoChunkOffset, 4) == GETID3_MPEG_VIDEO_EXTENSION_START) { + $info['video']['codec'] = 'MPEG-2'; + } else { + $info['video']['codec'] = 'MPEG-1'; + } + + + $AudioChunkOffset = 0; + while (true) { + while (substr($MPEGstreamData, $AudioChunkOffset++, 4) !== GETID3_MPEG_AUDIO_START) { + if ($AudioChunkOffset >= $MPEGstreamDataLength) { + break 2; + } + } + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info = $info; + $getid3_mp3 = new getid3_mp3($getid3_temp); + for ($i = 0; $i <= 7; $i++) { + // some files have the MPEG-audio header 8 bytes after the end of the $00 $00 $01 $C0 signature, some have it up to 13 bytes (or more?) after + // I have no idea why or what the difference is, so this is a stupid hack. + // If anybody has any better idea of what's going on, please let me know - info@getid3.org + fseek($getid3_temp->fp, ftell($this->getid3->fp), SEEK_SET); + $getid3_temp->info = $info; // only overwrite real data if valid header found + if ($getid3_mp3->decodeMPEGaudioHeader(($AudioChunkOffset + 3) + 8 + $i, $getid3_temp->info, false)) { + $info = $getid3_temp->info; + $info['audio']['bitrate_mode'] = 'cbr'; + $info['audio']['lossless'] = false; + unset($getid3_temp, $getid3_mp3); + break 2; + } + } + unset($getid3_temp, $getid3_mp3); + } + + // Temporary hack to account for interleaving overhead: + if (!empty($info['video']['bitrate']) && !empty($info['audio']['bitrate'])) { + $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['video']['bitrate'] + $info['audio']['bitrate']); + + // Interleaved MPEG audio/video files have a certain amount of overhead that varies + // by both video and audio bitrates, and not in any sensible, linear/logarithmic patter + // Use interpolated lookup tables to approximately guess how much is overhead, because + // playtime is calculated as filesize / total-bitrate + $info['playtime_seconds'] *= $this->MPEGsystemNonOverheadPercentage($info['video']['bitrate'], $info['audio']['bitrate']); + + //switch ($info['video']['bitrate']) { + // case('5000000'): + // $multiplier = 0.93292642112380355828048824319889; + // break; + // case('5500000'): + // $multiplier = 0.93582895375200989965359777343219; + // break; + // case('6000000'): + // $multiplier = 0.93796247714820932532911373859139; + // break; + // case('7000000'): + // $multiplier = 0.9413264083635103463010117778776; + // break; + // default: + // $multiplier = 1; + // break; + //} + //$info['playtime_seconds'] *= $multiplier; + //$info['warning'][] = 'Interleaved MPEG audio/video playtime may be inaccurate. With current hack should be within a few seconds of accurate. Report to info@getid3.org if off by more than 10 seconds.'; + if ($info['video']['bitrate'] < 50000) { + $info['warning'][] = 'Interleaved MPEG audio/video playtime may be slightly inaccurate for video bitrates below 100kbps. Except in extreme low-bitrate situations, error should be less than 1%. Report to info@getid3.org if greater than this.'; + } + } + + return true; + } + + + public function MPEGsystemNonOverheadPercentage($VideoBitrate, $AudioBitrate) { + $OverheadPercentage = 0; + + $AudioBitrate = max(min($AudioBitrate / 1000, 384), 32); // limit to range of 32kbps - 384kbps (should be only legal bitrates, but maybe VBR?) + $VideoBitrate = max(min($VideoBitrate / 1000, 10000), 10); // limit to range of 10kbps - 10Mbps (beyond that curves flatten anyways, no big loss) + + + //OMBB[audiobitrate] = array(video-10kbps, video-100kbps, video-1000kbps, video-10000kbps) + $OverheadMultiplierByBitrate[32] = array(0, 0.9676287944368530, 0.9802276264360310, 0.9844916183244460, 0.9852821845179940); + $OverheadMultiplierByBitrate[48] = array(0, 0.9779100089209830, 0.9787770035359320, 0.9846738664076130, 0.9852683013799960); + $OverheadMultiplierByBitrate[56] = array(0, 0.9731249855367600, 0.9776624308938040, 0.9832606361852130, 0.9843922606633340); + $OverheadMultiplierByBitrate[64] = array(0, 0.9755642683275760, 0.9795256705493390, 0.9836573009193170, 0.9851122539404470); + $OverheadMultiplierByBitrate[96] = array(0, 0.9788025247497290, 0.9798553314148700, 0.9822956869792560, 0.9834815119124690); + $OverheadMultiplierByBitrate[128] = array(0, 0.9816940050925480, 0.9821675936072120, 0.9829756927470870, 0.9839763420152050); + $OverheadMultiplierByBitrate[160] = array(0, 0.9825894094561180, 0.9820913399073960, 0.9823907143253970, 0.9832821783651570); + $OverheadMultiplierByBitrate[192] = array(0, 0.9832038474336260, 0.9825731694317960, 0.9821028622712400, 0.9828262076447620); + $OverheadMultiplierByBitrate[224] = array(0, 0.9836516298538770, 0.9824718601823890, 0.9818302180625380, 0.9823735101626480); + $OverheadMultiplierByBitrate[256] = array(0, 0.9845863022094920, 0.9837229411967540, 0.9824521662210830, 0.9828645172100790); + $OverheadMultiplierByBitrate[320] = array(0, 0.9849565280263180, 0.9837683142805110, 0.9822885275960400, 0.9824424382727190); + $OverheadMultiplierByBitrate[384] = array(0, 0.9856094774357600, 0.9844573394432720, 0.9825970399837330, 0.9824673808303890); + + $BitrateToUseMin = 32; + $BitrateToUseMax = 32; + $previousBitrate = 32; + foreach ($OverheadMultiplierByBitrate as $key => $value) { + if ($AudioBitrate >= $previousBitrate) { + $BitrateToUseMin = $previousBitrate; + } + if ($AudioBitrate < $key) { + $BitrateToUseMax = $key; + break; + } + $previousBitrate = $key; + } + $FactorA = ($BitrateToUseMax - $AudioBitrate) / ($BitrateToUseMax - $BitrateToUseMin); + + $VideoBitrateLog10 = log10($VideoBitrate); + $VideoFactorMin1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][floor($VideoBitrateLog10)]; + $VideoFactorMin2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][floor($VideoBitrateLog10)]; + $VideoFactorMax1 = $OverheadMultiplierByBitrate[$BitrateToUseMin][ceil($VideoBitrateLog10)]; + $VideoFactorMax2 = $OverheadMultiplierByBitrate[$BitrateToUseMax][ceil($VideoBitrateLog10)]; + $FactorV = $VideoBitrateLog10 - floor($VideoBitrateLog10); + + $OverheadPercentage = $VideoFactorMin1 * $FactorA * $FactorV; + $OverheadPercentage += $VideoFactorMin2 * (1 - $FactorA) * $FactorV; + $OverheadPercentage += $VideoFactorMax1 * $FactorA * (1 - $FactorV); + $OverheadPercentage += $VideoFactorMax2 * (1 - $FactorA) * (1 - $FactorV); + + return $OverheadPercentage; + } + + + public function MPEGvideoFramerateLookup($rawframerate) { + $MPEGvideoFramerateLookup = array(0, 23.976, 24, 25, 29.97, 30, 50, 59.94, 60); + return (isset($MPEGvideoFramerateLookup[$rawframerate]) ? (float) $MPEGvideoFramerateLookup[$rawframerate] : (float) 0); + } + + public function MPEGvideoAspectRatioLookup($rawaspectratio) { + $MPEGvideoAspectRatioLookup = array(0, 1, 0.6735, 0.7031, 0.7615, 0.8055, 0.8437, 0.8935, 0.9157, 0.9815, 1.0255, 1.0695, 1.0950, 1.1575, 1.2015, 0); + return (isset($MPEGvideoAspectRatioLookup[$rawaspectratio]) ? (float) $MPEGvideoAspectRatioLookup[$rawaspectratio] : (float) 0); + } + + public function MPEGvideoAspectRatioTextLookup($rawaspectratio) { + $MPEGvideoAspectRatioTextLookup = array('forbidden', 'square pixels', '0.6735', '16:9, 625 line, PAL', '0.7615', '0.8055', '16:9, 525 line, NTSC', '0.8935', '4:3, 625 line, PAL, CCIR601', '0.9815', '1.0255', '1.0695', '4:3, 525 line, NTSC, CCIR601', '1.1575', '1.2015', 'reserved'); + return (isset($MPEGvideoAspectRatioTextLookup[$rawaspectratio]) ? $MPEGvideoAspectRatioTextLookup[$rawaspectratio] : ''); + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.nsv.php b/app/libs/vendor/getid3/module.audio-video.nsv.php index 10c27efd..3191eb3b 100644 --- a/app/libs/vendor/getid3/module.audio-video.nsv.php +++ b/app/libs/vendor/getid3/module.audio-video.nsv.php @@ -1,223 +1,223 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.nsv.php // -// module for analyzing Nullsoft NSV files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_nsv extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $NSVheader = fread($this->getid3->fp, 4); - - switch ($NSVheader) { - case 'NSVs': - if ($this->getNSVsHeaderFilepointer(0)) { - $info['fileformat'] = 'nsv'; - $info['audio']['dataformat'] = 'nsv'; - $info['video']['dataformat'] = 'nsv'; - $info['audio']['lossless'] = false; - $info['video']['lossless'] = false; - } - break; - - case 'NSVf': - if ($this->getNSVfHeaderFilepointer(0)) { - $info['fileformat'] = 'nsv'; - $info['audio']['dataformat'] = 'nsv'; - $info['video']['dataformat'] = 'nsv'; - $info['audio']['lossless'] = false; - $info['video']['lossless'] = false; - $this->getNSVsHeaderFilepointer($info['nsv']['NSVf']['header_length']); - } - break; - - default: - $info['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"'; - return false; - break; - } - - if (!isset($info['nsv']['NSVf'])) { - $info['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate'; - } - - return true; - } - - public function getNSVsHeaderFilepointer($fileoffset) { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $fileoffset, SEEK_SET); - $NSVsheader = fread($this->getid3->fp, 28); - $offset = 0; - - $info['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4); - $offset += 4; - - if ($info['nsv']['NSVs']['identifier'] != 'NSVs') { - $info['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead'; - unset($info['nsv']['NSVs']); - return false; - } - - $info['nsv']['NSVs']['offset'] = $fileoffset; - - $info['nsv']['NSVs']['video_codec'] = substr($NSVsheader, $offset, 4); - $offset += 4; - $info['nsv']['NSVs']['audio_codec'] = substr($NSVsheader, $offset, 4); - $offset += 4; - $info['nsv']['NSVs']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); - $offset += 2; - $info['nsv']['NSVs']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); - $offset += 2; - - $info['nsv']['NSVs']['framerate_index'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown1b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown1c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown1d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown2a'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown2b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown2c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - //$info['nsv']['NSVs']['unknown2d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - - switch ($info['nsv']['NSVs']['audio_codec']) { - case 'PCM ': - $info['nsv']['NSVs']['bits_channel'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - $info['nsv']['NSVs']['channels'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); - $offset += 1; - $info['nsv']['NSVs']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); - $offset += 2; - - $info['audio']['sample_rate'] = $info['nsv']['NSVs']['sample_rate']; - break; - - case 'MP3 ': - case 'NONE': - default: - //$info['nsv']['NSVs']['unknown3'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 4)); - $offset += 4; - break; - } - - $info['video']['resolution_x'] = $info['nsv']['NSVs']['resolution_x']; - $info['video']['resolution_y'] = $info['nsv']['NSVs']['resolution_y']; - $info['nsv']['NSVs']['frame_rate'] = $this->NSVframerateLookup($info['nsv']['NSVs']['framerate_index']); - $info['video']['frame_rate'] = $info['nsv']['NSVs']['frame_rate']; - $info['video']['bits_per_sample'] = 24; - $info['video']['pixel_aspect_ratio'] = (float) 1; - - return true; - } - - public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $fileoffset, SEEK_SET); - $NSVfheader = fread($this->getid3->fp, 28); - $offset = 0; - - $info['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4); - $offset += 4; - - if ($info['nsv']['NSVf']['identifier'] != 'NSVf') { - $info['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead'; - unset($info['nsv']['NSVf']); - return false; - } - - $info['nsv']['NSVs']['offset'] = $fileoffset; - - $info['nsv']['NSVf']['header_length'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - $info['nsv']['NSVf']['file_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - - if ($info['nsv']['NSVf']['file_size'] > $info['avdataend']) { - $info['warning'][] = 'truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes'; - } - - $info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - $info['nsv']['NSVf']['meta_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - $info['nsv']['NSVf']['TOC_entries_1'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - $info['nsv']['NSVf']['TOC_entries_2'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - - if ($info['nsv']['NSVf']['playtime_ms'] == 0) { - $info['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero'; - return false; - } - - $NSVfheader .= fread($this->getid3->fp, $info['nsv']['NSVf']['meta_size'] + (4 * $info['nsv']['NSVf']['TOC_entries_1']) + (4 * $info['nsv']['NSVf']['TOC_entries_2'])); - $NSVfheaderlength = strlen($NSVfheader); - $info['nsv']['NSVf']['metadata'] = substr($NSVfheader, $offset, $info['nsv']['NSVf']['meta_size']); - $offset += $info['nsv']['NSVf']['meta_size']; - - if ($getTOCoffsets) { - $TOCcounter = 0; - while ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) { - if ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) { - $info['nsv']['NSVf']['TOC_1'][$TOCcounter] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); - $offset += 4; - $TOCcounter++; - } - } - } - - if (trim($info['nsv']['NSVf']['metadata']) != '') { - $info['nsv']['NSVf']['metadata'] = str_replace('`', "\x01", $info['nsv']['NSVf']['metadata']); - $CommentPairArray = explode("\x01".' ', $info['nsv']['NSVf']['metadata']); - foreach ($CommentPairArray as $CommentPair) { - if (strstr($CommentPair, '='."\x01")) { - list($key, $value) = explode('='."\x01", $CommentPair, 2); - $info['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value)); - } - } - } - - $info['playtime_seconds'] = $info['nsv']['NSVf']['playtime_ms'] / 1000; - $info['bitrate'] = ($info['nsv']['NSVf']['file_size'] * 8) / $info['playtime_seconds']; - - return true; - } - - - public static function NSVframerateLookup($framerateindex) { - if ($framerateindex <= 127) { - return (float) $framerateindex; - } - static $NSVframerateLookup = array(); - if (empty($NSVframerateLookup)) { - $NSVframerateLookup[129] = (float) 29.970; - $NSVframerateLookup[131] = (float) 23.976; - $NSVframerateLookup[133] = (float) 14.985; - $NSVframerateLookup[197] = (float) 59.940; - $NSVframerateLookup[199] = (float) 47.952; - } - return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.nsv.php // +// module for analyzing Nullsoft NSV files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_nsv extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $NSVheader = fread($this->getid3->fp, 4); + + switch ($NSVheader) { + case 'NSVs': + if ($this->getNSVsHeaderFilepointer(0)) { + $info['fileformat'] = 'nsv'; + $info['audio']['dataformat'] = 'nsv'; + $info['video']['dataformat'] = 'nsv'; + $info['audio']['lossless'] = false; + $info['video']['lossless'] = false; + } + break; + + case 'NSVf': + if ($this->getNSVfHeaderFilepointer(0)) { + $info['fileformat'] = 'nsv'; + $info['audio']['dataformat'] = 'nsv'; + $info['video']['dataformat'] = 'nsv'; + $info['audio']['lossless'] = false; + $info['video']['lossless'] = false; + $this->getNSVsHeaderFilepointer($info['nsv']['NSVf']['header_length']); + } + break; + + default: + $info['error'][] = 'Expecting "NSVs" or "NSVf" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($NSVheader).'"'; + return false; + break; + } + + if (!isset($info['nsv']['NSVf'])) { + $info['warning'][] = 'NSVf header not present - cannot calculate playtime or bitrate'; + } + + return true; + } + + public function getNSVsHeaderFilepointer($fileoffset) { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $fileoffset, SEEK_SET); + $NSVsheader = fread($this->getid3->fp, 28); + $offset = 0; + + $info['nsv']['NSVs']['identifier'] = substr($NSVsheader, $offset, 4); + $offset += 4; + + if ($info['nsv']['NSVs']['identifier'] != 'NSVs') { + $info['error'][] = 'expected "NSVs" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVs']['identifier'].'" instead'; + unset($info['nsv']['NSVs']); + return false; + } + + $info['nsv']['NSVs']['offset'] = $fileoffset; + + $info['nsv']['NSVs']['video_codec'] = substr($NSVsheader, $offset, 4); + $offset += 4; + $info['nsv']['NSVs']['audio_codec'] = substr($NSVsheader, $offset, 4); + $offset += 4; + $info['nsv']['NSVs']['resolution_x'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); + $offset += 2; + $info['nsv']['NSVs']['resolution_y'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); + $offset += 2; + + $info['nsv']['NSVs']['framerate_index'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown1b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown1c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown1d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown2a'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown2b'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown2c'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + //$info['nsv']['NSVs']['unknown2d'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + + switch ($info['nsv']['NSVs']['audio_codec']) { + case 'PCM ': + $info['nsv']['NSVs']['bits_channel'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + $info['nsv']['NSVs']['channels'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 1)); + $offset += 1; + $info['nsv']['NSVs']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 2)); + $offset += 2; + + $info['audio']['sample_rate'] = $info['nsv']['NSVs']['sample_rate']; + break; + + case 'MP3 ': + case 'NONE': + default: + //$info['nsv']['NSVs']['unknown3'] = getid3_lib::LittleEndian2Int(substr($NSVsheader, $offset, 4)); + $offset += 4; + break; + } + + $info['video']['resolution_x'] = $info['nsv']['NSVs']['resolution_x']; + $info['video']['resolution_y'] = $info['nsv']['NSVs']['resolution_y']; + $info['nsv']['NSVs']['frame_rate'] = $this->NSVframerateLookup($info['nsv']['NSVs']['framerate_index']); + $info['video']['frame_rate'] = $info['nsv']['NSVs']['frame_rate']; + $info['video']['bits_per_sample'] = 24; + $info['video']['pixel_aspect_ratio'] = (float) 1; + + return true; + } + + public function getNSVfHeaderFilepointer($fileoffset, $getTOCoffsets=false) { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $fileoffset, SEEK_SET); + $NSVfheader = fread($this->getid3->fp, 28); + $offset = 0; + + $info['nsv']['NSVf']['identifier'] = substr($NSVfheader, $offset, 4); + $offset += 4; + + if ($info['nsv']['NSVf']['identifier'] != 'NSVf') { + $info['error'][] = 'expected "NSVf" at offset ('.$fileoffset.'), found "'.$info['nsv']['NSVf']['identifier'].'" instead'; + unset($info['nsv']['NSVf']); + return false; + } + + $info['nsv']['NSVs']['offset'] = $fileoffset; + + $info['nsv']['NSVf']['header_length'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + $info['nsv']['NSVf']['file_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + + if ($info['nsv']['NSVf']['file_size'] > $info['avdataend']) { + $info['warning'][] = 'truncated file - NSVf header indicates '.$info['nsv']['NSVf']['file_size'].' bytes, file actually '.$info['avdataend'].' bytes'; + } + + $info['nsv']['NSVf']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + $info['nsv']['NSVf']['meta_size'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + $info['nsv']['NSVf']['TOC_entries_1'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + $info['nsv']['NSVf']['TOC_entries_2'] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + + if ($info['nsv']['NSVf']['playtime_ms'] == 0) { + $info['error'][] = 'Corrupt NSV file: NSVf.playtime_ms == zero'; + return false; + } + + $NSVfheader .= fread($this->getid3->fp, $info['nsv']['NSVf']['meta_size'] + (4 * $info['nsv']['NSVf']['TOC_entries_1']) + (4 * $info['nsv']['NSVf']['TOC_entries_2'])); + $NSVfheaderlength = strlen($NSVfheader); + $info['nsv']['NSVf']['metadata'] = substr($NSVfheader, $offset, $info['nsv']['NSVf']['meta_size']); + $offset += $info['nsv']['NSVf']['meta_size']; + + if ($getTOCoffsets) { + $TOCcounter = 0; + while ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) { + if ($TOCcounter < $info['nsv']['NSVf']['TOC_entries_1']) { + $info['nsv']['NSVf']['TOC_1'][$TOCcounter] = getid3_lib::LittleEndian2Int(substr($NSVfheader, $offset, 4)); + $offset += 4; + $TOCcounter++; + } + } + } + + if (trim($info['nsv']['NSVf']['metadata']) != '') { + $info['nsv']['NSVf']['metadata'] = str_replace('`', "\x01", $info['nsv']['NSVf']['metadata']); + $CommentPairArray = explode("\x01".' ', $info['nsv']['NSVf']['metadata']); + foreach ($CommentPairArray as $CommentPair) { + if (strstr($CommentPair, '='."\x01")) { + list($key, $value) = explode('='."\x01", $CommentPair, 2); + $info['nsv']['comments'][strtolower($key)][] = trim(str_replace("\x01", '', $value)); + } + } + } + + $info['playtime_seconds'] = $info['nsv']['NSVf']['playtime_ms'] / 1000; + $info['bitrate'] = ($info['nsv']['NSVf']['file_size'] * 8) / $info['playtime_seconds']; + + return true; + } + + + public static function NSVframerateLookup($framerateindex) { + if ($framerateindex <= 127) { + return (float) $framerateindex; + } + static $NSVframerateLookup = array(); + if (empty($NSVframerateLookup)) { + $NSVframerateLookup[129] = (float) 29.970; + $NSVframerateLookup[131] = (float) 23.976; + $NSVframerateLookup[133] = (float) 14.985; + $NSVframerateLookup[197] = (float) 59.940; + $NSVframerateLookup[199] = (float) 47.952; + } + return (isset($NSVframerateLookup[$framerateindex]) ? $NSVframerateLookup[$framerateindex] : false); + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.quicktime.php b/app/libs/vendor/getid3/module.audio-video.quicktime.php index 01713c9b..31f28cf3 100644 --- a/app/libs/vendor/getid3/module.audio-video.quicktime.php +++ b/app/libs/vendor/getid3/module.audio-video.quicktime.php @@ -1,2221 +1,2221 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.quicktime.php // -// module for analyzing Quicktime and MP3-in-MP4 files // -// dependencies: module.audio.mp3.php // -// dependencies: module.tag.id3v2.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup - -class getid3_quicktime extends getid3_handler -{ - - public $ReturnAtomData = true; - public $ParseAllPossibleAtoms = false; - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'quicktime'; - $info['quicktime']['hinting'] = false; - $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $offset = 0; - $atomcounter = 0; - - while ($offset < $info['avdataend']) { - if (!getid3_lib::intValueSupported($offset)) { - $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions'; - break; - } - fseek($this->getid3->fp, $offset, SEEK_SET); - $AtomHeader = fread($this->getid3->fp, 8); - - $atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4)); - $atomname = substr($AtomHeader, 4, 4); - - // 64-bit MOV patch by jlegateØktnc*com - if ($atomsize == 1) { - $atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8)); - } - - $info['quicktime'][$atomname]['name'] = $atomname; - $info['quicktime'][$atomname]['size'] = $atomsize; - $info['quicktime'][$atomname]['offset'] = $offset; - - if (($offset + $atomsize) > $info['avdataend']) { - $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)'; - return false; - } - - if ($atomsize == 0) { - // Furthermore, for historical reasons the list of atoms is optionally - // terminated by a 32-bit integer set to 0. If you are writing a program - // to read user data atoms, you should allow for the terminating 0. - break; - } - switch ($atomname) { - case 'mdat': // Media DATa atom - // 'mdat' contains the actual data for the audio/video - if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { - - $info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8; - $OldAVDataEnd = $info['avdataend']; - $info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size']; - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_temp->info['avdataend'] = $info['avdataend']; - $getid3_mp3 = new getid3_mp3($getid3_temp); - if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) { - $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $value) { - $info['warning'][] = $value; - } - } - if (!empty($getid3_temp->info['mpeg'])) { - $info['mpeg'] = $getid3_temp->info['mpeg']; - if (isset($info['mpeg']['audio'])) { - $info['audio']['dataformat'] = 'mp3'; - $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3'))); - $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; - $info['audio']['channels'] = $info['mpeg']['audio']['channels']; - $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; - $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); - $info['bitrate'] = $info['audio']['bitrate']; - } - } - } - unset($getid3_mp3, $getid3_temp); - $info['avdataend'] = $OldAVDataEnd; - unset($OldAVDataEnd); - - } - break; - - case 'free': // FREE space atom - case 'skip': // SKIP atom - case 'wide': // 64-bit expansion placeholder atom - // 'free', 'skip' and 'wide' are just padding, contains no useful data at all - break; - - default: - $atomHierarchy = array(); - $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms); - break; - } - - $offset += $atomsize; - $atomcounter++; - } - - if (!empty($info['avdataend_tmp'])) { - // this value is assigned to a temp value and then erased because - // otherwise any atoms beyond the 'mdat' atom would not get parsed - $info['avdataend'] = $info['avdataend_tmp']; - unset($info['avdataend_tmp']); - } - - if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { - $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) { - $info['audio']['bitrate'] = $info['bitrate']; - } - if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) { - foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) { - $samples_per_second = $samples_count / $info['playtime_seconds']; - if ($samples_per_second > 240) { - // has to be audio samples - } else { - $info['video']['frame_rate'] = $samples_per_second; - break; - } - } - } - if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) { - $info['fileformat'] = 'mp4'; - $info['mime_type'] = 'audio/mp4'; - unset($info['video']['dataformat']); - } - - if (!$this->ReturnAtomData) { - unset($info['quicktime']['moov']); - } - - if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) { - $info['audio']['dataformat'] = 'quicktime'; - } - if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) { - $info['video']['dataformat'] = 'quicktime'; - } - - return true; - } - - public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { - // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm - - $info = &$this->getid3->info; - - //$atom_parent = array_pop($atomHierarchy); - $atom_parent = end($atomHierarchy); // http://www.getid3.org/phpBB3/viewtopic.php?t=1717 - array_push($atomHierarchy, $atomname); - $atom_structure['hierarchy'] = implode(' ', $atomHierarchy); - $atom_structure['name'] = $atomname; - $atom_structure['size'] = $atomsize; - $atom_structure['offset'] = $baseoffset; -//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'
    '; -//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'

    '; - switch ($atomname) { - case 'moov': // MOVie container atom - case 'trak': // TRAcK container atom - case 'clip': // CLIPping container atom - case 'matt': // track MATTe container atom - case 'edts': // EDiTS container atom - case 'tref': // Track REFerence container atom - case 'mdia': // MeDIA container atom - case 'minf': // Media INFormation container atom - case 'dinf': // Data INFormation container atom - case 'udta': // User DaTA container atom - case 'cmov': // Compressed MOVie container atom - case 'rmra': // Reference Movie Record Atom - case 'rmda': // Reference Movie Descriptor Atom - case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - break; - - case 'ilst': // Item LiST container atom - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - - // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted - $allnumericnames = true; - foreach ($atom_structure['subatoms'] as $subatomarray) { - if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) { - $allnumericnames = false; - break; - } - } - if ($allnumericnames) { - $newData = array(); - foreach ($atom_structure['subatoms'] as $subatomarray) { - foreach ($subatomarray['subatoms'] as $newData_subatomarray) { - unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']); - $newData[$subatomarray['name']] = $newData_subatomarray; - break; - } - } - $atom_structure['data'] = $newData; - unset($atom_structure['subatoms']); - } - break; - - case "\x00\x00\x00\x01": - case "\x00\x00\x00\x02": - case "\x00\x00\x00\x03": - case "\x00\x00\x00\x04": - case "\x00\x00\x00\x05": - $atomname = getid3_lib::BigEndian2Int($atomname); - $atom_structure['name'] = $atomname; - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - break; - - case 'stbl': // Sample TaBLe container atom - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - $isVideo = false; - $framerate = 0; - $framecount = 0; - foreach ($atom_structure['subatoms'] as $key => $value_array) { - if (isset($value_array['sample_description_table'])) { - foreach ($value_array['sample_description_table'] as $key2 => $value_array2) { - if (isset($value_array2['data_format'])) { - switch ($value_array2['data_format']) { - case 'avc1': - case 'mp4v': - // video data - $isVideo = true; - break; - case 'mp4a': - // audio data - break; - } - } - } - } elseif (isset($value_array['time_to_sample_table'])) { - foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { - if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { - $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); - $framecount = $value_array2['sample_count']; - } - } - } - } - if ($isVideo && $framerate) { - $info['quicktime']['video']['frame_rate'] = $framerate; - $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate']; - } - if ($isVideo && $framecount) { - $info['quicktime']['video']['frame_count'] = $framecount; - } - break; - - - case 'aART': // Album ARTist - case 'catg': // CaTeGory - case 'covr': // COVeR artwork - case 'cpil': // ComPILation - case 'cprt': // CoPyRighT - case 'desc': // DESCription - case 'disk': // DISK number - case 'egid': // Episode Global ID - case 'gnre': // GeNRE - case 'keyw': // KEYWord - case 'ldes': - case 'pcst': // PodCaST - case 'pgap': // GAPless Playback - case 'purd': // PURchase Date - case 'purl': // Podcast URL - case 'rati': - case 'rndu': - case 'rpdu': - case 'rtng': // RaTiNG - case 'stik': - case 'tmpo': // TeMPO (BPM) - case 'trkn': // TRacK Number - case 'tves': // TV EpiSode - case 'tvnn': // TV Network Name - case 'tvsh': // TV SHow Name - case 'tvsn': // TV SeasoN - case 'akID': // iTunes store account type - case 'apID': - case 'atID': - case 'cmID': - case 'cnID': - case 'geID': - case 'plID': - case 'sfID': // iTunes store country - case '©alb': // ALBum - case '©art': // ARTist - case '©ART': - case '©aut': - case '©cmt': // CoMmenT - case '©com': // COMposer - case '©cpy': - case '©day': // content created year - case '©dir': - case '©ed1': - case '©ed2': - case '©ed3': - case '©ed4': - case '©ed5': - case '©ed6': - case '©ed7': - case '©ed8': - case '©ed9': - case '©enc': - case '©fmt': - case '©gen': // GENre - case '©grp': // GRouPing - case '©hst': - case '©inf': - case '©lyr': // LYRics - case '©mak': - case '©mod': - case '©nam': // full NAMe - case '©ope': - case '©PRD': - case '©prd': - case '©prf': - case '©req': - case '©src': - case '©swr': - case '©too': // encoder - case '©trk': // TRacK - case '©url': - case '©wrn': - case '©wrt': // WRiTer - case '----': // itunes specific - if ($atom_parent == 'udta') { - // User data atom handler - $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); - $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); - $atom_structure['data'] = substr($atom_data, 4); - - $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); - if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { - $info['comments']['language'][] = $atom_structure['language']; - } - } else { - // Apple item list box atom handler - $atomoffset = 0; - if (substr($atom_data, 2, 2) == "\x10\xB5") { - // not sure what it means, but observed on iPhone4 data. - // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data - while ($atomoffset < strlen($atom_data)) { - $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2)); - $boxsmalltype = substr($atom_data, $atomoffset + 2, 2); - $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize); - if ($boxsmallsize <= 1) { - $info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset); - $atom_structure['data'] = null; - $atomoffset = strlen($atom_data); - break; - } - switch ($boxsmalltype) { - case "\x10\xB5": - $atom_structure['data'] = $boxsmalldata; - break; - default: - $info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset; - $atom_structure['data'] = $atom_data; - break; - } - $atomoffset += (4 + $boxsmallsize); - } - } else { - while ($atomoffset < strlen($atom_data)) { - $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4)); - $boxtype = substr($atom_data, $atomoffset + 4, 4); - $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8); - if ($boxsize <= 1) { - $info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset); - $atom_structure['data'] = null; - $atomoffset = strlen($atom_data); - break; - } - $atomoffset += $boxsize; - - switch ($boxtype) { - case 'mean': - case 'name': - $atom_structure[$boxtype] = substr($boxdata, 4); - break; - - case 'data': - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3)); - switch ($atom_structure['flags_raw']) { - case 0: // data flag - case 21: // tmpo/cpil flag - switch ($atomname) { - case 'cpil': - case 'pcst': - case 'pgap': - $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); - break; - - case 'tmpo': - $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); - break; - - case 'disk': - case 'trkn': - $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); - $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); - $atom_structure['data'] = empty($num) ? '' : $num; - $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total; - break; - - case 'gnre': - $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); - $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); - break; - - case 'rtng': - $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); - $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]); - break; - - case 'stik': - $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); - $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]); - break; - - case 'sfID': - $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); - $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]); - break; - - case 'egid': - case 'purl': - $atom_structure['data'] = substr($boxdata, 8); - break; - - default: - $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); - } - break; - - case 1: // text flag - case 13: // image flag - default: - $atom_structure['data'] = substr($boxdata, 8); - break; - - } - break; - - default: - $info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset; - $atom_structure['data'] = $atom_data; - - } - } - } - } - $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); - break; - - - case 'play': // auto-PLAY atom - $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - - $info['quicktime']['autoplay'] = $atom_structure['autoplay']; - break; - - - case 'WLOC': // Window LOCation atom - $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); - $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); - break; - - - case 'LOOP': // LOOPing atom - case 'SelO': // play SELection Only atom - case 'AllF': // play ALL Frames atom - $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data); - break; - - - case 'name': // - case 'MCPS': // Media Cleaner PRo - case '@PRM': // adobe PReMiere version - case '@PRQ': // adobe PRemiere Quicktime version - $atom_structure['data'] = $atom_data; - break; - - - case 'cmvd': // Compressed MooV Data atom - // Code by ubergeekØubergeek*tv based on information from - // http://developer.apple.com/quicktime/icefloe/dispatch012.html - $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); - - $CompressedFileData = substr($atom_data, 4); - if ($UncompressedHeader = @gzuncompress($CompressedFileData)) { - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms); - } else { - $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset']; - } - break; - - - case 'dcom': // Data COMpression atom - $atom_structure['compression_id'] = $atom_data; - $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data); - break; - - - case 'rdrf': // Reference movie Data ReFerence atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); - $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001); - - $atom_structure['reference_type_name'] = substr($atom_data, 4, 4); - $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - switch ($atom_structure['reference_type_name']) { - case 'url ': - $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12)); - break; - - case 'alis': - $atom_structure['file_alias'] = substr($atom_data, 12); - break; - - case 'rsrc': - $atom_structure['resource_alias'] = substr($atom_data, 12); - break; - - default: - $atom_structure['data'] = substr($atom_data, 12); - break; - } - break; - - - case 'rmqu': // Reference Movie QUality atom - $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data); - break; - - - case 'rmcs': // Reference Movie Cpu Speed atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - break; - - - case 'rmvc': // Reference Movie Version Check atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4); - $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); - $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); - break; - - - case 'rmcd': // Reference Movie Component check atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['component_type'] = substr($atom_data, 4, 4); - $atom_structure['component_subtype'] = substr($atom_data, 8, 4); - $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); - $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); - $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); - $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4)); - break; - - - case 'rmdr': // Reference Movie Data Rate atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - - $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10; - break; - - - case 'rmla': // Reference Movie Language Atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - - $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); - if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { - $info['comments']['language'][] = $atom_structure['language']; - } - break; - - - case 'rmla': // Reference Movie Language Atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - break; - - - case 'ptv ': // Print To Video - defines a movie's full screen mode - // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm - $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); - $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000 - $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000 - $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1)); - $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1)); - - $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag']; - $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; - - $ptv_lookup[0] = 'normal'; - $ptv_lookup[1] = 'double'; - $ptv_lookup[2] = 'half'; - $ptv_lookup[3] = 'full'; - $ptv_lookup[4] = 'current'; - if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { - $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; - } else { - $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'; - } - break; - - - case 'stsd': // Sample Table Sample Description atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $stsdEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); - $stsdEntriesDataOffset += 4; - $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); - $stsdEntriesDataOffset += 4; - $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6)); - $stsdEntriesDataOffset += 6; - $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2)); - $stsdEntriesDataOffset += 2; - $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); - $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); - - $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2)); - $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2)); - $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4); - - switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { - - case "\x00\x00\x00\x00": - // audio tracks - $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2)); - $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2)); - $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2)); - $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2)); - $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); - - // video tracks - // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html - $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); - $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); - $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); - $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); - $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); - $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); - $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4)); - $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2)); - $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4); - $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2)); - $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2)); - - switch ($atom_structure['sample_description_table'][$i]['data_format']) { - case '2vuY': - case 'avc1': - case 'cvid': - case 'dvc ': - case 'dvcp': - case 'gif ': - case 'h263': - case 'jpeg': - case 'kpcd': - case 'mjpa': - case 'mjpb': - case 'mp4v': - case 'png ': - case 'raw ': - case 'rle ': - case 'rpza': - case 'smc ': - case 'SVQ1': - case 'SVQ3': - case 'tiff': - case 'v210': - case 'v216': - case 'v308': - case 'v408': - case 'v410': - case 'yuv2': - $info['fileformat'] = 'mp4'; - $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; -// http://www.getid3.org/phpBB3/viewtopic.php?t=1550 -//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers -if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) { - // assume that values stored here are more important than values stored in [tkhd] atom - $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width']; - $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height']; - $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; - $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; -} - break; - - case 'qtvr': - $info['video']['dataformat'] = 'quicktimevr'; - break; - - case 'mp4a': - default: - $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); - $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; - $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; - $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; - $info['audio']['codec'] = $info['quicktime']['audio']['codec']; - $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate']; - $info['audio']['channels'] = $info['quicktime']['audio']['channels']; - $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth']; - switch ($atom_structure['sample_description_table'][$i]['data_format']) { - case 'raw ': // PCM - case 'alac': // Apple Lossless Audio Codec - $info['audio']['lossless'] = true; - break; - default: - $info['audio']['lossless'] = false; - break; - } - break; - } - break; - - default: - switch ($atom_structure['sample_description_table'][$i]['data_format']) { - case 'mp4s': - $info['fileformat'] = 'mp4'; - break; - - default: - // video atom - $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); - $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); - $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); - $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); - $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); - $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); - $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); - $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2)); - $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1)); - $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); - $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); - $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); - - $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); - $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); - - if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { - $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; - $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); - $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']); - $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; - $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; - - $info['video']['codec'] = $info['quicktime']['video']['codec']; - $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth']; - } - $info['video']['lossless'] = false; - $info['video']['pixel_aspect_ratio'] = (float) 1; - break; - } - break; - } - switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { - case 'mp4a': - $info['audio']['dataformat'] = 'mp4'; - $info['quicktime']['audio']['codec'] = 'mp4'; - break; - - case '3ivx': - case '3iv1': - case '3iv2': - $info['video']['dataformat'] = '3ivx'; - break; - - case 'xvid': - $info['video']['dataformat'] = 'xvid'; - break; - - case 'mp4v': - $info['video']['dataformat'] = 'mpeg4'; - break; - - case 'divx': - case 'div1': - case 'div2': - case 'div3': - case 'div4': - case 'div5': - case 'div6': - $info['video']['dataformat'] = 'divx'; - break; - - default: - // do nothing - break; - } - unset($atom_structure['sample_description_table'][$i]['data']); - } - break; - - - case 'stts': // Sample Table Time-to-Sample atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $sttsEntriesDataOffset = 8; - //$FrameRateCalculatorArray = array(); - $frames_count = 0; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); - $sttsEntriesDataOffset += 4; - $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); - $sttsEntriesDataOffset += 4; - - $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count']; - - // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM - //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) { - // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; - // if ($stts_new_framerate <= 60) { - // // some atoms have durations of "1" giving a very large framerate, which probably is not right - // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate); - // } - //} - // - //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; - } - $info['quicktime']['stts_framecount'][] = $frames_count; - //$sttsFramesTotal = 0; - //$sttsSecondsTotal = 0; - //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) { - // if (($frames_per_second > 60) || ($frames_per_second < 1)) { - // // not video FPS information, probably audio information - // $sttsFramesTotal = 0; - // $sttsSecondsTotal = 0; - // break; - // } - // $sttsFramesTotal += $frame_count; - // $sttsSecondsTotal += $frame_count / $frames_per_second; - //} - //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) { - // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) { - // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal; - // } - //} - break; - - - case 'stss': // Sample Table Sync Sample (key frames) atom - if ($ParseAllPossibleAtoms) { - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $stssEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4)); - $stssEntriesDataOffset += 4; - } - } - break; - - - case 'stsc': // Sample Table Sample-to-Chunk atom - if ($ParseAllPossibleAtoms) { - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $stscEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); - $stscEntriesDataOffset += 4; - $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); - $stscEntriesDataOffset += 4; - $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); - $stscEntriesDataOffset += 4; - } - } - break; - - - case 'stsz': // Sample Table SiZe atom - if ($ParseAllPossibleAtoms) { - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $stszEntriesDataOffset = 12; - if ($atom_structure['sample_size'] == 0) { - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4)); - $stszEntriesDataOffset += 4; - } - } - } - break; - - - case 'stco': // Sample Table Chunk Offset atom - if ($ParseAllPossibleAtoms) { - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $stcoEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4)); - $stcoEntriesDataOffset += 4; - } - } - break; - - - case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files) - if ($ParseAllPossibleAtoms) { - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $stcoEntriesDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8)); - $stcoEntriesDataOffset += 8; - } - } - break; - - - case 'dref': // Data REFerence atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $drefDataOffset = 8; - for ($i = 0; $i < $atom_structure['number_entries']; $i++) { - $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4)); - $drefDataOffset += 4; - $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4); - $drefDataOffset += 4; - $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1)); - $drefDataOffset += 1; - $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000 - $drefDataOffset += 3; - $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); - $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); - - $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001); - } - break; - - - case 'gmin': // base Media INformation atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); - $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); - $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); - $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2)); - $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); - break; - - - case 'smhd': // Sound Media information HeaDer atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); - break; - - - case 'vmhd': // Video Media information HeaDer atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); - $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); - $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); - $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); - $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); - - $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001); - break; - - - case 'hdlr': // HanDLeR reference atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['component_type'] = substr($atom_data, 4, 4); - $atom_structure['component_subtype'] = substr($atom_data, 8, 4); - $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); - $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); - $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); - $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24)); - - if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { - $info['video']['dataformat'] = 'quicktimevr'; - } - break; - - - case 'mdhd': // MeDia HeaDer atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); - $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); - $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2)); - $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2)); - - if ($atom_structure['time_scale'] == 0) { - $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero'; - return false; - } - $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); - - $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); - $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); - $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; - $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); - if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { - $info['comments']['language'][] = $atom_structure['language']; - } - break; - - - case 'pnot': // Preview atom - $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format" - $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00 - $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT' - $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01 - - $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']); - break; - - - case 'crgn': // Clipping ReGioN atom - $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, - $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields - $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. - break; - - - case 'load': // track LOAD settings atom - $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); - $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); - - $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020); - $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100); - break; - - - case 'tmcd': // TiMe CoDe atom - case 'chap': // CHAPter list atom - case 'sync': // SYNChronization atom - case 'scpt': // tranSCriPT atom - case 'ssrc': // non-primary SouRCe atom - for ($i = 0; $i < (strlen($atom_data) % 4); $i++) { - $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4)); - } - break; - - - case 'elst': // Edit LiST atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) { - $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4)); - $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4)); - $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4)); - } - break; - - - case 'kmat': // compressed MATte atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 - $atom_structure['matte_data_raw'] = substr($atom_data, 4); - break; - - - case 'ctab': // Color TABle atom - $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 - $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 - $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; - for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { - $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); - $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); - $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); - $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); - } - break; - - - case 'mvhd': // MoVie HeaDer atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); - $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); - $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); - $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4)); - $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2)); - $atom_structure['reserved'] = substr($atom_data, 26, 10); - $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4)); - $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); - $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4)); - $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4)); - $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); - $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4)); - $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4)); - $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); - $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4)); - $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4)); - $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4)); - $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4)); - $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4)); - $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4)); - $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4)); - $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4)); - - if ($atom_structure['time_scale'] == 0) { - $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero'; - return false; - } - $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); - $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); - $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); - $info['quicktime']['display_scale'] = $atom_structure['matrix_a']; - $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; - break; - - - case 'tkhd': // TracK HeaDer atom - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); - $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); - $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); - $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); - $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); - $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8)); - $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2)); - $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2)); - $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2)); - $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); -// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html -// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737 - $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); - $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4)); - $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4)); - $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); - $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4)); - $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4)); - $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); - $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4)); - $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4)); - $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4)); - $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4)); - $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001); - $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002); - $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004); - $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008); - $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); - $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); - - if ($atom_structure['flags']['enabled'] == 1) { - if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { - $info['video']['resolution_x'] = $atom_structure['width']; - $info['video']['resolution_y'] = $atom_structure['height']; - } - $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); - $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); - $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; - $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; - } else { - // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295 - //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); } - //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); } - //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); } - } - break; - - - case 'iods': // Initial Object DeScriptor atom - // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h - // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html - $offset = 0; - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3)); - $offset += 3; - $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); - //$offset already adjusted by quicktime_read_mp4_descr_length() - $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); - $offset += 2; - $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - - $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields - for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) { - $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); - $offset += 1; - $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); - //$offset already adjusted by quicktime_read_mp4_descr_length() - $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); - $offset += 4; - } - - $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']); - $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']); - break; - - case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) - $atom_structure['signature'] = substr($atom_data, 0, 4); - $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); - $atom_structure['fourcc'] = substr($atom_data, 8, 4); - break; - - case 'mdat': // Media DATa atom - case 'free': // FREE space atom - case 'skip': // SKIP atom - case 'wide': // 64-bit expansion placeholder atom - // 'mdat' data is too big to deal with, contains no useful metadata - // 'free', 'skip' and 'wide' are just padding, contains no useful data at all - - // When writing QuickTime files, it is sometimes necessary to update an atom's size. - // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom - // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime - // puts an 8-byte placeholder atom before any atoms it may have to update the size of. - // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the - // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. - // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). - break; - - - case 'nsav': // NoSAVe atom - // http://developer.apple.com/technotes/tn/tn2038.html - $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); - break; - - case 'ctyp': // Controller TYPe atom (seen on QTVR) - // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt - // some controller names are: - // 0x00 + 'std' for linear movie - // 'none' for no controls - $atom_structure['ctyp'] = substr($atom_data, 0, 4); - $info['quicktime']['controller'] = $atom_structure['ctyp']; - switch ($atom_structure['ctyp']) { - case 'qtvr': - $info['video']['dataformat'] = 'quicktimevr'; - break; - } - break; - - case 'pano': // PANOrama track (seen on QTVR) - $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); - break; - - case 'hint': // HINT track - case 'hinf': // - case 'hinv': // - case 'hnti': // - $info['quicktime']['hinting'] = true; - break; - - case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR) - for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) { - $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); - } - break; - - - // Observed-but-not-handled atom types are just listed here to prevent warnings being generated - case 'FXTC': // Something to do with Adobe After Effects (?) - case 'PrmA': - case 'code': - case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html - case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html - // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838] - // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html - // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html - case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html - case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html - case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html - case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html - //$atom_structure['data'] = $atom_data; - break; - - case '©xyz': // GPS latitude+longitude+altitude - $atom_structure['data'] = $atom_data; - if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) { - @list($all, $latitude, $longitude, $altitude) = $matches; - $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude); - $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude); - if (!empty($altitude)) { - $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude); - } - } else { - $info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.'; - } - break; - - case 'NCDT': - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html - // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); - break; - case 'NCTH': // Nikon Camera THumbnail image - case 'NCVW': // Nikon Camera preVieW image - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html - if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { - $atom_structure['data'] = $atom_data; - $atom_structure['image_mime'] = 'image/jpeg'; - $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); - $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); - } - break; - case 'NCHD': // MakerNoteVersion - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html - $atom_structure['data'] = $atom_data; - break; - case 'NCTG': // NikonTags - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG - $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); - break; - case 'NCDB': // NikonTags - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html - $atom_structure['data'] = $atom_data; - break; - - case "\x00\x00\x00\x00": - case 'meta': // METAdata atom - // some kind of metacontainer, may contain a big data dump such as: - // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4 - // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt - - $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); - $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); - $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); - break; - - case 'data': // metaDATA atom - // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data - $atom_structure['language'] = substr($atom_data, 4 + 0, 2); - $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); - $atom_structure['data'] = substr($atom_data, 4 + 4); - break; - - default: - $info['warning'][] = 'Unknown QuickTime atom type: "'.$atomname.'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset; - $atom_structure['data'] = $atom_data; - break; - } - array_pop($atomHierarchy); - return $atom_structure; - } - - public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { -//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'

    '; - $atom_structure = false; - $subatomoffset = 0; - $subatomcounter = 0; - if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) { - return false; - } - while ($subatomoffset < strlen($atom_data)) { - $subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4)); - $subatomname = substr($atom_data, $subatomoffset + 4, 4); - $subatomdata = substr($atom_data, $subatomoffset + 8, $subatomsize - 8); - if ($subatomsize == 0) { - // Furthermore, for historical reasons the list of atoms is optionally - // terminated by a 32-bit integer set to 0. If you are writing a program - // to read user data atoms, you should allow for the terminating 0. - return $atom_structure; - } - - $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); - - $subatomoffset += $subatomsize; - $subatomcounter++; - } - return $atom_structure; - } - - - public function quicktime_read_mp4_descr_length($data, &$offset) { - // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html - $num_bytes = 0; - $length = 0; - do { - $b = ord(substr($data, $offset++, 1)); - $length = ($length << 7) | ($b & 0x7F); - } while (($b & 0x80) && ($num_bytes++ < 4)); - return $length; - } - - - public function QuicktimeLanguageLookup($languageid) { - // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353 - static $QuicktimeLanguageLookup = array(); - if (empty($QuicktimeLanguageLookup)) { - $QuicktimeLanguageLookup[0] = 'English'; - $QuicktimeLanguageLookup[1] = 'French'; - $QuicktimeLanguageLookup[2] = 'German'; - $QuicktimeLanguageLookup[3] = 'Italian'; - $QuicktimeLanguageLookup[4] = 'Dutch'; - $QuicktimeLanguageLookup[5] = 'Swedish'; - $QuicktimeLanguageLookup[6] = 'Spanish'; - $QuicktimeLanguageLookup[7] = 'Danish'; - $QuicktimeLanguageLookup[8] = 'Portuguese'; - $QuicktimeLanguageLookup[9] = 'Norwegian'; - $QuicktimeLanguageLookup[10] = 'Hebrew'; - $QuicktimeLanguageLookup[11] = 'Japanese'; - $QuicktimeLanguageLookup[12] = 'Arabic'; - $QuicktimeLanguageLookup[13] = 'Finnish'; - $QuicktimeLanguageLookup[14] = 'Greek'; - $QuicktimeLanguageLookup[15] = 'Icelandic'; - $QuicktimeLanguageLookup[16] = 'Maltese'; - $QuicktimeLanguageLookup[17] = 'Turkish'; - $QuicktimeLanguageLookup[18] = 'Croatian'; - $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)'; - $QuicktimeLanguageLookup[20] = 'Urdu'; - $QuicktimeLanguageLookup[21] = 'Hindi'; - $QuicktimeLanguageLookup[22] = 'Thai'; - $QuicktimeLanguageLookup[23] = 'Korean'; - $QuicktimeLanguageLookup[24] = 'Lithuanian'; - $QuicktimeLanguageLookup[25] = 'Polish'; - $QuicktimeLanguageLookup[26] = 'Hungarian'; - $QuicktimeLanguageLookup[27] = 'Estonian'; - $QuicktimeLanguageLookup[28] = 'Lettish'; - $QuicktimeLanguageLookup[28] = 'Latvian'; - $QuicktimeLanguageLookup[29] = 'Saamisk'; - $QuicktimeLanguageLookup[29] = 'Lappish'; - $QuicktimeLanguageLookup[30] = 'Faeroese'; - $QuicktimeLanguageLookup[31] = 'Farsi'; - $QuicktimeLanguageLookup[31] = 'Persian'; - $QuicktimeLanguageLookup[32] = 'Russian'; - $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)'; - $QuicktimeLanguageLookup[34] = 'Flemish'; - $QuicktimeLanguageLookup[35] = 'Irish'; - $QuicktimeLanguageLookup[36] = 'Albanian'; - $QuicktimeLanguageLookup[37] = 'Romanian'; - $QuicktimeLanguageLookup[38] = 'Czech'; - $QuicktimeLanguageLookup[39] = 'Slovak'; - $QuicktimeLanguageLookup[40] = 'Slovenian'; - $QuicktimeLanguageLookup[41] = 'Yiddish'; - $QuicktimeLanguageLookup[42] = 'Serbian'; - $QuicktimeLanguageLookup[43] = 'Macedonian'; - $QuicktimeLanguageLookup[44] = 'Bulgarian'; - $QuicktimeLanguageLookup[45] = 'Ukrainian'; - $QuicktimeLanguageLookup[46] = 'Byelorussian'; - $QuicktimeLanguageLookup[47] = 'Uzbek'; - $QuicktimeLanguageLookup[48] = 'Kazakh'; - $QuicktimeLanguageLookup[49] = 'Azerbaijani'; - $QuicktimeLanguageLookup[50] = 'AzerbaijanAr'; - $QuicktimeLanguageLookup[51] = 'Armenian'; - $QuicktimeLanguageLookup[52] = 'Georgian'; - $QuicktimeLanguageLookup[53] = 'Moldavian'; - $QuicktimeLanguageLookup[54] = 'Kirghiz'; - $QuicktimeLanguageLookup[55] = 'Tajiki'; - $QuicktimeLanguageLookup[56] = 'Turkmen'; - $QuicktimeLanguageLookup[57] = 'Mongolian'; - $QuicktimeLanguageLookup[58] = 'MongolianCyr'; - $QuicktimeLanguageLookup[59] = 'Pashto'; - $QuicktimeLanguageLookup[60] = 'Kurdish'; - $QuicktimeLanguageLookup[61] = 'Kashmiri'; - $QuicktimeLanguageLookup[62] = 'Sindhi'; - $QuicktimeLanguageLookup[63] = 'Tibetan'; - $QuicktimeLanguageLookup[64] = 'Nepali'; - $QuicktimeLanguageLookup[65] = 'Sanskrit'; - $QuicktimeLanguageLookup[66] = 'Marathi'; - $QuicktimeLanguageLookup[67] = 'Bengali'; - $QuicktimeLanguageLookup[68] = 'Assamese'; - $QuicktimeLanguageLookup[69] = 'Gujarati'; - $QuicktimeLanguageLookup[70] = 'Punjabi'; - $QuicktimeLanguageLookup[71] = 'Oriya'; - $QuicktimeLanguageLookup[72] = 'Malayalam'; - $QuicktimeLanguageLookup[73] = 'Kannada'; - $QuicktimeLanguageLookup[74] = 'Tamil'; - $QuicktimeLanguageLookup[75] = 'Telugu'; - $QuicktimeLanguageLookup[76] = 'Sinhalese'; - $QuicktimeLanguageLookup[77] = 'Burmese'; - $QuicktimeLanguageLookup[78] = 'Khmer'; - $QuicktimeLanguageLookup[79] = 'Lao'; - $QuicktimeLanguageLookup[80] = 'Vietnamese'; - $QuicktimeLanguageLookup[81] = 'Indonesian'; - $QuicktimeLanguageLookup[82] = 'Tagalog'; - $QuicktimeLanguageLookup[83] = 'MalayRoman'; - $QuicktimeLanguageLookup[84] = 'MalayArabic'; - $QuicktimeLanguageLookup[85] = 'Amharic'; - $QuicktimeLanguageLookup[86] = 'Tigrinya'; - $QuicktimeLanguageLookup[87] = 'Galla'; - $QuicktimeLanguageLookup[87] = 'Oromo'; - $QuicktimeLanguageLookup[88] = 'Somali'; - $QuicktimeLanguageLookup[89] = 'Swahili'; - $QuicktimeLanguageLookup[90] = 'Ruanda'; - $QuicktimeLanguageLookup[91] = 'Rundi'; - $QuicktimeLanguageLookup[92] = 'Chewa'; - $QuicktimeLanguageLookup[93] = 'Malagasy'; - $QuicktimeLanguageLookup[94] = 'Esperanto'; - $QuicktimeLanguageLookup[128] = 'Welsh'; - $QuicktimeLanguageLookup[129] = 'Basque'; - $QuicktimeLanguageLookup[130] = 'Catalan'; - $QuicktimeLanguageLookup[131] = 'Latin'; - $QuicktimeLanguageLookup[132] = 'Quechua'; - $QuicktimeLanguageLookup[133] = 'Guarani'; - $QuicktimeLanguageLookup[134] = 'Aymara'; - $QuicktimeLanguageLookup[135] = 'Tatar'; - $QuicktimeLanguageLookup[136] = 'Uighur'; - $QuicktimeLanguageLookup[137] = 'Dzongkha'; - $QuicktimeLanguageLookup[138] = 'JavaneseRom'; - $QuicktimeLanguageLookup[32767] = 'Unspecified'; - } - if (($languageid > 138) && ($languageid < 32767)) { - /* - ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php - Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field. - The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate - these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero. - - One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character - and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character, - and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least - significant bits and the most significant bit set to zero. - */ - $iso_language_id = ''; - $iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60); - $iso_language_id .= chr((($languageid & 0x03E0) >> 5) + 0x60); - $iso_language_id .= chr((($languageid & 0x001F) >> 0) + 0x60); - $QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id); - } - return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid'); - } - - public function QuicktimeVideoCodecLookup($codecid) { - static $QuicktimeVideoCodecLookup = array(); - if (empty($QuicktimeVideoCodecLookup)) { - $QuicktimeVideoCodecLookup['.SGI'] = 'SGI'; - $QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1'; - $QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2'; - $QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4'; - $QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB'; - $QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC'; - $QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG'; - $QuicktimeVideoCodecLookup['b16g'] = '16Gray'; - $QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray'; - $QuicktimeVideoCodecLookup['b48r'] = '48RGB'; - $QuicktimeVideoCodecLookup['b64a'] = '64ARGB'; - $QuicktimeVideoCodecLookup['base'] = 'Base'; - $QuicktimeVideoCodecLookup['clou'] = 'Cloud'; - $QuicktimeVideoCodecLookup['cmyk'] = 'CMYK'; - $QuicktimeVideoCodecLookup['cvid'] = 'Cinepak'; - $QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG'; - $QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC'; - $QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL'; - $QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC'; - $QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL'; - $QuicktimeVideoCodecLookup['fire'] = 'Fire'; - $QuicktimeVideoCodecLookup['flic'] = 'FLC'; - $QuicktimeVideoCodecLookup['gif '] = 'GIF'; - $QuicktimeVideoCodecLookup['h261'] = 'H261'; - $QuicktimeVideoCodecLookup['h263'] = 'H263'; - $QuicktimeVideoCodecLookup['IV41'] = 'Indeo4'; - $QuicktimeVideoCodecLookup['jpeg'] = 'JPEG'; - $QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD'; - $QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A'; - $QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B'; - $QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1'; - $QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420'; - $QuicktimeVideoCodecLookup['path'] = 'Vector'; - $QuicktimeVideoCodecLookup['png '] = 'PNG'; - $QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint'; - $QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX'; - $QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw'; - $QuicktimeVideoCodecLookup['raw '] = 'RAW'; - $QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple'; - $QuicktimeVideoCodecLookup['rpza'] = 'Video'; - $QuicktimeVideoCodecLookup['smc '] = 'Graphics'; - $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1'; - $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3'; - $QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9'; - $QuicktimeVideoCodecLookup['tga '] = 'Targa'; - $QuicktimeVideoCodecLookup['tiff'] = 'TIFF'; - $QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW'; - $QuicktimeVideoCodecLookup['WRLE'] = 'BMP'; - $QuicktimeVideoCodecLookup['y420'] = 'YUV420'; - $QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo'; - $QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned'; - $QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned'; - } - return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : ''); - } - - public function QuicktimeAudioCodecLookup($codecid) { - static $QuicktimeAudioCodecLookup = array(); - if (empty($QuicktimeAudioCodecLookup)) { - $QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias'; - $QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC'; - $QuicktimeAudioCodecLookup['agsm'] = 'Apple GSM 10:1'; - $QuicktimeAudioCodecLookup['alac'] = 'Apple Lossless Audio Codec'; - $QuicktimeAudioCodecLookup['alaw'] = 'A-law 2:1'; - $QuicktimeAudioCodecLookup['conv'] = 'Sample Format'; - $QuicktimeAudioCodecLookup['dvca'] = 'DV'; - $QuicktimeAudioCodecLookup['dvi '] = 'DV 4:1'; - $QuicktimeAudioCodecLookup['eqal'] = 'Frequency Equalizer'; - $QuicktimeAudioCodecLookup['fl32'] = '32-bit Floating Point'; - $QuicktimeAudioCodecLookup['fl64'] = '64-bit Floating Point'; - $QuicktimeAudioCodecLookup['ima4'] = 'Interactive Multimedia Association 4:1'; - $QuicktimeAudioCodecLookup['in24'] = '24-bit Integer'; - $QuicktimeAudioCodecLookup['in32'] = '32-bit Integer'; - $QuicktimeAudioCodecLookup['lpc '] = 'LPC 23:1'; - $QuicktimeAudioCodecLookup['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1'; - $QuicktimeAudioCodecLookup['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1'; - $QuicktimeAudioCodecLookup['mixb'] = '8-bit Mixer'; - $QuicktimeAudioCodecLookup['mixw'] = '16-bit Mixer'; - $QuicktimeAudioCodecLookup['mp4a'] = 'ISO/IEC 14496-3 AAC'; - $QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM'; - $QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA'; - $QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III'; - $QuicktimeAudioCodecLookup['NONE'] = 'No Encoding'; - $QuicktimeAudioCodecLookup['Qclp'] = 'Qualcomm PureVoice'; - $QuicktimeAudioCodecLookup['QDM2'] = 'QDesign Music 2'; - $QuicktimeAudioCodecLookup['QDMC'] = 'QDesign Music 1'; - $QuicktimeAudioCodecLookup['ratb'] = '8-bit Rate'; - $QuicktimeAudioCodecLookup['ratw'] = '16-bit Rate'; - $QuicktimeAudioCodecLookup['raw '] = 'raw PCM'; - $QuicktimeAudioCodecLookup['sour'] = 'Sound Source'; - $QuicktimeAudioCodecLookup['sowt'] = 'signed/two\'s complement (Little Endian)'; - $QuicktimeAudioCodecLookup['str1'] = 'Iomega MPEG layer II'; - $QuicktimeAudioCodecLookup['str2'] = 'Iomega MPEG *layer II'; - $QuicktimeAudioCodecLookup['str3'] = 'Iomega MPEG **layer II'; - $QuicktimeAudioCodecLookup['str4'] = 'Iomega MPEG ***layer II'; - $QuicktimeAudioCodecLookup['twos'] = 'signed/two\'s complement (Big Endian)'; - $QuicktimeAudioCodecLookup['ulaw'] = 'mu-law 2:1'; - } - return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : ''); - } - - public function QuicktimeDCOMLookup($compressionid) { - static $QuicktimeDCOMLookup = array(); - if (empty($QuicktimeDCOMLookup)) { - $QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate'; - $QuicktimeDCOMLookup['adec'] = 'Apple Compression'; - } - return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : ''); - } - - public function QuicktimeColorNameLookup($colordepthid) { - static $QuicktimeColorNameLookup = array(); - if (empty($QuicktimeColorNameLookup)) { - $QuicktimeColorNameLookup[1] = '2-color (monochrome)'; - $QuicktimeColorNameLookup[2] = '4-color'; - $QuicktimeColorNameLookup[4] = '16-color'; - $QuicktimeColorNameLookup[8] = '256-color'; - $QuicktimeColorNameLookup[16] = 'thousands (16-bit color)'; - $QuicktimeColorNameLookup[24] = 'millions (24-bit color)'; - $QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)'; - $QuicktimeColorNameLookup[33] = 'black & white'; - $QuicktimeColorNameLookup[34] = '4-gray'; - $QuicktimeColorNameLookup[36] = '16-gray'; - $QuicktimeColorNameLookup[40] = '256-gray'; - } - return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid'); - } - - public function QuicktimeSTIKLookup($stik) { - static $QuicktimeSTIKLookup = array(); - if (empty($QuicktimeSTIKLookup)) { - $QuicktimeSTIKLookup[0] = 'Movie'; - $QuicktimeSTIKLookup[1] = 'Normal'; - $QuicktimeSTIKLookup[2] = 'Audiobook'; - $QuicktimeSTIKLookup[5] = 'Whacked Bookmark'; - $QuicktimeSTIKLookup[6] = 'Music Video'; - $QuicktimeSTIKLookup[9] = 'Short Film'; - $QuicktimeSTIKLookup[10] = 'TV Show'; - $QuicktimeSTIKLookup[11] = 'Booklet'; - $QuicktimeSTIKLookup[14] = 'Ringtone'; - $QuicktimeSTIKLookup[21] = 'Podcast'; - } - return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid'); - } - - public function QuicktimeIODSaudioProfileName($audio_profile_id) { - static $QuicktimeIODSaudioProfileNameLookup = array(); - if (empty($QuicktimeIODSaudioProfileNameLookup)) { - $QuicktimeIODSaudioProfileNameLookup = array( - 0x00 => 'ISO Reserved (0x00)', - 0x01 => 'Main Audio Profile @ Level 1', - 0x02 => 'Main Audio Profile @ Level 2', - 0x03 => 'Main Audio Profile @ Level 3', - 0x04 => 'Main Audio Profile @ Level 4', - 0x05 => 'Scalable Audio Profile @ Level 1', - 0x06 => 'Scalable Audio Profile @ Level 2', - 0x07 => 'Scalable Audio Profile @ Level 3', - 0x08 => 'Scalable Audio Profile @ Level 4', - 0x09 => 'Speech Audio Profile @ Level 1', - 0x0A => 'Speech Audio Profile @ Level 2', - 0x0B => 'Synthetic Audio Profile @ Level 1', - 0x0C => 'Synthetic Audio Profile @ Level 2', - 0x0D => 'Synthetic Audio Profile @ Level 3', - 0x0E => 'High Quality Audio Profile @ Level 1', - 0x0F => 'High Quality Audio Profile @ Level 2', - 0x10 => 'High Quality Audio Profile @ Level 3', - 0x11 => 'High Quality Audio Profile @ Level 4', - 0x12 => 'High Quality Audio Profile @ Level 5', - 0x13 => 'High Quality Audio Profile @ Level 6', - 0x14 => 'High Quality Audio Profile @ Level 7', - 0x15 => 'High Quality Audio Profile @ Level 8', - 0x16 => 'Low Delay Audio Profile @ Level 1', - 0x17 => 'Low Delay Audio Profile @ Level 2', - 0x18 => 'Low Delay Audio Profile @ Level 3', - 0x19 => 'Low Delay Audio Profile @ Level 4', - 0x1A => 'Low Delay Audio Profile @ Level 5', - 0x1B => 'Low Delay Audio Profile @ Level 6', - 0x1C => 'Low Delay Audio Profile @ Level 7', - 0x1D => 'Low Delay Audio Profile @ Level 8', - 0x1E => 'Natural Audio Profile @ Level 1', - 0x1F => 'Natural Audio Profile @ Level 2', - 0x20 => 'Natural Audio Profile @ Level 3', - 0x21 => 'Natural Audio Profile @ Level 4', - 0x22 => 'Mobile Audio Internetworking Profile @ Level 1', - 0x23 => 'Mobile Audio Internetworking Profile @ Level 2', - 0x24 => 'Mobile Audio Internetworking Profile @ Level 3', - 0x25 => 'Mobile Audio Internetworking Profile @ Level 4', - 0x26 => 'Mobile Audio Internetworking Profile @ Level 5', - 0x27 => 'Mobile Audio Internetworking Profile @ Level 6', - 0x28 => 'AAC Profile @ Level 1', - 0x29 => 'AAC Profile @ Level 2', - 0x2A => 'AAC Profile @ Level 4', - 0x2B => 'AAC Profile @ Level 5', - 0x2C => 'High Efficiency AAC Profile @ Level 2', - 0x2D => 'High Efficiency AAC Profile @ Level 3', - 0x2E => 'High Efficiency AAC Profile @ Level 4', - 0x2F => 'High Efficiency AAC Profile @ Level 5', - 0xFE => 'Not part of MPEG-4 audio profiles', - 0xFF => 'No audio capability required', - ); - } - return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private'); - } - - - public function QuicktimeIODSvideoProfileName($video_profile_id) { - static $QuicktimeIODSvideoProfileNameLookup = array(); - if (empty($QuicktimeIODSvideoProfileNameLookup)) { - $QuicktimeIODSvideoProfileNameLookup = array( - 0x00 => 'Reserved (0x00) Profile', - 0x01 => 'Simple Profile @ Level 1', - 0x02 => 'Simple Profile @ Level 2', - 0x03 => 'Simple Profile @ Level 3', - 0x08 => 'Simple Profile @ Level 0', - 0x10 => 'Simple Scalable Profile @ Level 0', - 0x11 => 'Simple Scalable Profile @ Level 1', - 0x12 => 'Simple Scalable Profile @ Level 2', - 0x15 => 'AVC/H264 Profile', - 0x21 => 'Core Profile @ Level 1', - 0x22 => 'Core Profile @ Level 2', - 0x32 => 'Main Profile @ Level 2', - 0x33 => 'Main Profile @ Level 3', - 0x34 => 'Main Profile @ Level 4', - 0x42 => 'N-bit Profile @ Level 2', - 0x51 => 'Scalable Texture Profile @ Level 1', - 0x61 => 'Simple Face Animation Profile @ Level 1', - 0x62 => 'Simple Face Animation Profile @ Level 2', - 0x63 => 'Simple FBA Profile @ Level 1', - 0x64 => 'Simple FBA Profile @ Level 2', - 0x71 => 'Basic Animated Texture Profile @ Level 1', - 0x72 => 'Basic Animated Texture Profile @ Level 2', - 0x81 => 'Hybrid Profile @ Level 1', - 0x82 => 'Hybrid Profile @ Level 2', - 0x91 => 'Advanced Real Time Simple Profile @ Level 1', - 0x92 => 'Advanced Real Time Simple Profile @ Level 2', - 0x93 => 'Advanced Real Time Simple Profile @ Level 3', - 0x94 => 'Advanced Real Time Simple Profile @ Level 4', - 0xA1 => 'Core Scalable Profile @ Level1', - 0xA2 => 'Core Scalable Profile @ Level2', - 0xA3 => 'Core Scalable Profile @ Level3', - 0xB1 => 'Advanced Coding Efficiency Profile @ Level 1', - 0xB2 => 'Advanced Coding Efficiency Profile @ Level 2', - 0xB3 => 'Advanced Coding Efficiency Profile @ Level 3', - 0xB4 => 'Advanced Coding Efficiency Profile @ Level 4', - 0xC1 => 'Advanced Core Profile @ Level 1', - 0xC2 => 'Advanced Core Profile @ Level 2', - 0xD1 => 'Advanced Scalable Texture @ Level1', - 0xD2 => 'Advanced Scalable Texture @ Level2', - 0xE1 => 'Simple Studio Profile @ Level 1', - 0xE2 => 'Simple Studio Profile @ Level 2', - 0xE3 => 'Simple Studio Profile @ Level 3', - 0xE4 => 'Simple Studio Profile @ Level 4', - 0xE5 => 'Core Studio Profile @ Level 1', - 0xE6 => 'Core Studio Profile @ Level 2', - 0xE7 => 'Core Studio Profile @ Level 3', - 0xE8 => 'Core Studio Profile @ Level 4', - 0xF0 => 'Advanced Simple Profile @ Level 0', - 0xF1 => 'Advanced Simple Profile @ Level 1', - 0xF2 => 'Advanced Simple Profile @ Level 2', - 0xF3 => 'Advanced Simple Profile @ Level 3', - 0xF4 => 'Advanced Simple Profile @ Level 4', - 0xF5 => 'Advanced Simple Profile @ Level 5', - 0xF7 => 'Advanced Simple Profile @ Level 3b', - 0xF8 => 'Fine Granularity Scalable Profile @ Level 0', - 0xF9 => 'Fine Granularity Scalable Profile @ Level 1', - 0xFA => 'Fine Granularity Scalable Profile @ Level 2', - 0xFB => 'Fine Granularity Scalable Profile @ Level 3', - 0xFC => 'Fine Granularity Scalable Profile @ Level 4', - 0xFD => 'Fine Granularity Scalable Profile @ Level 5', - 0xFE => 'Not part of MPEG-4 Visual profiles', - 0xFF => 'No visual capability required', - ); - } - return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile'); - } - - - public function QuicktimeContentRatingLookup($rtng) { - static $QuicktimeContentRatingLookup = array(); - if (empty($QuicktimeContentRatingLookup)) { - $QuicktimeContentRatingLookup[0] = 'None'; - $QuicktimeContentRatingLookup[2] = 'Clean'; - $QuicktimeContentRatingLookup[4] = 'Explicit'; - } - return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); - } - - public function QuicktimeStoreAccountTypeLookup($akid) { - static $QuicktimeStoreAccountTypeLookup = array(); - if (empty($QuicktimeStoreAccountTypeLookup)) { - $QuicktimeStoreAccountTypeLookup[0] = 'iTunes'; - $QuicktimeStoreAccountTypeLookup[1] = 'AOL'; - } - return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid'); - } - - public function QuicktimeStoreFrontCodeLookup($sfid) { - static $QuicktimeStoreFrontCodeLookup = array(); - if (empty($QuicktimeStoreFrontCodeLookup)) { - $QuicktimeStoreFrontCodeLookup[143460] = 'Australia'; - $QuicktimeStoreFrontCodeLookup[143445] = 'Austria'; - $QuicktimeStoreFrontCodeLookup[143446] = 'Belgium'; - $QuicktimeStoreFrontCodeLookup[143455] = 'Canada'; - $QuicktimeStoreFrontCodeLookup[143458] = 'Denmark'; - $QuicktimeStoreFrontCodeLookup[143447] = 'Finland'; - $QuicktimeStoreFrontCodeLookup[143442] = 'France'; - $QuicktimeStoreFrontCodeLookup[143443] = 'Germany'; - $QuicktimeStoreFrontCodeLookup[143448] = 'Greece'; - $QuicktimeStoreFrontCodeLookup[143449] = 'Ireland'; - $QuicktimeStoreFrontCodeLookup[143450] = 'Italy'; - $QuicktimeStoreFrontCodeLookup[143462] = 'Japan'; - $QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg'; - $QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands'; - $QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand'; - $QuicktimeStoreFrontCodeLookup[143457] = 'Norway'; - $QuicktimeStoreFrontCodeLookup[143453] = 'Portugal'; - $QuicktimeStoreFrontCodeLookup[143454] = 'Spain'; - $QuicktimeStoreFrontCodeLookup[143456] = 'Sweden'; - $QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland'; - $QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom'; - $QuicktimeStoreFrontCodeLookup[143441] = 'United States'; - } - return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); - } - - public function QuicktimeParseNikonNCTG($atom_data) { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG - // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 - // Data is stored as records of: - // * 4 bytes record type - // * 2 bytes size of data field type: - // 0x0001 = flag (size field *= 1-byte) - // 0x0002 = char (size field *= 1-byte) - // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB - // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD - // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together - // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? - // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? - // * 2 bytes data size field - // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15") - // all integers are stored BigEndian - - $NCTGtagName = array( - 0x00000001 => 'Make', - 0x00000002 => 'Model', - 0x00000003 => 'Software', - 0x00000011 => 'CreateDate', - 0x00000012 => 'DateTimeOriginal', - 0x00000013 => 'FrameCount', - 0x00000016 => 'FrameRate', - 0x00000022 => 'FrameWidth', - 0x00000023 => 'FrameHeight', - 0x00000032 => 'AudioChannels', - 0x00000033 => 'AudioBitsPerSample', - 0x00000034 => 'AudioSampleRate', - 0x02000001 => 'MakerNoteVersion', - 0x02000005 => 'WhiteBalance', - 0x0200000b => 'WhiteBalanceFineTune', - 0x0200001e => 'ColorSpace', - 0x02000023 => 'PictureControlData', - 0x02000024 => 'WorldTime', - 0x02000032 => 'UnknownInfo', - 0x02000083 => 'LensType', - 0x02000084 => 'Lens', - ); - - $offset = 0; - $datalength = strlen($atom_data); - $parsed = array(); - while ($offset < $datalength) { -//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'
    '; - $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4; - $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; - $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; - switch ($data_size_type) { - case 0x0001: // 0x0001 = flag (size field *= 1-byte) - $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1)); - $offset += ($data_size * 1); - break; - case 0x0002: // 0x0002 = char (size field *= 1-byte) - $data = substr($atom_data, $offset, $data_size * 1); - $offset += ($data_size * 1); - $data = rtrim($data, "\x00"); - break; - case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB - $data = ''; - for ($i = $data_size - 1; $i >= 0; $i--) { - $data .= substr($atom_data, $offset + ($i * 2), 2); - } - $data = getid3_lib::BigEndian2Int($data); - $offset += ($data_size * 2); - break; - case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD - $data = ''; - for ($i = $data_size - 1; $i >= 0; $i--) { - $data .= substr($atom_data, $offset + ($i * 4), 4); - } - $data = getid3_lib::BigEndian2Int($data); - $offset += ($data_size * 4); - break; - case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together - $data = array(); - for ($i = 0; $i < $data_size; $i++) { - $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4)); - $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4)); - if ($denomninator == 0) { - $data[$i] = false; - } else { - $data[$i] = (double) $numerator / $denomninator; - } - } - $offset += (8 * $data_size); - if (count($data) == 1) { - $data = $data[0]; - } - break; - case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? - $data = substr($atom_data, $offset, $data_size * 1); - $offset += ($data_size * 1); - break; - case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? - $data = substr($atom_data, $offset, $data_size * 2); - $offset += ($data_size * 2); - break; - default: -echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'
    '; - break 2; - } - - switch ($record_type) { - case 0x00000011: // CreateDate - case 0x00000012: // DateTimeOriginal - $data = strtotime($data); - break; - case 0x0200001e: // ColorSpace - switch ($data) { - case 1: - $data = 'sRGB'; - break; - case 2: - $data = 'Adobe RGB'; - break; - } - break; - case 0x02000023: // PictureControlData - $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full'); - $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a'); - $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a'); - $data = array( - 'PictureControlVersion' => substr($data, 0, 4), - 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"), - 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"), - //'?' => substr($data, 44, 4), - 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))], - 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)), - 'Sharpness' => ord(substr($data, 50, 1)), - 'Contrast' => ord(substr($data, 51, 1)), - 'Brightness' => ord(substr($data, 52, 1)), - 'Saturation' => ord(substr($data, 53, 1)), - 'HueAdjustment' => ord(substr($data, 54, 1)), - 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))], - 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))], - 'ToningSaturation' => ord(substr($data, 57, 1)), - ); - break; - case 0x02000024: // WorldTime - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime - // timezone is stored as offset from GMT in minutes - $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2)); - if ($timezone & 0x8000) { - $timezone = 0 - (0x10000 - $timezone); - } - $timezone /= 60; - - $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1)); - switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) { - case 2: - $datedisplayformat = 'D/M/Y'; break; - case 1: - $datedisplayformat = 'M/D/Y'; break; - case 0: - default: - $datedisplayformat = 'Y/M/D'; break; - } - - $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat); - break; - case 0x02000083: // LensType - $data = array( - //'_' => $data, - 'mf' => (bool) ($data & 0x01), - 'd' => (bool) ($data & 0x02), - 'g' => (bool) ($data & 0x04), - 'vr' => (bool) ($data & 0x08), - ); - break; - } - $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT)); - $parsed[$tag_name] = $data; - } - return $parsed; - } - - - public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') { - static $handyatomtranslatorarray = array(); - if (empty($handyatomtranslatorarray)) { - $handyatomtranslatorarray['©cpy'] = 'copyright'; - $handyatomtranslatorarray['©day'] = 'creation_date'; // iTunes 4.0 - $handyatomtranslatorarray['©dir'] = 'director'; - $handyatomtranslatorarray['©ed1'] = 'edit1'; - $handyatomtranslatorarray['©ed2'] = 'edit2'; - $handyatomtranslatorarray['©ed3'] = 'edit3'; - $handyatomtranslatorarray['©ed4'] = 'edit4'; - $handyatomtranslatorarray['©ed5'] = 'edit5'; - $handyatomtranslatorarray['©ed6'] = 'edit6'; - $handyatomtranslatorarray['©ed7'] = 'edit7'; - $handyatomtranslatorarray['©ed8'] = 'edit8'; - $handyatomtranslatorarray['©ed9'] = 'edit9'; - $handyatomtranslatorarray['©fmt'] = 'format'; - $handyatomtranslatorarray['©inf'] = 'information'; - $handyatomtranslatorarray['©prd'] = 'producer'; - $handyatomtranslatorarray['©prf'] = 'performers'; - $handyatomtranslatorarray['©req'] = 'system_requirements'; - $handyatomtranslatorarray['©src'] = 'source_credit'; - $handyatomtranslatorarray['©wrt'] = 'writer'; - - // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt - $handyatomtranslatorarray['©nam'] = 'title'; // iTunes 4.0 - $handyatomtranslatorarray['©cmt'] = 'comment'; // iTunes 4.0 - $handyatomtranslatorarray['©wrn'] = 'warning'; - $handyatomtranslatorarray['©hst'] = 'host_computer'; - $handyatomtranslatorarray['©mak'] = 'make'; - $handyatomtranslatorarray['©mod'] = 'model'; - $handyatomtranslatorarray['©PRD'] = 'product'; - $handyatomtranslatorarray['©swr'] = 'software'; - $handyatomtranslatorarray['©aut'] = 'author'; - $handyatomtranslatorarray['©ART'] = 'artist'; - $handyatomtranslatorarray['©trk'] = 'track'; - $handyatomtranslatorarray['©alb'] = 'album'; // iTunes 4.0 - $handyatomtranslatorarray['©com'] = 'comment'; - $handyatomtranslatorarray['©gen'] = 'genre'; // iTunes 4.0 - $handyatomtranslatorarray['©ope'] = 'composer'; - $handyatomtranslatorarray['©url'] = 'url'; - $handyatomtranslatorarray['©enc'] = 'encoder'; - - // http://atomicparsley.sourceforge.net/mpeg-4files.html - $handyatomtranslatorarray['©art'] = 'artist'; // iTunes 4.0 - $handyatomtranslatorarray['aART'] = 'album_artist'; - $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0 - $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0 - $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0 - $handyatomtranslatorarray['©too'] = 'encoder'; // iTunes 4.0 - $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0 - $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0? - $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0 - $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0 - $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0 - $handyatomtranslatorarray['©grp'] = 'grouping'; // iTunes 4.2 - $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9 - $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9 - $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9 - $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9 - $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9 - $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9 - $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0 - $handyatomtranslatorarray['©lyr'] = 'lyrics'; // iTunes 5.0 - $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0 - $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0 - $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0 - $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0 - $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2 - $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0 - - // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt - - - - // boxnames: - /* - $handyatomtranslatorarray['iTunSMPB'] = 'iTunSMPB'; - $handyatomtranslatorarray['iTunNORM'] = 'iTunNORM'; - $handyatomtranslatorarray['Encoding Params'] = 'Encoding Params'; - $handyatomtranslatorarray['replaygain_track_gain'] = 'replaygain_track_gain'; - $handyatomtranslatorarray['replaygain_track_peak'] = 'replaygain_track_peak'; - $handyatomtranslatorarray['replaygain_track_minmax'] = 'replaygain_track_minmax'; - $handyatomtranslatorarray['MusicIP PUID'] = 'MusicIP PUID'; - $handyatomtranslatorarray['MusicBrainz Artist Id'] = 'MusicBrainz Artist Id'; - $handyatomtranslatorarray['MusicBrainz Album Id'] = 'MusicBrainz Album Id'; - $handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id'; - $handyatomtranslatorarray['MusicBrainz Track Id'] = 'MusicBrainz Track Id'; - $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id'; - - // http://age.hobba.nl/audio/tag_frame_reference.html - $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355 - $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355 - */ - } - $info = &$this->getid3->info; - $comment_key = ''; - if ($boxname && ($boxname != $keyname)) { - $comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname); - } elseif (isset($handyatomtranslatorarray[$keyname])) { - $comment_key = $handyatomtranslatorarray[$keyname]; - } - if ($comment_key) { - if ($comment_key == 'picture') { - if (!is_array($data)) { - $image_mime = ''; - if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) { - $image_mime = 'image/png'; - } elseif (preg_match('#^\xFF\xD8\xFF#', $data)) { - $image_mime = 'image/jpeg'; - } elseif (preg_match('#^GIF#', $data)) { - $image_mime = 'image/gif'; - } elseif (preg_match('#^BM#', $data)) { - $image_mime = 'image/bmp'; - } - $data = array('data'=>$data, 'image_mime'=>$image_mime); - } - } - $info['quicktime']['comments'][$comment_key][] = $data; - } - return true; - } - - public function NoNullString($nullterminatedstring) { - // remove the single null terminator on null terminated strings - if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") { - return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1); - } - return $nullterminatedstring; - } - - public function Pascal2String($pascalstring) { - // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string - return substr($pascalstring, 1); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.quicktime.php // +// module for analyzing Quicktime and MP3-in-MP4 files // +// dependencies: module.audio.mp3.php // +// dependencies: module.tag.id3v2.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); // needed for ISO 639-2 language code lookup + +class getid3_quicktime extends getid3_handler +{ + + public $ReturnAtomData = true; + public $ParseAllPossibleAtoms = false; + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'quicktime'; + $info['quicktime']['hinting'] = false; + $info['quicktime']['controller'] = 'standard'; // may be overridden if 'ctyp' atom is present + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $offset = 0; + $atomcounter = 0; + + while ($offset < $info['avdataend']) { + if (!getid3_lib::intValueSupported($offset)) { + $info['error'][] = 'Unable to parse atom at offset '.$offset.' because beyond '.round(PHP_INT_MAX / 1073741824).'GB limit of PHP filesystem functions'; + break; + } + fseek($this->getid3->fp, $offset, SEEK_SET); + $AtomHeader = fread($this->getid3->fp, 8); + + $atomsize = getid3_lib::BigEndian2Int(substr($AtomHeader, 0, 4)); + $atomname = substr($AtomHeader, 4, 4); + + // 64-bit MOV patch by jlegateØktnc*com + if ($atomsize == 1) { + $atomsize = getid3_lib::BigEndian2Int(fread($this->getid3->fp, 8)); + } + + $info['quicktime'][$atomname]['name'] = $atomname; + $info['quicktime'][$atomname]['size'] = $atomsize; + $info['quicktime'][$atomname]['offset'] = $offset; + + if (($offset + $atomsize) > $info['avdataend']) { + $info['error'][] = 'Atom at offset '.$offset.' claims to go beyond end-of-file (length: '.$atomsize.' bytes)'; + return false; + } + + if ($atomsize == 0) { + // Furthermore, for historical reasons the list of atoms is optionally + // terminated by a 32-bit integer set to 0. If you are writing a program + // to read user data atoms, you should allow for the terminating 0. + break; + } + switch ($atomname) { + case 'mdat': // Media DATa atom + // 'mdat' contains the actual data for the audio/video + if (($atomsize > 8) && (!isset($info['avdataend_tmp']) || ($info['quicktime'][$atomname]['size'] > ($info['avdataend_tmp'] - $info['avdataoffset'])))) { + + $info['avdataoffset'] = $info['quicktime'][$atomname]['offset'] + 8; + $OldAVDataEnd = $info['avdataend']; + $info['avdataend'] = $info['quicktime'][$atomname]['offset'] + $info['quicktime'][$atomname]['size']; + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_temp->info['avdataend'] = $info['avdataend']; + $getid3_mp3 = new getid3_mp3($getid3_temp); + if ($getid3_mp3->MPEGaudioHeaderValid($getid3_mp3->MPEGaudioHeaderDecode(fread($this->getid3->fp, 4)))) { + $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $value) { + $info['warning'][] = $value; + } + } + if (!empty($getid3_temp->info['mpeg'])) { + $info['mpeg'] = $getid3_temp->info['mpeg']; + if (isset($info['mpeg']['audio'])) { + $info['audio']['dataformat'] = 'mp3'; + $info['audio']['codec'] = (!empty($info['mpeg']['audio']['encoder']) ? $info['mpeg']['audio']['encoder'] : (!empty($info['mpeg']['audio']['codec']) ? $info['mpeg']['audio']['codec'] : (!empty($info['mpeg']['audio']['LAME']) ? 'LAME' :'mp3'))); + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + $info['bitrate'] = $info['audio']['bitrate']; + } + } + } + unset($getid3_mp3, $getid3_temp); + $info['avdataend'] = $OldAVDataEnd; + unset($OldAVDataEnd); + + } + break; + + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + break; + + default: + $atomHierarchy = array(); + $info['quicktime'][$atomname] = $this->QuicktimeParseAtom($atomname, $atomsize, fread($this->getid3->fp, $atomsize), $offset, $atomHierarchy, $this->ParseAllPossibleAtoms); + break; + } + + $offset += $atomsize; + $atomcounter++; + } + + if (!empty($info['avdataend_tmp'])) { + // this value is assigned to a temp value and then erased because + // otherwise any atoms beyond the 'mdat' atom would not get parsed + $info['avdataend'] = $info['avdataend_tmp']; + unset($info['avdataend_tmp']); + } + + if (!isset($info['bitrate']) && isset($info['playtime_seconds'])) { + $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + if (isset($info['bitrate']) && !isset($info['audio']['bitrate']) && !isset($info['quicktime']['video'])) { + $info['audio']['bitrate'] = $info['bitrate']; + } + if (!empty($info['playtime_seconds']) && !isset($info['video']['frame_rate']) && !empty($info['quicktime']['stts_framecount'])) { + foreach ($info['quicktime']['stts_framecount'] as $key => $samples_count) { + $samples_per_second = $samples_count / $info['playtime_seconds']; + if ($samples_per_second > 240) { + // has to be audio samples + } else { + $info['video']['frame_rate'] = $samples_per_second; + break; + } + } + } + if (($info['audio']['dataformat'] == 'mp4') && empty($info['video']['resolution_x'])) { + $info['fileformat'] = 'mp4'; + $info['mime_type'] = 'audio/mp4'; + unset($info['video']['dataformat']); + } + + if (!$this->ReturnAtomData) { + unset($info['quicktime']['moov']); + } + + if (empty($info['audio']['dataformat']) && !empty($info['quicktime']['audio'])) { + $info['audio']['dataformat'] = 'quicktime'; + } + if (empty($info['video']['dataformat']) && !empty($info['quicktime']['video'])) { + $info['video']['dataformat'] = 'quicktime'; + } + + return true; + } + + public function QuicktimeParseAtom($atomname, $atomsize, $atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { + // http://developer.apple.com/techpubs/quicktime/qtdevdocs/APIREF/INDEX/atomalphaindex.htm + + $info = &$this->getid3->info; + + //$atom_parent = array_pop($atomHierarchy); + $atom_parent = end($atomHierarchy); // http://www.getid3.org/phpBB3/viewtopic.php?t=1717 + array_push($atomHierarchy, $atomname); + $atom_structure['hierarchy'] = implode(' ', $atomHierarchy); + $atom_structure['name'] = $atomname; + $atom_structure['size'] = $atomsize; + $atom_structure['offset'] = $baseoffset; +//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8)).'
    '; +//echo getid3_lib::PrintHexBytes(substr($atom_data, 0, 8), false).'

    '; + switch ($atomname) { + case 'moov': // MOVie container atom + case 'trak': // TRAcK container atom + case 'clip': // CLIPping container atom + case 'matt': // track MATTe container atom + case 'edts': // EDiTS container atom + case 'tref': // Track REFerence container atom + case 'mdia': // MeDIA container atom + case 'minf': // Media INFormation container atom + case 'dinf': // Data INFormation container atom + case 'udta': // User DaTA container atom + case 'cmov': // Compressed MOVie container atom + case 'rmra': // Reference Movie Record Atom + case 'rmda': // Reference Movie Descriptor Atom + case 'gmhd': // Generic Media info HeaDer atom (seen on QTVR) + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + break; + + case 'ilst': // Item LiST container atom + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + + // some "ilst" atoms contain data atoms that have a numeric name, and the data is far more accessible if the returned array is compacted + $allnumericnames = true; + foreach ($atom_structure['subatoms'] as $subatomarray) { + if (!is_integer($subatomarray['name']) || (count($subatomarray['subatoms']) != 1)) { + $allnumericnames = false; + break; + } + } + if ($allnumericnames) { + $newData = array(); + foreach ($atom_structure['subatoms'] as $subatomarray) { + foreach ($subatomarray['subatoms'] as $newData_subatomarray) { + unset($newData_subatomarray['hierarchy'], $newData_subatomarray['name']); + $newData[$subatomarray['name']] = $newData_subatomarray; + break; + } + } + $atom_structure['data'] = $newData; + unset($atom_structure['subatoms']); + } + break; + + case "\x00\x00\x00\x01": + case "\x00\x00\x00\x02": + case "\x00\x00\x00\x03": + case "\x00\x00\x00\x04": + case "\x00\x00\x00\x05": + $atomname = getid3_lib::BigEndian2Int($atomname); + $atom_structure['name'] = $atomname; + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + break; + + case 'stbl': // Sample TaBLe container atom + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + $isVideo = false; + $framerate = 0; + $framecount = 0; + foreach ($atom_structure['subatoms'] as $key => $value_array) { + if (isset($value_array['sample_description_table'])) { + foreach ($value_array['sample_description_table'] as $key2 => $value_array2) { + if (isset($value_array2['data_format'])) { + switch ($value_array2['data_format']) { + case 'avc1': + case 'mp4v': + // video data + $isVideo = true; + break; + case 'mp4a': + // audio data + break; + } + } + } + } elseif (isset($value_array['time_to_sample_table'])) { + foreach ($value_array['time_to_sample_table'] as $key2 => $value_array2) { + if (isset($value_array2['sample_count']) && isset($value_array2['sample_duration']) && ($value_array2['sample_duration'] > 0)) { + $framerate = round($info['quicktime']['time_scale'] / $value_array2['sample_duration'], 3); + $framecount = $value_array2['sample_count']; + } + } + } + } + if ($isVideo && $framerate) { + $info['quicktime']['video']['frame_rate'] = $framerate; + $info['video']['frame_rate'] = $info['quicktime']['video']['frame_rate']; + } + if ($isVideo && $framecount) { + $info['quicktime']['video']['frame_count'] = $framecount; + } + break; + + + case 'aART': // Album ARTist + case 'catg': // CaTeGory + case 'covr': // COVeR artwork + case 'cpil': // ComPILation + case 'cprt': // CoPyRighT + case 'desc': // DESCription + case 'disk': // DISK number + case 'egid': // Episode Global ID + case 'gnre': // GeNRE + case 'keyw': // KEYWord + case 'ldes': + case 'pcst': // PodCaST + case 'pgap': // GAPless Playback + case 'purd': // PURchase Date + case 'purl': // Podcast URL + case 'rati': + case 'rndu': + case 'rpdu': + case 'rtng': // RaTiNG + case 'stik': + case 'tmpo': // TeMPO (BPM) + case 'trkn': // TRacK Number + case 'tves': // TV EpiSode + case 'tvnn': // TV Network Name + case 'tvsh': // TV SHow Name + case 'tvsn': // TV SeasoN + case 'akID': // iTunes store account type + case 'apID': + case 'atID': + case 'cmID': + case 'cnID': + case 'geID': + case 'plID': + case 'sfID': // iTunes store country + case '©alb': // ALBum + case '©art': // ARTist + case '©ART': + case '©aut': + case '©cmt': // CoMmenT + case '©com': // COMposer + case '©cpy': + case '©day': // content created year + case '©dir': + case '©ed1': + case '©ed2': + case '©ed3': + case '©ed4': + case '©ed5': + case '©ed6': + case '©ed7': + case '©ed8': + case '©ed9': + case '©enc': + case '©fmt': + case '©gen': // GENre + case '©grp': // GRouPing + case '©hst': + case '©inf': + case '©lyr': // LYRics + case '©mak': + case '©mod': + case '©nam': // full NAMe + case '©ope': + case '©PRD': + case '©prd': + case '©prf': + case '©req': + case '©src': + case '©swr': + case '©too': // encoder + case '©trk': // TRacK + case '©url': + case '©wrn': + case '©wrt': // WRiTer + case '----': // itunes specific + if ($atom_parent == 'udta') { + // User data atom handler + $atom_structure['data_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); + $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); + $atom_structure['data'] = substr($atom_data, 4); + + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + } else { + // Apple item list box atom handler + $atomoffset = 0; + if (substr($atom_data, 2, 2) == "\x10\xB5") { + // not sure what it means, but observed on iPhone4 data. + // Each $atom_data has 2 bytes of datasize, plus 0x10B5, then data + while ($atomoffset < strlen($atom_data)) { + $boxsmallsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 2)); + $boxsmalltype = substr($atom_data, $atomoffset + 2, 2); + $boxsmalldata = substr($atom_data, $atomoffset + 4, $boxsmallsize); + if ($boxsmallsize <= 1) { + $info['warning'][] = 'Invalid QuickTime atom smallbox size "'.$boxsmallsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset); + $atom_structure['data'] = null; + $atomoffset = strlen($atom_data); + break; + } + switch ($boxsmalltype) { + case "\x10\xB5": + $atom_structure['data'] = $boxsmalldata; + break; + default: + $info['warning'][] = 'Unknown QuickTime smallbox type: "'.getid3_lib::PrintHexBytes($boxsmalltype).'" at offset '.$baseoffset; + $atom_structure['data'] = $atom_data; + break; + } + $atomoffset += (4 + $boxsmallsize); + } + } else { + while ($atomoffset < strlen($atom_data)) { + $boxsize = getid3_lib::BigEndian2Int(substr($atom_data, $atomoffset, 4)); + $boxtype = substr($atom_data, $atomoffset + 4, 4); + $boxdata = substr($atom_data, $atomoffset + 8, $boxsize - 8); + if ($boxsize <= 1) { + $info['warning'][] = 'Invalid QuickTime atom box size "'.$boxsize.'" in atom "'.$atomname.'" at offset: '.($atom_structure['offset'] + $atomoffset); + $atom_structure['data'] = null; + $atomoffset = strlen($atom_data); + break; + } + $atomoffset += $boxsize; + + switch ($boxtype) { + case 'mean': + case 'name': + $atom_structure[$boxtype] = substr($boxdata, 4); + break; + + case 'data': + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($boxdata, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($boxdata, 1, 3)); + switch ($atom_structure['flags_raw']) { + case 0: // data flag + case 21: // tmpo/cpil flag + switch ($atomname) { + case 'cpil': + case 'pcst': + case 'pgap': + $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); + break; + + case 'tmpo': + $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 2)); + break; + + case 'disk': + case 'trkn': + $num = getid3_lib::BigEndian2Int(substr($boxdata, 10, 2)); + $num_total = getid3_lib::BigEndian2Int(substr($boxdata, 12, 2)); + $atom_structure['data'] = empty($num) ? '' : $num; + $atom_structure['data'] .= empty($num_total) ? '' : '/'.$num_total; + break; + + case 'gnre': + $GenreID = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); + $atom_structure['data'] = getid3_id3v1::LookupGenreName($GenreID - 1); + break; + + case 'rtng': + $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); + $atom_structure['data'] = $this->QuicktimeContentRatingLookup($atom_structure[$atomname]); + break; + + case 'stik': + $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 1)); + $atom_structure['data'] = $this->QuicktimeSTIKLookup($atom_structure[$atomname]); + break; + + case 'sfID': + $atom_structure[$atomname] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); + $atom_structure['data'] = $this->QuicktimeStoreFrontCodeLookup($atom_structure[$atomname]); + break; + + case 'egid': + case 'purl': + $atom_structure['data'] = substr($boxdata, 8); + break; + + default: + $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($boxdata, 8, 4)); + } + break; + + case 1: // text flag + case 13: // image flag + default: + $atom_structure['data'] = substr($boxdata, 8); + break; + + } + break; + + default: + $info['warning'][] = 'Unknown QuickTime box type: "'.getid3_lib::PrintHexBytes($boxtype).'" at offset '.$baseoffset; + $atom_structure['data'] = $atom_data; + + } + } + } + } + $this->CopyToAppropriateCommentsSection($atomname, $atom_structure['data'], $atom_structure['name']); + break; + + + case 'play': // auto-PLAY atom + $atom_structure['autoplay'] = (bool) getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + + $info['quicktime']['autoplay'] = $atom_structure['autoplay']; + break; + + + case 'WLOC': // Window LOCation atom + $atom_structure['location_x'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); + $atom_structure['location_y'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); + break; + + + case 'LOOP': // LOOPing atom + case 'SelO': // play SELection Only atom + case 'AllF': // play ALL Frames atom + $atom_structure['data'] = getid3_lib::BigEndian2Int($atom_data); + break; + + + case 'name': // + case 'MCPS': // Media Cleaner PRo + case '@PRM': // adobe PReMiere version + case '@PRQ': // adobe PRemiere Quicktime version + $atom_structure['data'] = $atom_data; + break; + + + case 'cmvd': // Compressed MooV Data atom + // Code by ubergeekØubergeek*tv based on information from + // http://developer.apple.com/quicktime/icefloe/dispatch012.html + $atom_structure['unCompressedSize'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + + $CompressedFileData = substr($atom_data, 4); + if ($UncompressedHeader = @gzuncompress($CompressedFileData)) { + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($UncompressedHeader, 0, $atomHierarchy, $ParseAllPossibleAtoms); + } else { + $info['warning'][] = 'Error decompressing compressed MOV atom at offset '.$atom_structure['offset']; + } + break; + + + case 'dcom': // Data COMpression atom + $atom_structure['compression_id'] = $atom_data; + $atom_structure['compression_text'] = $this->QuicktimeDCOMLookup($atom_data); + break; + + + case 'rdrf': // Reference movie Data ReFerence atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); + $atom_structure['flags']['internal_data'] = (bool) ($atom_structure['flags_raw'] & 0x000001); + + $atom_structure['reference_type_name'] = substr($atom_data, 4, 4); + $atom_structure['reference_length'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + switch ($atom_structure['reference_type_name']) { + case 'url ': + $atom_structure['url'] = $this->NoNullString(substr($atom_data, 12)); + break; + + case 'alis': + $atom_structure['file_alias'] = substr($atom_data, 12); + break; + + case 'rsrc': + $atom_structure['resource_alias'] = substr($atom_data, 12); + break; + + default: + $atom_structure['data'] = substr($atom_data, 12); + break; + } + break; + + + case 'rmqu': // Reference Movie QUality atom + $atom_structure['movie_quality'] = getid3_lib::BigEndian2Int($atom_data); + break; + + + case 'rmcs': // Reference Movie Cpu Speed atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['cpu_speed_rating'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + break; + + + case 'rmvc': // Reference Movie Version Check atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['gestalt_selector'] = substr($atom_data, 4, 4); + $atom_structure['gestalt_value_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $atom_structure['gestalt_value'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); + $atom_structure['gestalt_check_type'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); + break; + + + case 'rmcd': // Reference Movie Component check atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['component_type'] = substr($atom_data, 4, 4); + $atom_structure['component_subtype'] = substr($atom_data, 8, 4); + $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); + $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); + $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); + $atom_structure['component_min_version'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 4)); + break; + + + case 'rmdr': // Reference Movie Data Rate atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['data_rate'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + + $atom_structure['data_rate_bps'] = $atom_structure['data_rate'] * 10; + break; + + + case 'rmla': // Reference Movie Language Atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + break; + + + case 'rmla': // Reference Movie Language Atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + break; + + + case 'ptv ': // Print To Video - defines a movie's full screen mode + // http://developer.apple.com/documentation/QuickTime/APIREF/SOURCESIV/at_ptv-_pg.htm + $atom_structure['display_size_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); + $atom_structure['reserved_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 2)); // hardcoded: 0x0000 + $atom_structure['reserved_2'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x0000 + $atom_structure['slide_show_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 1)); + $atom_structure['play_on_open_flag'] = getid3_lib::BigEndian2Int(substr($atom_data, 7, 1)); + + $atom_structure['flags']['play_on_open'] = (bool) $atom_structure['play_on_open_flag']; + $atom_structure['flags']['slide_show'] = (bool) $atom_structure['slide_show_flag']; + + $ptv_lookup[0] = 'normal'; + $ptv_lookup[1] = 'double'; + $ptv_lookup[2] = 'half'; + $ptv_lookup[3] = 'full'; + $ptv_lookup[4] = 'current'; + if (isset($ptv_lookup[$atom_structure['display_size_raw']])) { + $atom_structure['display_size'] = $ptv_lookup[$atom_structure['display_size_raw']]; + } else { + $info['warning'][] = 'unknown "ptv " display constant ('.$atom_structure['display_size_raw'].')'; + } + break; + + + case 'stsd': // Sample Table Sample Description atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stsdEntriesDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['sample_description_table'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 4)); + $stsdEntriesDataOffset += 4; + $atom_structure['sample_description_table'][$i]['data_format'] = substr($atom_data, $stsdEntriesDataOffset, 4); + $stsdEntriesDataOffset += 4; + $atom_structure['sample_description_table'][$i]['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 6)); + $stsdEntriesDataOffset += 6; + $atom_structure['sample_description_table'][$i]['reference_index'] = getid3_lib::BigEndian2Int(substr($atom_data, $stsdEntriesDataOffset, 2)); + $stsdEntriesDataOffset += 2; + $atom_structure['sample_description_table'][$i]['data'] = substr($atom_data, $stsdEntriesDataOffset, ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2)); + $stsdEntriesDataOffset += ($atom_structure['sample_description_table'][$i]['size'] - 4 - 4 - 6 - 2); + + $atom_structure['sample_description_table'][$i]['encoder_version'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 0, 2)); + $atom_structure['sample_description_table'][$i]['encoder_revision'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 2, 2)); + $atom_structure['sample_description_table'][$i]['encoder_vendor'] = substr($atom_structure['sample_description_table'][$i]['data'], 4, 4); + + switch ($atom_structure['sample_description_table'][$i]['encoder_vendor']) { + + case "\x00\x00\x00\x00": + // audio tracks + $atom_structure['sample_description_table'][$i]['audio_channels'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 2)); + $atom_structure['sample_description_table'][$i]['audio_bit_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 10, 2)); + $atom_structure['sample_description_table'][$i]['audio_compression_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 2)); + $atom_structure['sample_description_table'][$i]['audio_packet_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 14, 2)); + $atom_structure['sample_description_table'][$i]['audio_sample_rate'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 16, 4)); + + // video tracks + // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap3/qtff3.html + $atom_structure['sample_description_table'][$i]['temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); + $atom_structure['sample_description_table'][$i]['spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); + $atom_structure['sample_description_table'][$i]['width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); + $atom_structure['sample_description_table'][$i]['height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); + $atom_structure['sample_description_table'][$i]['resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); + $atom_structure['sample_description_table'][$i]['resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); + $atom_structure['sample_description_table'][$i]['data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 4)); + $atom_structure['sample_description_table'][$i]['frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 36, 2)); + $atom_structure['sample_description_table'][$i]['compressor_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 38, 4); + $atom_structure['sample_description_table'][$i]['pixel_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 42, 2)); + $atom_structure['sample_description_table'][$i]['color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 44, 2)); + + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + case '2vuY': + case 'avc1': + case 'cvid': + case 'dvc ': + case 'dvcp': + case 'gif ': + case 'h263': + case 'jpeg': + case 'kpcd': + case 'mjpa': + case 'mjpb': + case 'mp4v': + case 'png ': + case 'raw ': + case 'rle ': + case 'rpza': + case 'smc ': + case 'SVQ1': + case 'SVQ3': + case 'tiff': + case 'v210': + case 'v216': + case 'v308': + case 'v408': + case 'v410': + case 'yuv2': + $info['fileformat'] = 'mp4'; + $info['video']['fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; +// http://www.getid3.org/phpBB3/viewtopic.php?t=1550 +//if ((!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['width'])) && (empty($info['video']['resolution_x']) || empty($info['video']['resolution_y']) || (number_format($info['video']['resolution_x'], 6) != number_format(round($info['video']['resolution_x']), 6)) || (number_format($info['video']['resolution_y'], 6) != number_format(round($info['video']['resolution_y']), 6)))) { // ugly check for floating point numbers +if (!empty($atom_structure['sample_description_table'][$i]['width']) && !empty($atom_structure['sample_description_table'][$i]['height'])) { + // assume that values stored here are more important than values stored in [tkhd] atom + $info['video']['resolution_x'] = $atom_structure['sample_description_table'][$i]['width']; + $info['video']['resolution_y'] = $atom_structure['sample_description_table'][$i]['height']; + $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; + $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; +} + break; + + case 'qtvr': + $info['video']['dataformat'] = 'quicktimevr'; + break; + + case 'mp4a': + default: + $info['quicktime']['audio']['codec'] = $this->QuicktimeAudioCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); + $info['quicktime']['audio']['sample_rate'] = $atom_structure['sample_description_table'][$i]['audio_sample_rate']; + $info['quicktime']['audio']['channels'] = $atom_structure['sample_description_table'][$i]['audio_channels']; + $info['quicktime']['audio']['bit_depth'] = $atom_structure['sample_description_table'][$i]['audio_bit_depth']; + $info['audio']['codec'] = $info['quicktime']['audio']['codec']; + $info['audio']['sample_rate'] = $info['quicktime']['audio']['sample_rate']; + $info['audio']['channels'] = $info['quicktime']['audio']['channels']; + $info['audio']['bits_per_sample'] = $info['quicktime']['audio']['bit_depth']; + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + case 'raw ': // PCM + case 'alac': // Apple Lossless Audio Codec + $info['audio']['lossless'] = true; + break; + default: + $info['audio']['lossless'] = false; + break; + } + break; + } + break; + + default: + switch ($atom_structure['sample_description_table'][$i]['data_format']) { + case 'mp4s': + $info['fileformat'] = 'mp4'; + break; + + default: + // video atom + $atom_structure['sample_description_table'][$i]['video_temporal_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 8, 4)); + $atom_structure['sample_description_table'][$i]['video_spatial_quality'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 12, 4)); + $atom_structure['sample_description_table'][$i]['video_frame_width'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 16, 2)); + $atom_structure['sample_description_table'][$i]['video_frame_height'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 18, 2)); + $atom_structure['sample_description_table'][$i]['video_resolution_x'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 20, 4)); + $atom_structure['sample_description_table'][$i]['video_resolution_y'] = getid3_lib::FixedPoint16_16(substr($atom_structure['sample_description_table'][$i]['data'], 24, 4)); + $atom_structure['sample_description_table'][$i]['video_data_size'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 28, 4)); + $atom_structure['sample_description_table'][$i]['video_frame_count'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 32, 2)); + $atom_structure['sample_description_table'][$i]['video_encoder_name_len'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 34, 1)); + $atom_structure['sample_description_table'][$i]['video_encoder_name'] = substr($atom_structure['sample_description_table'][$i]['data'], 35, $atom_structure['sample_description_table'][$i]['video_encoder_name_len']); + $atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 66, 2)); + $atom_structure['sample_description_table'][$i]['video_color_table_id'] = getid3_lib::BigEndian2Int(substr($atom_structure['sample_description_table'][$i]['data'], 68, 2)); + + $atom_structure['sample_description_table'][$i]['video_pixel_color_type'] = (($atom_structure['sample_description_table'][$i]['video_pixel_color_depth'] > 32) ? 'grayscale' : 'color'); + $atom_structure['sample_description_table'][$i]['video_pixel_color_name'] = $this->QuicktimeColorNameLookup($atom_structure['sample_description_table'][$i]['video_pixel_color_depth']); + + if ($atom_structure['sample_description_table'][$i]['video_pixel_color_name'] != 'invalid') { + $info['quicktime']['video']['codec_fourcc'] = $atom_structure['sample_description_table'][$i]['data_format']; + $info['quicktime']['video']['codec_fourcc_lookup'] = $this->QuicktimeVideoCodecLookup($atom_structure['sample_description_table'][$i]['data_format']); + $info['quicktime']['video']['codec'] = (($atom_structure['sample_description_table'][$i]['video_encoder_name_len'] > 0) ? $atom_structure['sample_description_table'][$i]['video_encoder_name'] : $atom_structure['sample_description_table'][$i]['data_format']); + $info['quicktime']['video']['color_depth'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_depth']; + $info['quicktime']['video']['color_depth_name'] = $atom_structure['sample_description_table'][$i]['video_pixel_color_name']; + + $info['video']['codec'] = $info['quicktime']['video']['codec']; + $info['video']['bits_per_sample'] = $info['quicktime']['video']['color_depth']; + } + $info['video']['lossless'] = false; + $info['video']['pixel_aspect_ratio'] = (float) 1; + break; + } + break; + } + switch (strtolower($atom_structure['sample_description_table'][$i]['data_format'])) { + case 'mp4a': + $info['audio']['dataformat'] = 'mp4'; + $info['quicktime']['audio']['codec'] = 'mp4'; + break; + + case '3ivx': + case '3iv1': + case '3iv2': + $info['video']['dataformat'] = '3ivx'; + break; + + case 'xvid': + $info['video']['dataformat'] = 'xvid'; + break; + + case 'mp4v': + $info['video']['dataformat'] = 'mpeg4'; + break; + + case 'divx': + case 'div1': + case 'div2': + case 'div3': + case 'div4': + case 'div5': + case 'div6': + $info['video']['dataformat'] = 'divx'; + break; + + default: + // do nothing + break; + } + unset($atom_structure['sample_description_table'][$i]['data']); + } + break; + + + case 'stts': // Sample Table Time-to-Sample atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $sttsEntriesDataOffset = 8; + //$FrameRateCalculatorArray = array(); + $frames_count = 0; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['time_to_sample_table'][$i]['sample_count'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); + $sttsEntriesDataOffset += 4; + $atom_structure['time_to_sample_table'][$i]['sample_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, $sttsEntriesDataOffset, 4)); + $sttsEntriesDataOffset += 4; + + $frames_count += $atom_structure['time_to_sample_table'][$i]['sample_count']; + + // THIS SECTION REPLACED WITH CODE IN "stbl" ATOM + //if (!empty($info['quicktime']['time_scale']) && ($atom_structure['time_to_sample_table'][$i]['sample_duration'] > 0)) { + // $stts_new_framerate = $info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration']; + // if ($stts_new_framerate <= 60) { + // // some atoms have durations of "1" giving a very large framerate, which probably is not right + // $info['video']['frame_rate'] = max($info['video']['frame_rate'], $stts_new_framerate); + // } + //} + // + //$FrameRateCalculatorArray[($info['quicktime']['time_scale'] / $atom_structure['time_to_sample_table'][$i]['sample_duration'])] += $atom_structure['time_to_sample_table'][$i]['sample_count']; + } + $info['quicktime']['stts_framecount'][] = $frames_count; + //$sttsFramesTotal = 0; + //$sttsSecondsTotal = 0; + //foreach ($FrameRateCalculatorArray as $frames_per_second => $frame_count) { + // if (($frames_per_second > 60) || ($frames_per_second < 1)) { + // // not video FPS information, probably audio information + // $sttsFramesTotal = 0; + // $sttsSecondsTotal = 0; + // break; + // } + // $sttsFramesTotal += $frame_count; + // $sttsSecondsTotal += $frame_count / $frames_per_second; + //} + //if (($sttsFramesTotal > 0) && ($sttsSecondsTotal > 0)) { + // if (($sttsFramesTotal / $sttsSecondsTotal) > $info['video']['frame_rate']) { + // $info['video']['frame_rate'] = $sttsFramesTotal / $sttsSecondsTotal; + // } + //} + break; + + + case 'stss': // Sample Table Sync Sample (key frames) atom + if ($ParseAllPossibleAtoms) { + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stssEntriesDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['time_to_sample_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stssEntriesDataOffset, 4)); + $stssEntriesDataOffset += 4; + } + } + break; + + + case 'stsc': // Sample Table Sample-to-Chunk atom + if ($ParseAllPossibleAtoms) { + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stscEntriesDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['sample_to_chunk_table'][$i]['first_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + $atom_structure['sample_to_chunk_table'][$i]['samples_per_chunk'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + $atom_structure['sample_to_chunk_table'][$i]['sample_description'] = getid3_lib::BigEndian2Int(substr($atom_data, $stscEntriesDataOffset, 4)); + $stscEntriesDataOffset += 4; + } + } + break; + + + case 'stsz': // Sample Table SiZe atom + if ($ParseAllPossibleAtoms) { + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['sample_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $stszEntriesDataOffset = 12; + if ($atom_structure['sample_size'] == 0) { + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['sample_size_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stszEntriesDataOffset, 4)); + $stszEntriesDataOffset += 4; + } + } + } + break; + + + case 'stco': // Sample Table Chunk Offset atom + if ($ParseAllPossibleAtoms) { + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stcoEntriesDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 4)); + $stcoEntriesDataOffset += 4; + } + } + break; + + + case 'co64': // Chunk Offset 64-bit (version of "stco" that supports > 2GB files) + if ($ParseAllPossibleAtoms) { + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $stcoEntriesDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['chunk_offset_table'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $stcoEntriesDataOffset, 8)); + $stcoEntriesDataOffset += 8; + } + } + break; + + + case 'dref': // Data REFerence atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $drefDataOffset = 8; + for ($i = 0; $i < $atom_structure['number_entries']; $i++) { + $atom_structure['data_references'][$i]['size'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 4)); + $drefDataOffset += 4; + $atom_structure['data_references'][$i]['type'] = substr($atom_data, $drefDataOffset, 4); + $drefDataOffset += 4; + $atom_structure['data_references'][$i]['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 1)); + $drefDataOffset += 1; + $atom_structure['data_references'][$i]['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $drefDataOffset, 3)); // hardcoded: 0x0000 + $drefDataOffset += 3; + $atom_structure['data_references'][$i]['data'] = substr($atom_data, $drefDataOffset, ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3)); + $drefDataOffset += ($atom_structure['data_references'][$i]['size'] - 4 - 4 - 1 - 3); + + $atom_structure['data_references'][$i]['flags']['self_reference'] = (bool) ($atom_structure['data_references'][$i]['flags_raw'] & 0x001); + } + break; + + + case 'gmin': // base Media INformation atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); + $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); + $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); + $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 2)); + $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 14, 2)); + break; + + + case 'smhd': // Sound Media information HeaDer atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['balance'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + $atom_structure['reserved'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); + break; + + + case 'vmhd': // Video Media information HeaDer atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); + $atom_structure['graphics_mode'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); + $atom_structure['opcolor_red'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)); + $atom_structure['opcolor_green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 2)); + $atom_structure['opcolor_blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); + + $atom_structure['flags']['no_lean_ahead'] = (bool) ($atom_structure['flags_raw'] & 0x001); + break; + + + case 'hdlr': // HanDLeR reference atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['component_type'] = substr($atom_data, 4, 4); + $atom_structure['component_subtype'] = substr($atom_data, 8, 4); + $atom_structure['component_manufacturer'] = substr($atom_data, 12, 4); + $atom_structure['component_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); + $atom_structure['component_flags_mask'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); + $atom_structure['component_name'] = $this->Pascal2String(substr($atom_data, 24)); + + if (($atom_structure['component_subtype'] == 'STpn') && ($atom_structure['component_manufacturer'] == 'zzzz')) { + $info['video']['dataformat'] = 'quicktimevr'; + } + break; + + + case 'mdhd': // MeDia HeaDer atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); + $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); + $atom_structure['language_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 2)); + $atom_structure['quality'] = getid3_lib::BigEndian2Int(substr($atom_data, 22, 2)); + + if ($atom_structure['time_scale'] == 0) { + $info['error'][] = 'Corrupt Quicktime file: mdhd.time_scale == zero'; + return false; + } + $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); + + $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); + $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); + $atom_structure['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; + $atom_structure['language'] = $this->QuicktimeLanguageLookup($atom_structure['language_id']); + if (empty($info['comments']['language']) || (!in_array($atom_structure['language'], $info['comments']['language']))) { + $info['comments']['language'][] = $atom_structure['language']; + } + break; + + + case 'pnot': // Preview atom + $atom_structure['modification_date'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // "standard Macintosh format" + $atom_structure['version_number'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x00 + $atom_structure['atom_type'] = substr($atom_data, 6, 4); // usually: 'PICT' + $atom_structure['atom_index'] = getid3_lib::BigEndian2Int(substr($atom_data, 10, 2)); // usually: 0x01 + + $atom_structure['modification_date_unix'] = getid3_lib::DateMac2Unix($atom_structure['modification_date']); + break; + + + case 'crgn': // Clipping ReGioN atom + $atom_structure['region_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 2)); // The Region size, Region boundary box, + $atom_structure['boundary_box'] = getid3_lib::BigEndian2Int(substr($atom_data, 2, 8)); // and Clipping region data fields + $atom_structure['clipping_data'] = substr($atom_data, 10); // constitute a QuickDraw region. + break; + + + case 'load': // track LOAD settings atom + $atom_structure['preload_start_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + $atom_structure['preload_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['preload_flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $atom_structure['default_hints_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); + + $atom_structure['default_hints']['double_buffer'] = (bool) ($atom_structure['default_hints_raw'] & 0x0020); + $atom_structure['default_hints']['high_quality'] = (bool) ($atom_structure['default_hints_raw'] & 0x0100); + break; + + + case 'tmcd': // TiMe CoDe atom + case 'chap': // CHAPter list atom + case 'sync': // SYNChronization atom + case 'scpt': // tranSCriPT atom + case 'ssrc': // non-primary SouRCe atom + for ($i = 0; $i < (strlen($atom_data) % 4); $i++) { + $atom_structure['track_id'][$i] = getid3_lib::BigEndian2Int(substr($atom_data, $i * 4, 4)); + } + break; + + + case 'elst': // Edit LiST atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['number_entries'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + for ($i = 0; $i < $atom_structure['number_entries']; $i++ ) { + $atom_structure['edit_list'][$i]['track_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 0, 4)); + $atom_structure['edit_list'][$i]['media_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($i * 12) + 4, 4)); + $atom_structure['edit_list'][$i]['media_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 8 + ($i * 12) + 8, 4)); + } + break; + + + case 'kmat': // compressed MATte atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); // hardcoded: 0x0000 + $atom_structure['matte_data_raw'] = substr($atom_data, 4); + break; + + + case 'ctab': // Color TABle atom + $atom_structure['color_table_seed'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); // hardcoded: 0x00000000 + $atom_structure['color_table_flags'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 2)); // hardcoded: 0x8000 + $atom_structure['color_table_size'] = getid3_lib::BigEndian2Int(substr($atom_data, 6, 2)) + 1; + for ($colortableentry = 0; $colortableentry < $atom_structure['color_table_size']; $colortableentry++) { + $atom_structure['color_table'][$colortableentry]['alpha'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 0, 2)); + $atom_structure['color_table'][$colortableentry]['red'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 2, 2)); + $atom_structure['color_table'][$colortableentry]['green'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 4, 2)); + $atom_structure['color_table'][$colortableentry]['blue'] = getid3_lib::BigEndian2Int(substr($atom_data, 8 + ($colortableentry * 8) + 6, 2)); + } + break; + + + case 'mvhd': // MoVie HeaDer atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); + $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $atom_structure['time_scale'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); + $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); + $atom_structure['preferred_rate'] = getid3_lib::FixedPoint16_16(substr($atom_data, 20, 4)); + $atom_structure['preferred_volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 24, 2)); + $atom_structure['reserved'] = substr($atom_data, 26, 10); + $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 36, 4)); + $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); + $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 44, 4)); + $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 48, 4)); + $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); + $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 56, 4)); + $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 60, 4)); + $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); + $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 68, 4)); + $atom_structure['preview_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 72, 4)); + $atom_structure['preview_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 76, 4)); + $atom_structure['poster_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 80, 4)); + $atom_structure['selection_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 84, 4)); + $atom_structure['selection_duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 88, 4)); + $atom_structure['current_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 92, 4)); + $atom_structure['next_track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, 96, 4)); + + if ($atom_structure['time_scale'] == 0) { + $info['error'][] = 'Corrupt Quicktime file: mvhd.time_scale == zero'; + return false; + } + $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); + $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); + $info['quicktime']['time_scale'] = (isset($info['quicktime']['time_scale']) ? max($info['quicktime']['time_scale'], $atom_structure['time_scale']) : $atom_structure['time_scale']); + $info['quicktime']['display_scale'] = $atom_structure['matrix_a']; + $info['playtime_seconds'] = $atom_structure['duration'] / $atom_structure['time_scale']; + break; + + + case 'tkhd': // TracK HeaDer atom + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); + $atom_structure['creation_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['modify_time'] = getid3_lib::BigEndian2Int(substr($atom_data, 8, 4)); + $atom_structure['trackid'] = getid3_lib::BigEndian2Int(substr($atom_data, 12, 4)); + $atom_structure['reserved1'] = getid3_lib::BigEndian2Int(substr($atom_data, 16, 4)); + $atom_structure['duration'] = getid3_lib::BigEndian2Int(substr($atom_data, 20, 4)); + $atom_structure['reserved2'] = getid3_lib::BigEndian2Int(substr($atom_data, 24, 8)); + $atom_structure['layer'] = getid3_lib::BigEndian2Int(substr($atom_data, 32, 2)); + $atom_structure['alternate_group'] = getid3_lib::BigEndian2Int(substr($atom_data, 34, 2)); + $atom_structure['volume'] = getid3_lib::FixedPoint8_8(substr($atom_data, 36, 2)); + $atom_structure['reserved3'] = getid3_lib::BigEndian2Int(substr($atom_data, 38, 2)); +// http://developer.apple.com/library/mac/#documentation/QuickTime/RM/MovieBasics/MTEditing/K-Chapter/11MatrixFunctions.html +// http://developer.apple.com/library/mac/#documentation/QuickTime/qtff/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-18737 + $atom_structure['matrix_a'] = getid3_lib::FixedPoint16_16(substr($atom_data, 40, 4)); + $atom_structure['matrix_b'] = getid3_lib::FixedPoint16_16(substr($atom_data, 44, 4)); + $atom_structure['matrix_u'] = getid3_lib::FixedPoint2_30(substr($atom_data, 48, 4)); + $atom_structure['matrix_c'] = getid3_lib::FixedPoint16_16(substr($atom_data, 52, 4)); + $atom_structure['matrix_d'] = getid3_lib::FixedPoint16_16(substr($atom_data, 56, 4)); + $atom_structure['matrix_v'] = getid3_lib::FixedPoint2_30(substr($atom_data, 60, 4)); + $atom_structure['matrix_x'] = getid3_lib::FixedPoint16_16(substr($atom_data, 64, 4)); + $atom_structure['matrix_y'] = getid3_lib::FixedPoint16_16(substr($atom_data, 68, 4)); + $atom_structure['matrix_w'] = getid3_lib::FixedPoint2_30(substr($atom_data, 72, 4)); + $atom_structure['width'] = getid3_lib::FixedPoint16_16(substr($atom_data, 76, 4)); + $atom_structure['height'] = getid3_lib::FixedPoint16_16(substr($atom_data, 80, 4)); + $atom_structure['flags']['enabled'] = (bool) ($atom_structure['flags_raw'] & 0x0001); + $atom_structure['flags']['in_movie'] = (bool) ($atom_structure['flags_raw'] & 0x0002); + $atom_structure['flags']['in_preview'] = (bool) ($atom_structure['flags_raw'] & 0x0004); + $atom_structure['flags']['in_poster'] = (bool) ($atom_structure['flags_raw'] & 0x0008); + $atom_structure['creation_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['creation_time']); + $atom_structure['modify_time_unix'] = getid3_lib::DateMac2Unix($atom_structure['modify_time']); + + if ($atom_structure['flags']['enabled'] == 1) { + if (!isset($info['video']['resolution_x']) || !isset($info['video']['resolution_y'])) { + $info['video']['resolution_x'] = $atom_structure['width']; + $info['video']['resolution_y'] = $atom_structure['height']; + } + $info['video']['resolution_x'] = max($info['video']['resolution_x'], $atom_structure['width']); + $info['video']['resolution_y'] = max($info['video']['resolution_y'], $atom_structure['height']); + $info['quicktime']['video']['resolution_x'] = $info['video']['resolution_x']; + $info['quicktime']['video']['resolution_y'] = $info['video']['resolution_y']; + } else { + // see: http://www.getid3.org/phpBB3/viewtopic.php?t=1295 + //if (isset($info['video']['resolution_x'])) { unset($info['video']['resolution_x']); } + //if (isset($info['video']['resolution_y'])) { unset($info['video']['resolution_y']); } + //if (isset($info['quicktime']['video'])) { unset($info['quicktime']['video']); } + } + break; + + + case 'iods': // Initial Object DeScriptor atom + // http://www.koders.com/c/fid1FAB3E762903DC482D8A246D4A4BF9F28E049594.aspx?s=windows.h + // http://libquicktime.sourcearchive.com/documentation/1.0.2plus-pdebian/iods_8c-source.html + $offset = 0; + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 3)); + $offset += 3; + $atom_structure['mp4_iod_tag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); + //$offset already adjusted by quicktime_read_mp4_descr_length() + $atom_structure['object_descriptor_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); + $offset += 2; + $atom_structure['od_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['scene_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['audio_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['video_profile_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['graphics_profile_level'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + + $atom_structure['num_iods_tracks'] = ($atom_structure['length'] - 7) / 6; // 6 bytes would only be right if all tracks use 1-byte length fields + for ($i = 0; $i < $atom_structure['num_iods_tracks']; $i++) { + $atom_structure['track'][$i]['ES_ID_IncTag'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 1)); + $offset += 1; + $atom_structure['track'][$i]['length'] = $this->quicktime_read_mp4_descr_length($atom_data, $offset); + //$offset already adjusted by quicktime_read_mp4_descr_length() + $atom_structure['track'][$i]['track_id'] = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); + $offset += 4; + } + + $atom_structure['audio_profile_name'] = $this->QuicktimeIODSaudioProfileName($atom_structure['audio_profile_id']); + $atom_structure['video_profile_name'] = $this->QuicktimeIODSvideoProfileName($atom_structure['video_profile_id']); + break; + + case 'ftyp': // FileTYPe (?) atom (for MP4 it seems) + $atom_structure['signature'] = substr($atom_data, 0, 4); + $atom_structure['unknown_1'] = getid3_lib::BigEndian2Int(substr($atom_data, 4, 4)); + $atom_structure['fourcc'] = substr($atom_data, 8, 4); + break; + + case 'mdat': // Media DATa atom + case 'free': // FREE space atom + case 'skip': // SKIP atom + case 'wide': // 64-bit expansion placeholder atom + // 'mdat' data is too big to deal with, contains no useful metadata + // 'free', 'skip' and 'wide' are just padding, contains no useful data at all + + // When writing QuickTime files, it is sometimes necessary to update an atom's size. + // It is impossible to update a 32-bit atom to a 64-bit atom since the 32-bit atom + // is only 8 bytes in size, and the 64-bit atom requires 16 bytes. Therefore, QuickTime + // puts an 8-byte placeholder atom before any atoms it may have to update the size of. + // In this way, if the atom needs to be converted from a 32-bit to a 64-bit atom, the + // placeholder atom can be overwritten to obtain the necessary 8 extra bytes. + // The placeholder atom has a type of kWideAtomPlaceholderType ( 'wide' ). + break; + + + case 'nsav': // NoSAVe atom + // http://developer.apple.com/technotes/tn/tn2038.html + $atom_structure['data'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + break; + + case 'ctyp': // Controller TYPe atom (seen on QTVR) + // http://homepages.slingshot.co.nz/~helmboy/quicktime/formats/qtm-layout.txt + // some controller names are: + // 0x00 + 'std' for linear movie + // 'none' for no controls + $atom_structure['ctyp'] = substr($atom_data, 0, 4); + $info['quicktime']['controller'] = $atom_structure['ctyp']; + switch ($atom_structure['ctyp']) { + case 'qtvr': + $info['video']['dataformat'] = 'quicktimevr'; + break; + } + break; + + case 'pano': // PANOrama track (seen on QTVR) + $atom_structure['pano'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 4)); + break; + + case 'hint': // HINT track + case 'hinf': // + case 'hinv': // + case 'hnti': // + $info['quicktime']['hinting'] = true; + break; + + case 'imgt': // IMaGe Track reference (kQTVRImageTrackRefType) (seen on QTVR) + for ($i = 0; $i < ($atom_structure['size'] - 8); $i += 4) { + $atom_structure['imgt'][] = getid3_lib::BigEndian2Int(substr($atom_data, $i, 4)); + } + break; + + + // Observed-but-not-handled atom types are just listed here to prevent warnings being generated + case 'FXTC': // Something to do with Adobe After Effects (?) + case 'PrmA': + case 'code': + case 'FIEL': // this is NOT "fiel" (Field Ordering) as describe here: http://developer.apple.com/documentation/QuickTime/QTFF/QTFFChap3/chapter_4_section_2.html + case 'tapt': // TrackApertureModeDimensionsAID - http://developer.apple.com/documentation/QuickTime/Reference/QT7-1_Update_Reference/Constants/Constants.html + // tapt seems to be used to compute the video size [http://www.getid3.org/phpBB3/viewtopic.php?t=838] + // * http://lists.apple.com/archives/quicktime-api/2006/Aug/msg00014.html + // * http://handbrake.fr/irclogs/handbrake-dev/handbrake-dev20080128_pg2.html + case 'ctts':// STCompositionOffsetAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html + case 'cslg':// STCompositionShiftLeastGreatestAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html + case 'sdtp':// STSampleDependencyAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html + case 'stps':// STPartialSyncSampleAID - http://developer.apple.com/documentation/QuickTime/Reference/QTRef_Constants/Reference/reference.html + //$atom_structure['data'] = $atom_data; + break; + + case '©xyz': // GPS latitude+longitude+altitude + $atom_structure['data'] = $atom_data; + if (preg_match('#([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)([\\+\\-][0-9\\.]+)?/$#i', $atom_data, $matches)) { + @list($all, $latitude, $longitude, $altitude) = $matches; + $info['quicktime']['comments']['gps_latitude'][] = floatval($latitude); + $info['quicktime']['comments']['gps_longitude'][] = floatval($longitude); + if (!empty($altitude)) { + $info['quicktime']['comments']['gps_altitude'][] = floatval($altitude); + } + } else { + $info['warning'][] = 'QuickTime atom "©xyz" data does not match expected data pattern at offset '.$baseoffset.'. Please report as getID3() bug.'; + } + break; + + case 'NCDT': + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html + // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 4, $atomHierarchy, $ParseAllPossibleAtoms); + break; + case 'NCTH': // Nikon Camera THumbnail image + case 'NCVW': // Nikon Camera preVieW image + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html + if (preg_match('/^\xFF\xD8\xFF/', $atom_data)) { + $atom_structure['data'] = $atom_data; + $atom_structure['image_mime'] = 'image/jpeg'; + $atom_structure['description'] = (($atomname == 'NCTH') ? 'Nikon Camera Thumbnail Image' : (($atomname == 'NCVW') ? 'Nikon Camera Preview Image' : 'Nikon preview image')); + $info['quicktime']['comments']['picture'][] = array('image_mime'=>$atom_structure['image_mime'], 'data'=>$atom_data, 'description'=>$atom_structure['description']); + } + break; + case 'NCHD': // MakerNoteVersion + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html + $atom_structure['data'] = $atom_data; + break; + case 'NCTG': // NikonTags + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG + $atom_structure['data'] = $this->QuicktimeParseNikonNCTG($atom_data); + break; + case 'NCDB': // NikonTags + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html + $atom_structure['data'] = $atom_data; + break; + + case "\x00\x00\x00\x00": + case 'meta': // METAdata atom + // some kind of metacontainer, may contain a big data dump such as: + // mdta keys  mdtacom.apple.quicktime.make (mdtacom.apple.quicktime.creationdate ,mdtacom.apple.quicktime.location.ISO6709 $mdtacom.apple.quicktime.software !mdtacom.apple.quicktime.model ilst   data DEApple 0  (data DE2011-05-11T17:54:04+0200 2  *data DE+52.4936+013.3897+040.247/   data DE4.3.1  data DEiPhone 4 + // http://www.geocities.com/xhelmboyx/quicktime/formats/qti-layout.txt + + $atom_structure['version'] = getid3_lib::BigEndian2Int(substr($atom_data, 0, 1)); + $atom_structure['flags_raw'] = getid3_lib::BigEndian2Int(substr($atom_data, 1, 3)); + $atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom(substr($atom_data, 4), $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + //$atom_structure['subatoms'] = $this->QuicktimeParseContainerAtom($atom_data, $baseoffset + 8, $atomHierarchy, $ParseAllPossibleAtoms); + break; + + case 'data': // metaDATA atom + // seems to be 2 bytes language code (ASCII), 2 bytes unknown (set to 0x10B5 in sample I have), remainder is useful data + $atom_structure['language'] = substr($atom_data, 4 + 0, 2); + $atom_structure['unknown'] = getid3_lib::BigEndian2Int(substr($atom_data, 4 + 2, 2)); + $atom_structure['data'] = substr($atom_data, 4 + 4); + break; + + default: + $info['warning'][] = 'Unknown QuickTime atom type: "'.$atomname.'" ('.trim(getid3_lib::PrintHexBytes($atomname)).') at offset '.$baseoffset; + $atom_structure['data'] = $atom_data; + break; + } + array_pop($atomHierarchy); + return $atom_structure; + } + + public function QuicktimeParseContainerAtom($atom_data, $baseoffset, &$atomHierarchy, $ParseAllPossibleAtoms) { +//echo 'QuicktimeParseContainerAtom('.substr($atom_data, 4, 4).') @ '.$baseoffset.'

    '; + $atom_structure = false; + $subatomoffset = 0; + $subatomcounter = 0; + if ((strlen($atom_data) == 4) && (getid3_lib::BigEndian2Int($atom_data) == 0x00000000)) { + return false; + } + while ($subatomoffset < strlen($atom_data)) { + $subatomsize = getid3_lib::BigEndian2Int(substr($atom_data, $subatomoffset + 0, 4)); + $subatomname = substr($atom_data, $subatomoffset + 4, 4); + $subatomdata = substr($atom_data, $subatomoffset + 8, $subatomsize - 8); + if ($subatomsize == 0) { + // Furthermore, for historical reasons the list of atoms is optionally + // terminated by a 32-bit integer set to 0. If you are writing a program + // to read user data atoms, you should allow for the terminating 0. + return $atom_structure; + } + + $atom_structure[$subatomcounter] = $this->QuicktimeParseAtom($subatomname, $subatomsize, $subatomdata, $baseoffset + $subatomoffset, $atomHierarchy, $ParseAllPossibleAtoms); + + $subatomoffset += $subatomsize; + $subatomcounter++; + } + return $atom_structure; + } + + + public function quicktime_read_mp4_descr_length($data, &$offset) { + // http://libquicktime.sourcearchive.com/documentation/2:1.0.2plus-pdebian-2build1/esds_8c-source.html + $num_bytes = 0; + $length = 0; + do { + $b = ord(substr($data, $offset++, 1)); + $length = ($length << 7) | ($b & 0x7F); + } while (($b & 0x80) && ($num_bytes++ < 4)); + return $length; + } + + + public function QuicktimeLanguageLookup($languageid) { + // http://developer.apple.com/library/mac/#documentation/QuickTime/QTFF/QTFFChap4/qtff4.html#//apple_ref/doc/uid/TP40000939-CH206-34353 + static $QuicktimeLanguageLookup = array(); + if (empty($QuicktimeLanguageLookup)) { + $QuicktimeLanguageLookup[0] = 'English'; + $QuicktimeLanguageLookup[1] = 'French'; + $QuicktimeLanguageLookup[2] = 'German'; + $QuicktimeLanguageLookup[3] = 'Italian'; + $QuicktimeLanguageLookup[4] = 'Dutch'; + $QuicktimeLanguageLookup[5] = 'Swedish'; + $QuicktimeLanguageLookup[6] = 'Spanish'; + $QuicktimeLanguageLookup[7] = 'Danish'; + $QuicktimeLanguageLookup[8] = 'Portuguese'; + $QuicktimeLanguageLookup[9] = 'Norwegian'; + $QuicktimeLanguageLookup[10] = 'Hebrew'; + $QuicktimeLanguageLookup[11] = 'Japanese'; + $QuicktimeLanguageLookup[12] = 'Arabic'; + $QuicktimeLanguageLookup[13] = 'Finnish'; + $QuicktimeLanguageLookup[14] = 'Greek'; + $QuicktimeLanguageLookup[15] = 'Icelandic'; + $QuicktimeLanguageLookup[16] = 'Maltese'; + $QuicktimeLanguageLookup[17] = 'Turkish'; + $QuicktimeLanguageLookup[18] = 'Croatian'; + $QuicktimeLanguageLookup[19] = 'Chinese (Traditional)'; + $QuicktimeLanguageLookup[20] = 'Urdu'; + $QuicktimeLanguageLookup[21] = 'Hindi'; + $QuicktimeLanguageLookup[22] = 'Thai'; + $QuicktimeLanguageLookup[23] = 'Korean'; + $QuicktimeLanguageLookup[24] = 'Lithuanian'; + $QuicktimeLanguageLookup[25] = 'Polish'; + $QuicktimeLanguageLookup[26] = 'Hungarian'; + $QuicktimeLanguageLookup[27] = 'Estonian'; + $QuicktimeLanguageLookup[28] = 'Lettish'; + $QuicktimeLanguageLookup[28] = 'Latvian'; + $QuicktimeLanguageLookup[29] = 'Saamisk'; + $QuicktimeLanguageLookup[29] = 'Lappish'; + $QuicktimeLanguageLookup[30] = 'Faeroese'; + $QuicktimeLanguageLookup[31] = 'Farsi'; + $QuicktimeLanguageLookup[31] = 'Persian'; + $QuicktimeLanguageLookup[32] = 'Russian'; + $QuicktimeLanguageLookup[33] = 'Chinese (Simplified)'; + $QuicktimeLanguageLookup[34] = 'Flemish'; + $QuicktimeLanguageLookup[35] = 'Irish'; + $QuicktimeLanguageLookup[36] = 'Albanian'; + $QuicktimeLanguageLookup[37] = 'Romanian'; + $QuicktimeLanguageLookup[38] = 'Czech'; + $QuicktimeLanguageLookup[39] = 'Slovak'; + $QuicktimeLanguageLookup[40] = 'Slovenian'; + $QuicktimeLanguageLookup[41] = 'Yiddish'; + $QuicktimeLanguageLookup[42] = 'Serbian'; + $QuicktimeLanguageLookup[43] = 'Macedonian'; + $QuicktimeLanguageLookup[44] = 'Bulgarian'; + $QuicktimeLanguageLookup[45] = 'Ukrainian'; + $QuicktimeLanguageLookup[46] = 'Byelorussian'; + $QuicktimeLanguageLookup[47] = 'Uzbek'; + $QuicktimeLanguageLookup[48] = 'Kazakh'; + $QuicktimeLanguageLookup[49] = 'Azerbaijani'; + $QuicktimeLanguageLookup[50] = 'AzerbaijanAr'; + $QuicktimeLanguageLookup[51] = 'Armenian'; + $QuicktimeLanguageLookup[52] = 'Georgian'; + $QuicktimeLanguageLookup[53] = 'Moldavian'; + $QuicktimeLanguageLookup[54] = 'Kirghiz'; + $QuicktimeLanguageLookup[55] = 'Tajiki'; + $QuicktimeLanguageLookup[56] = 'Turkmen'; + $QuicktimeLanguageLookup[57] = 'Mongolian'; + $QuicktimeLanguageLookup[58] = 'MongolianCyr'; + $QuicktimeLanguageLookup[59] = 'Pashto'; + $QuicktimeLanguageLookup[60] = 'Kurdish'; + $QuicktimeLanguageLookup[61] = 'Kashmiri'; + $QuicktimeLanguageLookup[62] = 'Sindhi'; + $QuicktimeLanguageLookup[63] = 'Tibetan'; + $QuicktimeLanguageLookup[64] = 'Nepali'; + $QuicktimeLanguageLookup[65] = 'Sanskrit'; + $QuicktimeLanguageLookup[66] = 'Marathi'; + $QuicktimeLanguageLookup[67] = 'Bengali'; + $QuicktimeLanguageLookup[68] = 'Assamese'; + $QuicktimeLanguageLookup[69] = 'Gujarati'; + $QuicktimeLanguageLookup[70] = 'Punjabi'; + $QuicktimeLanguageLookup[71] = 'Oriya'; + $QuicktimeLanguageLookup[72] = 'Malayalam'; + $QuicktimeLanguageLookup[73] = 'Kannada'; + $QuicktimeLanguageLookup[74] = 'Tamil'; + $QuicktimeLanguageLookup[75] = 'Telugu'; + $QuicktimeLanguageLookup[76] = 'Sinhalese'; + $QuicktimeLanguageLookup[77] = 'Burmese'; + $QuicktimeLanguageLookup[78] = 'Khmer'; + $QuicktimeLanguageLookup[79] = 'Lao'; + $QuicktimeLanguageLookup[80] = 'Vietnamese'; + $QuicktimeLanguageLookup[81] = 'Indonesian'; + $QuicktimeLanguageLookup[82] = 'Tagalog'; + $QuicktimeLanguageLookup[83] = 'MalayRoman'; + $QuicktimeLanguageLookup[84] = 'MalayArabic'; + $QuicktimeLanguageLookup[85] = 'Amharic'; + $QuicktimeLanguageLookup[86] = 'Tigrinya'; + $QuicktimeLanguageLookup[87] = 'Galla'; + $QuicktimeLanguageLookup[87] = 'Oromo'; + $QuicktimeLanguageLookup[88] = 'Somali'; + $QuicktimeLanguageLookup[89] = 'Swahili'; + $QuicktimeLanguageLookup[90] = 'Ruanda'; + $QuicktimeLanguageLookup[91] = 'Rundi'; + $QuicktimeLanguageLookup[92] = 'Chewa'; + $QuicktimeLanguageLookup[93] = 'Malagasy'; + $QuicktimeLanguageLookup[94] = 'Esperanto'; + $QuicktimeLanguageLookup[128] = 'Welsh'; + $QuicktimeLanguageLookup[129] = 'Basque'; + $QuicktimeLanguageLookup[130] = 'Catalan'; + $QuicktimeLanguageLookup[131] = 'Latin'; + $QuicktimeLanguageLookup[132] = 'Quechua'; + $QuicktimeLanguageLookup[133] = 'Guarani'; + $QuicktimeLanguageLookup[134] = 'Aymara'; + $QuicktimeLanguageLookup[135] = 'Tatar'; + $QuicktimeLanguageLookup[136] = 'Uighur'; + $QuicktimeLanguageLookup[137] = 'Dzongkha'; + $QuicktimeLanguageLookup[138] = 'JavaneseRom'; + $QuicktimeLanguageLookup[32767] = 'Unspecified'; + } + if (($languageid > 138) && ($languageid < 32767)) { + /* + ISO Language Codes - http://www.loc.gov/standards/iso639-2/php/code_list.php + Because the language codes specified by ISO 639-2/T are three characters long, they must be packed to fit into a 16-bit field. + The packing algorithm must map each of the three characters, which are always lowercase, into a 5-bit integer and then concatenate + these integers into the least significant 15 bits of a 16-bit integer, leaving the 16-bit integer's most significant bit set to zero. + + One algorithm for performing this packing is to treat each ISO character as a 16-bit integer. Subtract 0x60 from the first character + and multiply by 2^10 (0x400), subtract 0x60 from the second character and multiply by 2^5 (0x20), subtract 0x60 from the third character, + and add the three 16-bit values. This will result in a single 16-bit value with the three codes correctly packed into the 15 least + significant bits and the most significant bit set to zero. + */ + $iso_language_id = ''; + $iso_language_id .= chr((($languageid & 0x7C00) >> 10) + 0x60); + $iso_language_id .= chr((($languageid & 0x03E0) >> 5) + 0x60); + $iso_language_id .= chr((($languageid & 0x001F) >> 0) + 0x60); + $QuicktimeLanguageLookup[$languageid] = getid3_id3v2::LanguageLookup($iso_language_id); + } + return (isset($QuicktimeLanguageLookup[$languageid]) ? $QuicktimeLanguageLookup[$languageid] : 'invalid'); + } + + public function QuicktimeVideoCodecLookup($codecid) { + static $QuicktimeVideoCodecLookup = array(); + if (empty($QuicktimeVideoCodecLookup)) { + $QuicktimeVideoCodecLookup['.SGI'] = 'SGI'; + $QuicktimeVideoCodecLookup['3IV1'] = '3ivx MPEG-4 v1'; + $QuicktimeVideoCodecLookup['3IV2'] = '3ivx MPEG-4 v2'; + $QuicktimeVideoCodecLookup['3IVX'] = '3ivx MPEG-4'; + $QuicktimeVideoCodecLookup['8BPS'] = 'Planar RGB'; + $QuicktimeVideoCodecLookup['avc1'] = 'H.264/MPEG-4 AVC'; + $QuicktimeVideoCodecLookup['avr '] = 'AVR-JPEG'; + $QuicktimeVideoCodecLookup['b16g'] = '16Gray'; + $QuicktimeVideoCodecLookup['b32a'] = '32AlphaGray'; + $QuicktimeVideoCodecLookup['b48r'] = '48RGB'; + $QuicktimeVideoCodecLookup['b64a'] = '64ARGB'; + $QuicktimeVideoCodecLookup['base'] = 'Base'; + $QuicktimeVideoCodecLookup['clou'] = 'Cloud'; + $QuicktimeVideoCodecLookup['cmyk'] = 'CMYK'; + $QuicktimeVideoCodecLookup['cvid'] = 'Cinepak'; + $QuicktimeVideoCodecLookup['dmb1'] = 'OpenDML JPEG'; + $QuicktimeVideoCodecLookup['dvc '] = 'DVC-NTSC'; + $QuicktimeVideoCodecLookup['dvcp'] = 'DVC-PAL'; + $QuicktimeVideoCodecLookup['dvpn'] = 'DVCPro-NTSC'; + $QuicktimeVideoCodecLookup['dvpp'] = 'DVCPro-PAL'; + $QuicktimeVideoCodecLookup['fire'] = 'Fire'; + $QuicktimeVideoCodecLookup['flic'] = 'FLC'; + $QuicktimeVideoCodecLookup['gif '] = 'GIF'; + $QuicktimeVideoCodecLookup['h261'] = 'H261'; + $QuicktimeVideoCodecLookup['h263'] = 'H263'; + $QuicktimeVideoCodecLookup['IV41'] = 'Indeo4'; + $QuicktimeVideoCodecLookup['jpeg'] = 'JPEG'; + $QuicktimeVideoCodecLookup['kpcd'] = 'PhotoCD'; + $QuicktimeVideoCodecLookup['mjpa'] = 'Motion JPEG-A'; + $QuicktimeVideoCodecLookup['mjpb'] = 'Motion JPEG-B'; + $QuicktimeVideoCodecLookup['msvc'] = 'Microsoft Video1'; + $QuicktimeVideoCodecLookup['myuv'] = 'MPEG YUV420'; + $QuicktimeVideoCodecLookup['path'] = 'Vector'; + $QuicktimeVideoCodecLookup['png '] = 'PNG'; + $QuicktimeVideoCodecLookup['PNTG'] = 'MacPaint'; + $QuicktimeVideoCodecLookup['qdgx'] = 'QuickDrawGX'; + $QuicktimeVideoCodecLookup['qdrw'] = 'QuickDraw'; + $QuicktimeVideoCodecLookup['raw '] = 'RAW'; + $QuicktimeVideoCodecLookup['ripl'] = 'WaterRipple'; + $QuicktimeVideoCodecLookup['rpza'] = 'Video'; + $QuicktimeVideoCodecLookup['smc '] = 'Graphics'; + $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 1'; + $QuicktimeVideoCodecLookup['SVQ1'] = 'Sorenson Video 3'; + $QuicktimeVideoCodecLookup['syv9'] = 'Sorenson YUV9'; + $QuicktimeVideoCodecLookup['tga '] = 'Targa'; + $QuicktimeVideoCodecLookup['tiff'] = 'TIFF'; + $QuicktimeVideoCodecLookup['WRAW'] = 'Windows RAW'; + $QuicktimeVideoCodecLookup['WRLE'] = 'BMP'; + $QuicktimeVideoCodecLookup['y420'] = 'YUV420'; + $QuicktimeVideoCodecLookup['yuv2'] = 'ComponentVideo'; + $QuicktimeVideoCodecLookup['yuvs'] = 'ComponentVideoUnsigned'; + $QuicktimeVideoCodecLookup['yuvu'] = 'ComponentVideoSigned'; + } + return (isset($QuicktimeVideoCodecLookup[$codecid]) ? $QuicktimeVideoCodecLookup[$codecid] : ''); + } + + public function QuicktimeAudioCodecLookup($codecid) { + static $QuicktimeAudioCodecLookup = array(); + if (empty($QuicktimeAudioCodecLookup)) { + $QuicktimeAudioCodecLookup['.mp3'] = 'Fraunhofer MPEG Layer-III alias'; + $QuicktimeAudioCodecLookup['aac '] = 'ISO/IEC 14496-3 AAC'; + $QuicktimeAudioCodecLookup['agsm'] = 'Apple GSM 10:1'; + $QuicktimeAudioCodecLookup['alac'] = 'Apple Lossless Audio Codec'; + $QuicktimeAudioCodecLookup['alaw'] = 'A-law 2:1'; + $QuicktimeAudioCodecLookup['conv'] = 'Sample Format'; + $QuicktimeAudioCodecLookup['dvca'] = 'DV'; + $QuicktimeAudioCodecLookup['dvi '] = 'DV 4:1'; + $QuicktimeAudioCodecLookup['eqal'] = 'Frequency Equalizer'; + $QuicktimeAudioCodecLookup['fl32'] = '32-bit Floating Point'; + $QuicktimeAudioCodecLookup['fl64'] = '64-bit Floating Point'; + $QuicktimeAudioCodecLookup['ima4'] = 'Interactive Multimedia Association 4:1'; + $QuicktimeAudioCodecLookup['in24'] = '24-bit Integer'; + $QuicktimeAudioCodecLookup['in32'] = '32-bit Integer'; + $QuicktimeAudioCodecLookup['lpc '] = 'LPC 23:1'; + $QuicktimeAudioCodecLookup['MAC3'] = 'Macintosh Audio Compression/Expansion (MACE) 3:1'; + $QuicktimeAudioCodecLookup['MAC6'] = 'Macintosh Audio Compression/Expansion (MACE) 6:1'; + $QuicktimeAudioCodecLookup['mixb'] = '8-bit Mixer'; + $QuicktimeAudioCodecLookup['mixw'] = '16-bit Mixer'; + $QuicktimeAudioCodecLookup['mp4a'] = 'ISO/IEC 14496-3 AAC'; + $QuicktimeAudioCodecLookup['MS'."\x00\x02"] = 'Microsoft ADPCM'; + $QuicktimeAudioCodecLookup['MS'."\x00\x11"] = 'DV IMA'; + $QuicktimeAudioCodecLookup['MS'."\x00\x55"] = 'Fraunhofer MPEG Layer III'; + $QuicktimeAudioCodecLookup['NONE'] = 'No Encoding'; + $QuicktimeAudioCodecLookup['Qclp'] = 'Qualcomm PureVoice'; + $QuicktimeAudioCodecLookup['QDM2'] = 'QDesign Music 2'; + $QuicktimeAudioCodecLookup['QDMC'] = 'QDesign Music 1'; + $QuicktimeAudioCodecLookup['ratb'] = '8-bit Rate'; + $QuicktimeAudioCodecLookup['ratw'] = '16-bit Rate'; + $QuicktimeAudioCodecLookup['raw '] = 'raw PCM'; + $QuicktimeAudioCodecLookup['sour'] = 'Sound Source'; + $QuicktimeAudioCodecLookup['sowt'] = 'signed/two\'s complement (Little Endian)'; + $QuicktimeAudioCodecLookup['str1'] = 'Iomega MPEG layer II'; + $QuicktimeAudioCodecLookup['str2'] = 'Iomega MPEG *layer II'; + $QuicktimeAudioCodecLookup['str3'] = 'Iomega MPEG **layer II'; + $QuicktimeAudioCodecLookup['str4'] = 'Iomega MPEG ***layer II'; + $QuicktimeAudioCodecLookup['twos'] = 'signed/two\'s complement (Big Endian)'; + $QuicktimeAudioCodecLookup['ulaw'] = 'mu-law 2:1'; + } + return (isset($QuicktimeAudioCodecLookup[$codecid]) ? $QuicktimeAudioCodecLookup[$codecid] : ''); + } + + public function QuicktimeDCOMLookup($compressionid) { + static $QuicktimeDCOMLookup = array(); + if (empty($QuicktimeDCOMLookup)) { + $QuicktimeDCOMLookup['zlib'] = 'ZLib Deflate'; + $QuicktimeDCOMLookup['adec'] = 'Apple Compression'; + } + return (isset($QuicktimeDCOMLookup[$compressionid]) ? $QuicktimeDCOMLookup[$compressionid] : ''); + } + + public function QuicktimeColorNameLookup($colordepthid) { + static $QuicktimeColorNameLookup = array(); + if (empty($QuicktimeColorNameLookup)) { + $QuicktimeColorNameLookup[1] = '2-color (monochrome)'; + $QuicktimeColorNameLookup[2] = '4-color'; + $QuicktimeColorNameLookup[4] = '16-color'; + $QuicktimeColorNameLookup[8] = '256-color'; + $QuicktimeColorNameLookup[16] = 'thousands (16-bit color)'; + $QuicktimeColorNameLookup[24] = 'millions (24-bit color)'; + $QuicktimeColorNameLookup[32] = 'millions+ (32-bit color)'; + $QuicktimeColorNameLookup[33] = 'black & white'; + $QuicktimeColorNameLookup[34] = '4-gray'; + $QuicktimeColorNameLookup[36] = '16-gray'; + $QuicktimeColorNameLookup[40] = '256-gray'; + } + return (isset($QuicktimeColorNameLookup[$colordepthid]) ? $QuicktimeColorNameLookup[$colordepthid] : 'invalid'); + } + + public function QuicktimeSTIKLookup($stik) { + static $QuicktimeSTIKLookup = array(); + if (empty($QuicktimeSTIKLookup)) { + $QuicktimeSTIKLookup[0] = 'Movie'; + $QuicktimeSTIKLookup[1] = 'Normal'; + $QuicktimeSTIKLookup[2] = 'Audiobook'; + $QuicktimeSTIKLookup[5] = 'Whacked Bookmark'; + $QuicktimeSTIKLookup[6] = 'Music Video'; + $QuicktimeSTIKLookup[9] = 'Short Film'; + $QuicktimeSTIKLookup[10] = 'TV Show'; + $QuicktimeSTIKLookup[11] = 'Booklet'; + $QuicktimeSTIKLookup[14] = 'Ringtone'; + $QuicktimeSTIKLookup[21] = 'Podcast'; + } + return (isset($QuicktimeSTIKLookup[$stik]) ? $QuicktimeSTIKLookup[$stik] : 'invalid'); + } + + public function QuicktimeIODSaudioProfileName($audio_profile_id) { + static $QuicktimeIODSaudioProfileNameLookup = array(); + if (empty($QuicktimeIODSaudioProfileNameLookup)) { + $QuicktimeIODSaudioProfileNameLookup = array( + 0x00 => 'ISO Reserved (0x00)', + 0x01 => 'Main Audio Profile @ Level 1', + 0x02 => 'Main Audio Profile @ Level 2', + 0x03 => 'Main Audio Profile @ Level 3', + 0x04 => 'Main Audio Profile @ Level 4', + 0x05 => 'Scalable Audio Profile @ Level 1', + 0x06 => 'Scalable Audio Profile @ Level 2', + 0x07 => 'Scalable Audio Profile @ Level 3', + 0x08 => 'Scalable Audio Profile @ Level 4', + 0x09 => 'Speech Audio Profile @ Level 1', + 0x0A => 'Speech Audio Profile @ Level 2', + 0x0B => 'Synthetic Audio Profile @ Level 1', + 0x0C => 'Synthetic Audio Profile @ Level 2', + 0x0D => 'Synthetic Audio Profile @ Level 3', + 0x0E => 'High Quality Audio Profile @ Level 1', + 0x0F => 'High Quality Audio Profile @ Level 2', + 0x10 => 'High Quality Audio Profile @ Level 3', + 0x11 => 'High Quality Audio Profile @ Level 4', + 0x12 => 'High Quality Audio Profile @ Level 5', + 0x13 => 'High Quality Audio Profile @ Level 6', + 0x14 => 'High Quality Audio Profile @ Level 7', + 0x15 => 'High Quality Audio Profile @ Level 8', + 0x16 => 'Low Delay Audio Profile @ Level 1', + 0x17 => 'Low Delay Audio Profile @ Level 2', + 0x18 => 'Low Delay Audio Profile @ Level 3', + 0x19 => 'Low Delay Audio Profile @ Level 4', + 0x1A => 'Low Delay Audio Profile @ Level 5', + 0x1B => 'Low Delay Audio Profile @ Level 6', + 0x1C => 'Low Delay Audio Profile @ Level 7', + 0x1D => 'Low Delay Audio Profile @ Level 8', + 0x1E => 'Natural Audio Profile @ Level 1', + 0x1F => 'Natural Audio Profile @ Level 2', + 0x20 => 'Natural Audio Profile @ Level 3', + 0x21 => 'Natural Audio Profile @ Level 4', + 0x22 => 'Mobile Audio Internetworking Profile @ Level 1', + 0x23 => 'Mobile Audio Internetworking Profile @ Level 2', + 0x24 => 'Mobile Audio Internetworking Profile @ Level 3', + 0x25 => 'Mobile Audio Internetworking Profile @ Level 4', + 0x26 => 'Mobile Audio Internetworking Profile @ Level 5', + 0x27 => 'Mobile Audio Internetworking Profile @ Level 6', + 0x28 => 'AAC Profile @ Level 1', + 0x29 => 'AAC Profile @ Level 2', + 0x2A => 'AAC Profile @ Level 4', + 0x2B => 'AAC Profile @ Level 5', + 0x2C => 'High Efficiency AAC Profile @ Level 2', + 0x2D => 'High Efficiency AAC Profile @ Level 3', + 0x2E => 'High Efficiency AAC Profile @ Level 4', + 0x2F => 'High Efficiency AAC Profile @ Level 5', + 0xFE => 'Not part of MPEG-4 audio profiles', + 0xFF => 'No audio capability required', + ); + } + return (isset($QuicktimeIODSaudioProfileNameLookup[$audio_profile_id]) ? $QuicktimeIODSaudioProfileNameLookup[$audio_profile_id] : 'ISO Reserved / User Private'); + } + + + public function QuicktimeIODSvideoProfileName($video_profile_id) { + static $QuicktimeIODSvideoProfileNameLookup = array(); + if (empty($QuicktimeIODSvideoProfileNameLookup)) { + $QuicktimeIODSvideoProfileNameLookup = array( + 0x00 => 'Reserved (0x00) Profile', + 0x01 => 'Simple Profile @ Level 1', + 0x02 => 'Simple Profile @ Level 2', + 0x03 => 'Simple Profile @ Level 3', + 0x08 => 'Simple Profile @ Level 0', + 0x10 => 'Simple Scalable Profile @ Level 0', + 0x11 => 'Simple Scalable Profile @ Level 1', + 0x12 => 'Simple Scalable Profile @ Level 2', + 0x15 => 'AVC/H264 Profile', + 0x21 => 'Core Profile @ Level 1', + 0x22 => 'Core Profile @ Level 2', + 0x32 => 'Main Profile @ Level 2', + 0x33 => 'Main Profile @ Level 3', + 0x34 => 'Main Profile @ Level 4', + 0x42 => 'N-bit Profile @ Level 2', + 0x51 => 'Scalable Texture Profile @ Level 1', + 0x61 => 'Simple Face Animation Profile @ Level 1', + 0x62 => 'Simple Face Animation Profile @ Level 2', + 0x63 => 'Simple FBA Profile @ Level 1', + 0x64 => 'Simple FBA Profile @ Level 2', + 0x71 => 'Basic Animated Texture Profile @ Level 1', + 0x72 => 'Basic Animated Texture Profile @ Level 2', + 0x81 => 'Hybrid Profile @ Level 1', + 0x82 => 'Hybrid Profile @ Level 2', + 0x91 => 'Advanced Real Time Simple Profile @ Level 1', + 0x92 => 'Advanced Real Time Simple Profile @ Level 2', + 0x93 => 'Advanced Real Time Simple Profile @ Level 3', + 0x94 => 'Advanced Real Time Simple Profile @ Level 4', + 0xA1 => 'Core Scalable Profile @ Level1', + 0xA2 => 'Core Scalable Profile @ Level2', + 0xA3 => 'Core Scalable Profile @ Level3', + 0xB1 => 'Advanced Coding Efficiency Profile @ Level 1', + 0xB2 => 'Advanced Coding Efficiency Profile @ Level 2', + 0xB3 => 'Advanced Coding Efficiency Profile @ Level 3', + 0xB4 => 'Advanced Coding Efficiency Profile @ Level 4', + 0xC1 => 'Advanced Core Profile @ Level 1', + 0xC2 => 'Advanced Core Profile @ Level 2', + 0xD1 => 'Advanced Scalable Texture @ Level1', + 0xD2 => 'Advanced Scalable Texture @ Level2', + 0xE1 => 'Simple Studio Profile @ Level 1', + 0xE2 => 'Simple Studio Profile @ Level 2', + 0xE3 => 'Simple Studio Profile @ Level 3', + 0xE4 => 'Simple Studio Profile @ Level 4', + 0xE5 => 'Core Studio Profile @ Level 1', + 0xE6 => 'Core Studio Profile @ Level 2', + 0xE7 => 'Core Studio Profile @ Level 3', + 0xE8 => 'Core Studio Profile @ Level 4', + 0xF0 => 'Advanced Simple Profile @ Level 0', + 0xF1 => 'Advanced Simple Profile @ Level 1', + 0xF2 => 'Advanced Simple Profile @ Level 2', + 0xF3 => 'Advanced Simple Profile @ Level 3', + 0xF4 => 'Advanced Simple Profile @ Level 4', + 0xF5 => 'Advanced Simple Profile @ Level 5', + 0xF7 => 'Advanced Simple Profile @ Level 3b', + 0xF8 => 'Fine Granularity Scalable Profile @ Level 0', + 0xF9 => 'Fine Granularity Scalable Profile @ Level 1', + 0xFA => 'Fine Granularity Scalable Profile @ Level 2', + 0xFB => 'Fine Granularity Scalable Profile @ Level 3', + 0xFC => 'Fine Granularity Scalable Profile @ Level 4', + 0xFD => 'Fine Granularity Scalable Profile @ Level 5', + 0xFE => 'Not part of MPEG-4 Visual profiles', + 0xFF => 'No visual capability required', + ); + } + return (isset($QuicktimeIODSvideoProfileNameLookup[$video_profile_id]) ? $QuicktimeIODSvideoProfileNameLookup[$video_profile_id] : 'ISO Reserved Profile'); + } + + + public function QuicktimeContentRatingLookup($rtng) { + static $QuicktimeContentRatingLookup = array(); + if (empty($QuicktimeContentRatingLookup)) { + $QuicktimeContentRatingLookup[0] = 'None'; + $QuicktimeContentRatingLookup[2] = 'Clean'; + $QuicktimeContentRatingLookup[4] = 'Explicit'; + } + return (isset($QuicktimeContentRatingLookup[$rtng]) ? $QuicktimeContentRatingLookup[$rtng] : 'invalid'); + } + + public function QuicktimeStoreAccountTypeLookup($akid) { + static $QuicktimeStoreAccountTypeLookup = array(); + if (empty($QuicktimeStoreAccountTypeLookup)) { + $QuicktimeStoreAccountTypeLookup[0] = 'iTunes'; + $QuicktimeStoreAccountTypeLookup[1] = 'AOL'; + } + return (isset($QuicktimeStoreAccountTypeLookup[$akid]) ? $QuicktimeStoreAccountTypeLookup[$akid] : 'invalid'); + } + + public function QuicktimeStoreFrontCodeLookup($sfid) { + static $QuicktimeStoreFrontCodeLookup = array(); + if (empty($QuicktimeStoreFrontCodeLookup)) { + $QuicktimeStoreFrontCodeLookup[143460] = 'Australia'; + $QuicktimeStoreFrontCodeLookup[143445] = 'Austria'; + $QuicktimeStoreFrontCodeLookup[143446] = 'Belgium'; + $QuicktimeStoreFrontCodeLookup[143455] = 'Canada'; + $QuicktimeStoreFrontCodeLookup[143458] = 'Denmark'; + $QuicktimeStoreFrontCodeLookup[143447] = 'Finland'; + $QuicktimeStoreFrontCodeLookup[143442] = 'France'; + $QuicktimeStoreFrontCodeLookup[143443] = 'Germany'; + $QuicktimeStoreFrontCodeLookup[143448] = 'Greece'; + $QuicktimeStoreFrontCodeLookup[143449] = 'Ireland'; + $QuicktimeStoreFrontCodeLookup[143450] = 'Italy'; + $QuicktimeStoreFrontCodeLookup[143462] = 'Japan'; + $QuicktimeStoreFrontCodeLookup[143451] = 'Luxembourg'; + $QuicktimeStoreFrontCodeLookup[143452] = 'Netherlands'; + $QuicktimeStoreFrontCodeLookup[143461] = 'New Zealand'; + $QuicktimeStoreFrontCodeLookup[143457] = 'Norway'; + $QuicktimeStoreFrontCodeLookup[143453] = 'Portugal'; + $QuicktimeStoreFrontCodeLookup[143454] = 'Spain'; + $QuicktimeStoreFrontCodeLookup[143456] = 'Sweden'; + $QuicktimeStoreFrontCodeLookup[143459] = 'Switzerland'; + $QuicktimeStoreFrontCodeLookup[143444] = 'United Kingdom'; + $QuicktimeStoreFrontCodeLookup[143441] = 'United States'; + } + return (isset($QuicktimeStoreFrontCodeLookup[$sfid]) ? $QuicktimeStoreFrontCodeLookup[$sfid] : 'invalid'); + } + + public function QuicktimeParseNikonNCTG($atom_data) { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#NCTG + // Nikon-specific QuickTime tags found in the NCDT atom of MOV videos from some Nikon cameras such as the Coolpix S8000 and D5100 + // Data is stored as records of: + // * 4 bytes record type + // * 2 bytes size of data field type: + // 0x0001 = flag (size field *= 1-byte) + // 0x0002 = char (size field *= 1-byte) + // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB + // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD + // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together + // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? + // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? + // * 2 bytes data size field + // * ? bytes data (string data may be null-padded; datestamp fields are in the format "2011:05:25 20:24:15") + // all integers are stored BigEndian + + $NCTGtagName = array( + 0x00000001 => 'Make', + 0x00000002 => 'Model', + 0x00000003 => 'Software', + 0x00000011 => 'CreateDate', + 0x00000012 => 'DateTimeOriginal', + 0x00000013 => 'FrameCount', + 0x00000016 => 'FrameRate', + 0x00000022 => 'FrameWidth', + 0x00000023 => 'FrameHeight', + 0x00000032 => 'AudioChannels', + 0x00000033 => 'AudioBitsPerSample', + 0x00000034 => 'AudioSampleRate', + 0x02000001 => 'MakerNoteVersion', + 0x02000005 => 'WhiteBalance', + 0x0200000b => 'WhiteBalanceFineTune', + 0x0200001e => 'ColorSpace', + 0x02000023 => 'PictureControlData', + 0x02000024 => 'WorldTime', + 0x02000032 => 'UnknownInfo', + 0x02000083 => 'LensType', + 0x02000084 => 'Lens', + ); + + $offset = 0; + $datalength = strlen($atom_data); + $parsed = array(); + while ($offset < $datalength) { +//echo getid3_lib::PrintHexBytes(substr($atom_data, $offset, 4)).'
    '; + $record_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 4)); $offset += 4; + $data_size_type = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; + $data_size = getid3_lib::BigEndian2Int(substr($atom_data, $offset, 2)); $offset += 2; + switch ($data_size_type) { + case 0x0001: // 0x0001 = flag (size field *= 1-byte) + $data = getid3_lib::BigEndian2Int(substr($atom_data, $offset, $data_size * 1)); + $offset += ($data_size * 1); + break; + case 0x0002: // 0x0002 = char (size field *= 1-byte) + $data = substr($atom_data, $offset, $data_size * 1); + $offset += ($data_size * 1); + $data = rtrim($data, "\x00"); + break; + case 0x0003: // 0x0003 = DWORD+ (size field *= 2-byte), values are stored CDAB + $data = ''; + for ($i = $data_size - 1; $i >= 0; $i--) { + $data .= substr($atom_data, $offset + ($i * 2), 2); + } + $data = getid3_lib::BigEndian2Int($data); + $offset += ($data_size * 2); + break; + case 0x0004: // 0x0004 = QWORD+ (size field *= 4-byte), values are stored EFGHABCD + $data = ''; + for ($i = $data_size - 1; $i >= 0; $i--) { + $data .= substr($atom_data, $offset + ($i * 4), 4); + } + $data = getid3_lib::BigEndian2Int($data); + $offset += ($data_size * 4); + break; + case 0x0005: // 0x0005 = float (size field *= 8-byte), values are stored aaaabbbb where value is aaaa/bbbb; possibly multiple sets of values appended together + $data = array(); + for ($i = 0; $i < $data_size; $i++) { + $numerator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 0, 4)); + $denomninator = getid3_lib::BigEndian2Int(substr($atom_data, $offset + ($i * 8) + 4, 4)); + if ($denomninator == 0) { + $data[$i] = false; + } else { + $data[$i] = (double) $numerator / $denomninator; + } + } + $offset += (8 * $data_size); + if (count($data) == 1) { + $data = $data[0]; + } + break; + case 0x0007: // 0x0007 = bytes (size field *= 1-byte), values are stored as ?????? + $data = substr($atom_data, $offset, $data_size * 1); + $offset += ($data_size * 1); + break; + case 0x0008: // 0x0008 = ????? (size field *= 2-byte), values are stored as ?????? + $data = substr($atom_data, $offset, $data_size * 2); + $offset += ($data_size * 2); + break; + default: +echo 'QuicktimeParseNikonNCTG()::unknown $data_size_type: '.$data_size_type.'
    '; + break 2; + } + + switch ($record_type) { + case 0x00000011: // CreateDate + case 0x00000012: // DateTimeOriginal + $data = strtotime($data); + break; + case 0x0200001e: // ColorSpace + switch ($data) { + case 1: + $data = 'sRGB'; + break; + case 2: + $data = 'Adobe RGB'; + break; + } + break; + case 0x02000023: // PictureControlData + $PictureControlAdjust = array(0=>'default', 1=>'quick', 2=>'full'); + $FilterEffect = array(0x80=>'off', 0x81=>'yellow', 0x82=>'orange', 0x83=>'red', 0x84=>'green', 0xff=>'n/a'); + $ToningEffect = array(0x80=>'b&w', 0x81=>'sepia', 0x82=>'cyanotype', 0x83=>'red', 0x84=>'yellow', 0x85=>'green', 0x86=>'blue-green', 0x87=>'blue', 0x88=>'purple-blue', 0x89=>'red-purple', 0xff=>'n/a'); + $data = array( + 'PictureControlVersion' => substr($data, 0, 4), + 'PictureControlName' => rtrim(substr($data, 4, 20), "\x00"), + 'PictureControlBase' => rtrim(substr($data, 24, 20), "\x00"), + //'?' => substr($data, 44, 4), + 'PictureControlAdjust' => $PictureControlAdjust[ord(substr($data, 48, 1))], + 'PictureControlQuickAdjust' => ord(substr($data, 49, 1)), + 'Sharpness' => ord(substr($data, 50, 1)), + 'Contrast' => ord(substr($data, 51, 1)), + 'Brightness' => ord(substr($data, 52, 1)), + 'Saturation' => ord(substr($data, 53, 1)), + 'HueAdjustment' => ord(substr($data, 54, 1)), + 'FilterEffect' => $FilterEffect[ord(substr($data, 55, 1))], + 'ToningEffect' => $ToningEffect[ord(substr($data, 56, 1))], + 'ToningSaturation' => ord(substr($data, 57, 1)), + ); + break; + case 0x02000024: // WorldTime + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/Nikon.html#WorldTime + // timezone is stored as offset from GMT in minutes + $timezone = getid3_lib::BigEndian2Int(substr($data, 0, 2)); + if ($timezone & 0x8000) { + $timezone = 0 - (0x10000 - $timezone); + } + $timezone /= 60; + + $dst = (bool) getid3_lib::BigEndian2Int(substr($data, 2, 1)); + switch (getid3_lib::BigEndian2Int(substr($data, 3, 1))) { + case 2: + $datedisplayformat = 'D/M/Y'; break; + case 1: + $datedisplayformat = 'M/D/Y'; break; + case 0: + default: + $datedisplayformat = 'Y/M/D'; break; + } + + $data = array('timezone'=>floatval($timezone), 'dst'=>$dst, 'display'=>$datedisplayformat); + break; + case 0x02000083: // LensType + $data = array( + //'_' => $data, + 'mf' => (bool) ($data & 0x01), + 'd' => (bool) ($data & 0x02), + 'g' => (bool) ($data & 0x04), + 'vr' => (bool) ($data & 0x08), + ); + break; + } + $tag_name = (isset($NCTGtagName[$record_type]) ? $NCTGtagName[$record_type] : '0x'.str_pad(dechex($record_type), 8, '0', STR_PAD_LEFT)); + $parsed[$tag_name] = $data; + } + return $parsed; + } + + + public function CopyToAppropriateCommentsSection($keyname, $data, $boxname='') { + static $handyatomtranslatorarray = array(); + if (empty($handyatomtranslatorarray)) { + $handyatomtranslatorarray['©cpy'] = 'copyright'; + $handyatomtranslatorarray['©day'] = 'creation_date'; // iTunes 4.0 + $handyatomtranslatorarray['©dir'] = 'director'; + $handyatomtranslatorarray['©ed1'] = 'edit1'; + $handyatomtranslatorarray['©ed2'] = 'edit2'; + $handyatomtranslatorarray['©ed3'] = 'edit3'; + $handyatomtranslatorarray['©ed4'] = 'edit4'; + $handyatomtranslatorarray['©ed5'] = 'edit5'; + $handyatomtranslatorarray['©ed6'] = 'edit6'; + $handyatomtranslatorarray['©ed7'] = 'edit7'; + $handyatomtranslatorarray['©ed8'] = 'edit8'; + $handyatomtranslatorarray['©ed9'] = 'edit9'; + $handyatomtranslatorarray['©fmt'] = 'format'; + $handyatomtranslatorarray['©inf'] = 'information'; + $handyatomtranslatorarray['©prd'] = 'producer'; + $handyatomtranslatorarray['©prf'] = 'performers'; + $handyatomtranslatorarray['©req'] = 'system_requirements'; + $handyatomtranslatorarray['©src'] = 'source_credit'; + $handyatomtranslatorarray['©wrt'] = 'writer'; + + // http://www.geocities.com/xhelmboyx/quicktime/formats/qtm-layout.txt + $handyatomtranslatorarray['©nam'] = 'title'; // iTunes 4.0 + $handyatomtranslatorarray['©cmt'] = 'comment'; // iTunes 4.0 + $handyatomtranslatorarray['©wrn'] = 'warning'; + $handyatomtranslatorarray['©hst'] = 'host_computer'; + $handyatomtranslatorarray['©mak'] = 'make'; + $handyatomtranslatorarray['©mod'] = 'model'; + $handyatomtranslatorarray['©PRD'] = 'product'; + $handyatomtranslatorarray['©swr'] = 'software'; + $handyatomtranslatorarray['©aut'] = 'author'; + $handyatomtranslatorarray['©ART'] = 'artist'; + $handyatomtranslatorarray['©trk'] = 'track'; + $handyatomtranslatorarray['©alb'] = 'album'; // iTunes 4.0 + $handyatomtranslatorarray['©com'] = 'comment'; + $handyatomtranslatorarray['©gen'] = 'genre'; // iTunes 4.0 + $handyatomtranslatorarray['©ope'] = 'composer'; + $handyatomtranslatorarray['©url'] = 'url'; + $handyatomtranslatorarray['©enc'] = 'encoder'; + + // http://atomicparsley.sourceforge.net/mpeg-4files.html + $handyatomtranslatorarray['©art'] = 'artist'; // iTunes 4.0 + $handyatomtranslatorarray['aART'] = 'album_artist'; + $handyatomtranslatorarray['trkn'] = 'track_number'; // iTunes 4.0 + $handyatomtranslatorarray['disk'] = 'disc_number'; // iTunes 4.0 + $handyatomtranslatorarray['gnre'] = 'genre'; // iTunes 4.0 + $handyatomtranslatorarray['©too'] = 'encoder'; // iTunes 4.0 + $handyatomtranslatorarray['tmpo'] = 'bpm'; // iTunes 4.0 + $handyatomtranslatorarray['cprt'] = 'copyright'; // iTunes 4.0? + $handyatomtranslatorarray['cpil'] = 'compilation'; // iTunes 4.0 + $handyatomtranslatorarray['covr'] = 'picture'; // iTunes 4.0 + $handyatomtranslatorarray['rtng'] = 'rating'; // iTunes 4.0 + $handyatomtranslatorarray['©grp'] = 'grouping'; // iTunes 4.2 + $handyatomtranslatorarray['stik'] = 'stik'; // iTunes 4.9 + $handyatomtranslatorarray['pcst'] = 'podcast'; // iTunes 4.9 + $handyatomtranslatorarray['catg'] = 'category'; // iTunes 4.9 + $handyatomtranslatorarray['keyw'] = 'keyword'; // iTunes 4.9 + $handyatomtranslatorarray['purl'] = 'podcast_url'; // iTunes 4.9 + $handyatomtranslatorarray['egid'] = 'episode_guid'; // iTunes 4.9 + $handyatomtranslatorarray['desc'] = 'description'; // iTunes 5.0 + $handyatomtranslatorarray['©lyr'] = 'lyrics'; // iTunes 5.0 + $handyatomtranslatorarray['tvnn'] = 'tv_network_name'; // iTunes 6.0 + $handyatomtranslatorarray['tvsh'] = 'tv_show_name'; // iTunes 6.0 + $handyatomtranslatorarray['tvsn'] = 'tv_season'; // iTunes 6.0 + $handyatomtranslatorarray['tves'] = 'tv_episode'; // iTunes 6.0 + $handyatomtranslatorarray['purd'] = 'purchase_date'; // iTunes 6.0.2 + $handyatomtranslatorarray['pgap'] = 'gapless_playback'; // iTunes 7.0 + + // http://www.geocities.com/xhelmboyx/quicktime/formats/mp4-layout.txt + + + + // boxnames: + /* + $handyatomtranslatorarray['iTunSMPB'] = 'iTunSMPB'; + $handyatomtranslatorarray['iTunNORM'] = 'iTunNORM'; + $handyatomtranslatorarray['Encoding Params'] = 'Encoding Params'; + $handyatomtranslatorarray['replaygain_track_gain'] = 'replaygain_track_gain'; + $handyatomtranslatorarray['replaygain_track_peak'] = 'replaygain_track_peak'; + $handyatomtranslatorarray['replaygain_track_minmax'] = 'replaygain_track_minmax'; + $handyatomtranslatorarray['MusicIP PUID'] = 'MusicIP PUID'; + $handyatomtranslatorarray['MusicBrainz Artist Id'] = 'MusicBrainz Artist Id'; + $handyatomtranslatorarray['MusicBrainz Album Id'] = 'MusicBrainz Album Id'; + $handyatomtranslatorarray['MusicBrainz Album Artist Id'] = 'MusicBrainz Album Artist Id'; + $handyatomtranslatorarray['MusicBrainz Track Id'] = 'MusicBrainz Track Id'; + $handyatomtranslatorarray['MusicBrainz Disc Id'] = 'MusicBrainz Disc Id'; + + // http://age.hobba.nl/audio/tag_frame_reference.html + $handyatomtranslatorarray['PLAY_COUNTER'] = 'play_counter'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355 + $handyatomtranslatorarray['MEDIATYPE'] = 'mediatype'; // Foobar2000 - http://www.getid3.org/phpBB3/viewtopic.php?t=1355 + */ + } + $info = &$this->getid3->info; + $comment_key = ''; + if ($boxname && ($boxname != $keyname)) { + $comment_key = (isset($handyatomtranslatorarray[$boxname]) ? $handyatomtranslatorarray[$boxname] : $boxname); + } elseif (isset($handyatomtranslatorarray[$keyname])) { + $comment_key = $handyatomtranslatorarray[$keyname]; + } + if ($comment_key) { + if ($comment_key == 'picture') { + if (!is_array($data)) { + $image_mime = ''; + if (preg_match('#^\x89\x50\x4E\x47\x0D\x0A\x1A\x0A#', $data)) { + $image_mime = 'image/png'; + } elseif (preg_match('#^\xFF\xD8\xFF#', $data)) { + $image_mime = 'image/jpeg'; + } elseif (preg_match('#^GIF#', $data)) { + $image_mime = 'image/gif'; + } elseif (preg_match('#^BM#', $data)) { + $image_mime = 'image/bmp'; + } + $data = array('data'=>$data, 'image_mime'=>$image_mime); + } + } + $info['quicktime']['comments'][$comment_key][] = $data; + } + return true; + } + + public function NoNullString($nullterminatedstring) { + // remove the single null terminator on null terminated strings + if (substr($nullterminatedstring, strlen($nullterminatedstring) - 1, 1) === "\x00") { + return substr($nullterminatedstring, 0, strlen($nullterminatedstring) - 1); + } + return $nullterminatedstring; + } + + public function Pascal2String($pascalstring) { + // Pascal strings have 1 unsigned byte at the beginning saying how many chars (1-255) are in the string + return substr($pascalstring, 1); + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.real.php b/app/libs/vendor/getid3/module.audio-video.real.php index a775fc60..0226ac49 100644 --- a/app/libs/vendor/getid3/module.audio-video.real.php +++ b/app/libs/vendor/getid3/module.audio-video.real.php @@ -1,527 +1,527 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.real.php // -// module for analyzing Real Audio/Video files // -// dependencies: module.audio-video.riff.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - -class getid3_real extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'real'; - $info['bitrate'] = 0; - $info['playtime_seconds'] = 0; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $ChunkCounter = 0; - while (ftell($this->getid3->fp) < $info['avdataend']) { - $ChunkData = fread($this->getid3->fp, 8); - $ChunkName = substr($ChunkData, 0, 4); - $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4)); - - if ($ChunkName == '.ra'."\xFD") { - $ChunkData .= fread($this->getid3->fp, $ChunkSize - 8); - if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $info['real']['old_ra_header'])) { - $info['audio']['dataformat'] = 'real'; - $info['audio']['lossless'] = false; - $info['audio']['sample_rate'] = $info['real']['old_ra_header']['sample_rate']; - $info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample']; - $info['audio']['channels'] = $info['real']['old_ra_header']['channels']; - - $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); - $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); - $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']); - - foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) { - if (strlen(trim($valuearray[0])) > 0) { - $info['real']['comments'][$key][] = trim($valuearray[0]); - } - } - return true; - } - $info['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org'; - unset($info['bitrate']); - unset($info['playtime_seconds']); - return false; - } - - // shortcut - $info['real']['chunks'][$ChunkCounter] = array(); - $thisfile_real_chunks_currentchunk = &$info['real']['chunks'][$ChunkCounter]; - - $thisfile_real_chunks_currentchunk['name'] = $ChunkName; - $thisfile_real_chunks_currentchunk['offset'] = ftell($this->getid3->fp) - 8; - $thisfile_real_chunks_currentchunk['length'] = $ChunkSize; - if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) { - $info['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file'; - return false; - } - - if ($ChunkSize > ($this->getid3->fread_buffer_size() + 8)) { - - $ChunkData .= fread($this->getid3->fp, $this->getid3->fread_buffer_size() - 8); - fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET); - - } elseif(($ChunkSize - 8) > 0) { - - $ChunkData .= fread($this->getid3->fp, $ChunkSize - 8); - - } - $offset = 8; - - switch ($ChunkName) { - - case '.RMF': // RealMedia File Header - $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - switch ($thisfile_real_chunks_currentchunk['object_version']) { - - case 0: - $thisfile_real_chunks_currentchunk['file_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - break; - - default: - //$info['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)'; - break; - - } - break; - - - case 'PROP': // Properties Header - $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { - $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['num_packets'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['index_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['data_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['num_streams'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $info['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000; - if ($thisfile_real_chunks_currentchunk['duration'] > 0) { - $info['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate']; - } - $thisfile_real_chunks_currentchunk['flags']['save_enabled'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001); - $thisfile_real_chunks_currentchunk['flags']['perfect_play'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002); - $thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004); - } - break; - - case 'MDPR': // Media Properties Header - $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { - $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['start_time'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['stream_name_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); - $offset += 1; - $thisfile_real_chunks_currentchunk['stream_name'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']); - $offset += $thisfile_real_chunks_currentchunk['stream_name_size']; - $thisfile_real_chunks_currentchunk['mime_type_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); - $offset += 1; - $thisfile_real_chunks_currentchunk['mime_type'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']); - $offset += $thisfile_real_chunks_currentchunk['mime_type_size']; - $thisfile_real_chunks_currentchunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']); - $offset += $thisfile_real_chunks_currentchunk['type_specific_len']; - - // shortcut - $thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data']; - - switch ($thisfile_real_chunks_currentchunk['mime_type']) { - case 'video/x-pn-realvideo': - case 'video/x-pn-multirate-realvideo': - // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html - - // shortcut - $thisfile_real_chunks_currentchunk['video_info'] = array(); - $thisfile_real_chunks_currentchunk_videoinfo = &$thisfile_real_chunks_currentchunk['video_info']; - - $thisfile_real_chunks_currentchunk_videoinfo['dwSize'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 0, 4)); - $thisfile_real_chunks_currentchunk_videoinfo['fourcc1'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 4, 4); - $thisfile_real_chunks_currentchunk_videoinfo['fourcc2'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 8, 4); - $thisfile_real_chunks_currentchunk_videoinfo['width'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2)); - $thisfile_real_chunks_currentchunk_videoinfo['height'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2)); - $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2)); - $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown3'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown4'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown5'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown6'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown7'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown8'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2)); - //$thisfile_real_chunks_currentchunk_videoinfo['unknown9'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2)); - - $thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::fourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']); - - $info['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width']; - $info['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height']; - $info['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second']; - $info['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec']; - $info['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample']; - break; - - case 'audio/x-pn-realaudio': - case 'audio/x-pn-multirate-realaudio': - $this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']); - - $info['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate']; - $info['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample']; - $info['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels']; - if (!empty($info['audio']['dataformat'])) { - foreach ($info['audio'] as $key => $value) { - if ($key != 'streams') { - $info['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value; - } - } - } - break; - - case 'logical-fileinfo': - // shortcut - $thisfile_real_chunks_currentchunk['logical_fileinfo'] = array(); - $thisfile_real_chunks_currentchunk_logicalfileinfo = &$thisfile_real_chunks_currentchunk['logical_fileinfo']; - - $thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0; - $thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); - $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; - - //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); - $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; - - $thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); - $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; - - //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); - $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; - - //$thisfile_real_chunks_currentchunk_logicalfileinfo['d'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1)); - - //$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); - //$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2)); - //$thisfile_real_chunks_currentchunk_logicalfileinfo['one'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); - //$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); - - break; - - } - - - if (empty($info['playtime_seconds'])) { - $info['playtime_seconds'] = max($info['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000); - } - if ($thisfile_real_chunks_currentchunk['duration'] > 0) { - switch ($thisfile_real_chunks_currentchunk['mime_type']) { - case 'audio/x-pn-realaudio': - case 'audio/x-pn-multirate-realaudio': - $info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; - $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $info['audio']['bitrate']); - $info['audio']['dataformat'] = 'real'; - $info['audio']['lossless'] = false; - break; - - case 'video/x-pn-realvideo': - case 'video/x-pn-multirate-realvideo': - $info['video']['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; - $info['video']['bitrate_mode'] = 'cbr'; - $info['video']['dataformat'] = 'real'; - $info['video']['lossless'] = false; - $info['video']['pixel_aspect_ratio'] = (float) 1; - break; - - case 'audio/x-ralf-mpeg4-generic': - $info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; - $info['audio']['codec'] = 'RealAudio Lossless'; - $info['audio']['dataformat'] = 'real'; - $info['audio']['lossless'] = true; - break; - } - $info['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0); - } - } - break; - - case 'CONT': // Content Description Header (text comments) - $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { - $thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']); - $offset += $thisfile_real_chunks_currentchunk['title_len']; - - $thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']); - $offset += $thisfile_real_chunks_currentchunk['artist_len']; - - $thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']); - $offset += $thisfile_real_chunks_currentchunk['copyright_len']; - - $thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']); - $offset += $thisfile_real_chunks_currentchunk['comment_len']; - - - $commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment'); - foreach ($commentkeystocopy as $key => $val) { - if ($thisfile_real_chunks_currentchunk[$key]) { - $info['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]); - } - } - - } - break; - - - case 'DATA': // Data Chunk Header - // do nothing - break; - - case 'INDX': // Index Section Header - $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { - $thisfile_real_chunks_currentchunk['num_indices'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); - $offset += 2; - $thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); - $offset += 4; - - if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) { - // last index chunk found, ignore rest of file - break 2; - } else { - // non-last index chunk, seek to next index chunk (skipping actual index data) - fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET); - } - } - break; - - default: - $info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']; - break; - } - $ChunkCounter++; - } - - if (!empty($info['audio']['streams'])) { - $info['audio']['bitrate'] = 0; - foreach ($info['audio']['streams'] as $key => $valuearray) { - $info['audio']['bitrate'] += $valuearray['bitrate']; - } - } - - return true; - } - - - public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) { - // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html - - $ParsedArray = array(); - $ParsedArray['magic'] = substr($OldRAheaderData, 0, 4); - if ($ParsedArray['magic'] != '.ra'."\xFD") { - return false; - } - $ParsedArray['version1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 4, 2)); - - if ($ParsedArray['version1'] < 3) { - - return false; - - } elseif ($ParsedArray['version1'] == 3) { - - $ParsedArray['fourcc1'] = '.ra3'; - $ParsedArray['bits_per_sample'] = 16; // hard-coded for old versions? - $ParsedArray['sample_rate'] = 8000; // hard-coded for old versions? - - $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); - $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 8, 2)); // always 1 (?) - //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2)); - //$ParsedArray['unknown2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2)); - //$ParsedArray['unknown3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2)); - $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); - $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); - $ParsedArray['comments_raw'] = substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator - - $commentoffset = 0; - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - - $commentoffset++; // final null terminator (?) - $commentoffset++; // fourcc length (?) should be 4 - $ParsedArray['fourcc'] = substr($OldRAheaderData, 23 + $commentoffset, 4); - - } elseif ($ParsedArray['version1'] <= 5) { - - //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); - $ParsedArray['fourcc1'] = substr($OldRAheaderData, 8, 4); - $ParsedArray['file_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4)); - $ParsedArray['version2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); - $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); - $ParsedArray['codec_flavor_id'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2)); - $ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4)); - $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4)); - $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4)); - //$ParsedArray['unknown5'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4)); - $ParsedArray['sub_packet_h'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2)); - $ParsedArray['frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2)); - $ParsedArray['sub_packet_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2)); - //$ParsedArray['unknown6'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2)); - - switch ($ParsedArray['version1']) { - - case 4: - $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2)); - //$ParsedArray['unknown8'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2)); - $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2)); - $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2)); - $ParsedArray['length_fourcc2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1)); - $ParsedArray['fourcc2'] = substr($OldRAheaderData, 57, 4); - $ParsedArray['length_fourcc3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1)); - $ParsedArray['fourcc3'] = substr($OldRAheaderData, 62, 4); - //$ParsedArray['unknown9'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1)); - //$ParsedArray['unknown10'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2)); - $ParsedArray['comments_raw'] = substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16); - - $commentoffset = 0; - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - - $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); - $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); - $commentoffset += $commentlength; - break; - - case 5: - $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4)); - $ParsedArray['sample_rate2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4)); - $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4)); - $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2)); - $ParsedArray['genr'] = substr($OldRAheaderData, 62, 4); - $ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4); - $ParsedArray['comments'] = array(); - break; - } - $ParsedArray['fourcc'] = $ParsedArray['fourcc3']; - - } - foreach ($ParsedArray['comments'] as $key => $value) { - if ($ParsedArray['comments'][$key][0] === false) { - $ParsedArray['comments'][$key][0] = ''; - } - } - - return true; - } - - public function RealAudioCodecFourCClookup($fourcc, $bitrate) { - static $RealAudioCodecFourCClookup = array(); - if (empty($RealAudioCodecFourCClookup)) { - // http://www.its.msstate.edu/net/real/reports/config/tags.stats - // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html - - $RealAudioCodecFourCClookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)'; - $RealAudioCodecFourCClookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)'; - $RealAudioCodecFourCClookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)'; - $RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)'; - $RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)'; - $RealAudioCodecFourCClookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)'; - $RealAudioCodecFourCClookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)'; - $RealAudioCodecFourCClookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)'; - $RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)'; - $RealAudioCodecFourCClookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)'; - $RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)'; - $RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)'; - $RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)'; - $RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)'; - $RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)'; - $RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)'; - $RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)'; - $RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)'; - $RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)'; - - $RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3'; - $RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4'; - $RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2'; - $RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8'; - } - $roundbitrate = intval(round($bitrate)); - if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) { - return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate]; - } elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) { - return $RealAudioCodecFourCClookup[$fourcc][0]; - } - return $fourcc; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.real.php // +// module for analyzing Real Audio/Video files // +// dependencies: module.audio-video.riff.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + +class getid3_real extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'real'; + $info['bitrate'] = 0; + $info['playtime_seconds'] = 0; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $ChunkCounter = 0; + while (ftell($this->getid3->fp) < $info['avdataend']) { + $ChunkData = fread($this->getid3->fp, 8); + $ChunkName = substr($ChunkData, 0, 4); + $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, 4, 4)); + + if ($ChunkName == '.ra'."\xFD") { + $ChunkData .= fread($this->getid3->fp, $ChunkSize - 8); + if ($this->ParseOldRAheader(substr($ChunkData, 0, 128), $info['real']['old_ra_header'])) { + $info['audio']['dataformat'] = 'real'; + $info['audio']['lossless'] = false; + $info['audio']['sample_rate'] = $info['real']['old_ra_header']['sample_rate']; + $info['audio']['bits_per_sample'] = $info['real']['old_ra_header']['bits_per_sample']; + $info['audio']['channels'] = $info['real']['old_ra_header']['channels']; + + $info['playtime_seconds'] = 60 * ($info['real']['old_ra_header']['audio_bytes'] / $info['real']['old_ra_header']['bytes_per_minute']); + $info['audio']['bitrate'] = 8 * ($info['real']['old_ra_header']['audio_bytes'] / $info['playtime_seconds']); + $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($info['real']['old_ra_header']['fourcc'], $info['audio']['bitrate']); + + foreach ($info['real']['old_ra_header']['comments'] as $key => $valuearray) { + if (strlen(trim($valuearray[0])) > 0) { + $info['real']['comments'][$key][] = trim($valuearray[0]); + } + } + return true; + } + $info['error'][] = 'There was a problem parsing this RealAudio file. Please submit it for analysis to info@getid3.org'; + unset($info['bitrate']); + unset($info['playtime_seconds']); + return false; + } + + // shortcut + $info['real']['chunks'][$ChunkCounter] = array(); + $thisfile_real_chunks_currentchunk = &$info['real']['chunks'][$ChunkCounter]; + + $thisfile_real_chunks_currentchunk['name'] = $ChunkName; + $thisfile_real_chunks_currentchunk['offset'] = ftell($this->getid3->fp) - 8; + $thisfile_real_chunks_currentchunk['length'] = $ChunkSize; + if (($thisfile_real_chunks_currentchunk['offset'] + $thisfile_real_chunks_currentchunk['length']) > $info['avdataend']) { + $info['warning'][] = 'Chunk "'.$thisfile_real_chunks_currentchunk['name'].'" at offset '.$thisfile_real_chunks_currentchunk['offset'].' claims to be '.$thisfile_real_chunks_currentchunk['length'].' bytes long, which is beyond end of file'; + return false; + } + + if ($ChunkSize > ($this->getid3->fread_buffer_size() + 8)) { + + $ChunkData .= fread($this->getid3->fp, $this->getid3->fread_buffer_size() - 8); + fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['offset'] + $ChunkSize, SEEK_SET); + + } elseif(($ChunkSize - 8) > 0) { + + $ChunkData .= fread($this->getid3->fp, $ChunkSize - 8); + + } + $offset = 8; + + switch ($ChunkName) { + + case '.RMF': // RealMedia File Header + $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + switch ($thisfile_real_chunks_currentchunk['object_version']) { + + case 0: + $thisfile_real_chunks_currentchunk['file_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['headers_count'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + break; + + default: + //$info['warning'][] = 'Expected .RMF-object_version to be "0", actual value is "'.$thisfile_real_chunks_currentchunk['object_version'].'" (should not be a problem)'; + break; + + } + break; + + + case 'PROP': // Properties Header + $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { + $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['num_packets'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['index_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['data_offset'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['num_streams'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['flags_raw'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $info['playtime_seconds'] = $thisfile_real_chunks_currentchunk['duration'] / 1000; + if ($thisfile_real_chunks_currentchunk['duration'] > 0) { + $info['bitrate'] += $thisfile_real_chunks_currentchunk['avg_bit_rate']; + } + $thisfile_real_chunks_currentchunk['flags']['save_enabled'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0001); + $thisfile_real_chunks_currentchunk['flags']['perfect_play'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0002); + $thisfile_real_chunks_currentchunk['flags']['live_broadcast'] = (bool) ($thisfile_real_chunks_currentchunk['flags_raw'] & 0x0004); + } + break; + + case 'MDPR': // Media Properties Header + $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { + $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['max_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['avg_bit_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['max_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['avg_packet_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['start_time'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['preroll'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['duration'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['stream_name_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); + $offset += 1; + $thisfile_real_chunks_currentchunk['stream_name'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['stream_name_size']); + $offset += $thisfile_real_chunks_currentchunk['stream_name_size']; + $thisfile_real_chunks_currentchunk['mime_type_size'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 1)); + $offset += 1; + $thisfile_real_chunks_currentchunk['mime_type'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['mime_type_size']); + $offset += $thisfile_real_chunks_currentchunk['mime_type_size']; + $thisfile_real_chunks_currentchunk['type_specific_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['type_specific_data'] = substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['type_specific_len']); + $offset += $thisfile_real_chunks_currentchunk['type_specific_len']; + + // shortcut + $thisfile_real_chunks_currentchunk_typespecificdata = &$thisfile_real_chunks_currentchunk['type_specific_data']; + + switch ($thisfile_real_chunks_currentchunk['mime_type']) { + case 'video/x-pn-realvideo': + case 'video/x-pn-multirate-realvideo': + // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html + + // shortcut + $thisfile_real_chunks_currentchunk['video_info'] = array(); + $thisfile_real_chunks_currentchunk_videoinfo = &$thisfile_real_chunks_currentchunk['video_info']; + + $thisfile_real_chunks_currentchunk_videoinfo['dwSize'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 0, 4)); + $thisfile_real_chunks_currentchunk_videoinfo['fourcc1'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 4, 4); + $thisfile_real_chunks_currentchunk_videoinfo['fourcc2'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 8, 4); + $thisfile_real_chunks_currentchunk_videoinfo['width'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 12, 2)); + $thisfile_real_chunks_currentchunk_videoinfo['height'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 14, 2)); + $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 16, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 18, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 20, 2)); + $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 22, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown3'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 24, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown4'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 26, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown5'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 28, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown6'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 30, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown7'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 32, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown8'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 34, 2)); + //$thisfile_real_chunks_currentchunk_videoinfo['unknown9'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 36, 2)); + + $thisfile_real_chunks_currentchunk_videoinfo['codec'] = getid3_riff::fourccLookup($thisfile_real_chunks_currentchunk_videoinfo['fourcc2']); + + $info['video']['resolution_x'] = $thisfile_real_chunks_currentchunk_videoinfo['width']; + $info['video']['resolution_y'] = $thisfile_real_chunks_currentchunk_videoinfo['height']; + $info['video']['frame_rate'] = (float) $thisfile_real_chunks_currentchunk_videoinfo['frames_per_second']; + $info['video']['codec'] = $thisfile_real_chunks_currentchunk_videoinfo['codec']; + $info['video']['bits_per_sample'] = $thisfile_real_chunks_currentchunk_videoinfo['bits_per_sample']; + break; + + case 'audio/x-pn-realaudio': + case 'audio/x-pn-multirate-realaudio': + $this->ParseOldRAheader($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk['parsed_audio_data']); + + $info['audio']['sample_rate'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['sample_rate']; + $info['audio']['bits_per_sample'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['bits_per_sample']; + $info['audio']['channels'] = $thisfile_real_chunks_currentchunk['parsed_audio_data']['channels']; + if (!empty($info['audio']['dataformat'])) { + foreach ($info['audio'] as $key => $value) { + if ($key != 'streams') { + $info['audio']['streams'][$thisfile_real_chunks_currentchunk['stream_number']][$key] = $value; + } + } + } + break; + + case 'logical-fileinfo': + // shortcut + $thisfile_real_chunks_currentchunk['logical_fileinfo'] = array(); + $thisfile_real_chunks_currentchunk_logicalfileinfo = &$thisfile_real_chunks_currentchunk['logical_fileinfo']; + + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset = 0; + $thisfile_real_chunks_currentchunk_logicalfileinfo['logical_fileinfo_length'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; + + //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown1'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; + + $thisfile_real_chunks_currentchunk_logicalfileinfo['num_tags'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; + + //$thisfile_real_chunks_currentchunk_logicalfileinfo['unknown2'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset += 4; + + //$thisfile_real_chunks_currentchunk_logicalfileinfo['d'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 1)); + + //$thisfile_real_chunks_currentchunk_logicalfileinfo['one_type'] = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 4)); + //$thisfile_real_chunks_currentchunk_logicalfileinfo_thislength = getid3_lib::BigEndian2Int(substr($thisfile_real_chunks_currentchunk_typespecificdata, 4 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, 2)); + //$thisfile_real_chunks_currentchunk_logicalfileinfo['one'] = substr($thisfile_real_chunks_currentchunk_typespecificdata, 6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_offset, $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); + //$thisfile_real_chunks_currentchunk_logicalfileinfo_offset += (6 + $thisfile_real_chunks_currentchunk_logicalfileinfo_thislength); + + break; + + } + + + if (empty($info['playtime_seconds'])) { + $info['playtime_seconds'] = max($info['playtime_seconds'], ($thisfile_real_chunks_currentchunk['duration'] + $thisfile_real_chunks_currentchunk['start_time']) / 1000); + } + if ($thisfile_real_chunks_currentchunk['duration'] > 0) { + switch ($thisfile_real_chunks_currentchunk['mime_type']) { + case 'audio/x-pn-realaudio': + case 'audio/x-pn-multirate-realaudio': + $info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; + $info['audio']['codec'] = $this->RealAudioCodecFourCClookup($thisfile_real_chunks_currentchunk['parsed_audio_data']['fourcc'], $info['audio']['bitrate']); + $info['audio']['dataformat'] = 'real'; + $info['audio']['lossless'] = false; + break; + + case 'video/x-pn-realvideo': + case 'video/x-pn-multirate-realvideo': + $info['video']['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; + $info['video']['bitrate_mode'] = 'cbr'; + $info['video']['dataformat'] = 'real'; + $info['video']['lossless'] = false; + $info['video']['pixel_aspect_ratio'] = (float) 1; + break; + + case 'audio/x-ralf-mpeg4-generic': + $info['audio']['bitrate'] = (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0) + $thisfile_real_chunks_currentchunk['avg_bit_rate']; + $info['audio']['codec'] = 'RealAudio Lossless'; + $info['audio']['dataformat'] = 'real'; + $info['audio']['lossless'] = true; + break; + } + $info['bitrate'] = (isset($info['video']['bitrate']) ? $info['video']['bitrate'] : 0) + (isset($info['audio']['bitrate']) ? $info['audio']['bitrate'] : 0); + } + } + break; + + case 'CONT': // Content Description Header (text comments) + $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { + $thisfile_real_chunks_currentchunk['title_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['title'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['title_len']); + $offset += $thisfile_real_chunks_currentchunk['title_len']; + + $thisfile_real_chunks_currentchunk['artist_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['artist'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['artist_len']); + $offset += $thisfile_real_chunks_currentchunk['artist_len']; + + $thisfile_real_chunks_currentchunk['copyright_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['copyright'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['copyright_len']); + $offset += $thisfile_real_chunks_currentchunk['copyright_len']; + + $thisfile_real_chunks_currentchunk['comment_len'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['comment'] = (string) substr($ChunkData, $offset, $thisfile_real_chunks_currentchunk['comment_len']); + $offset += $thisfile_real_chunks_currentchunk['comment_len']; + + + $commentkeystocopy = array('title'=>'title', 'artist'=>'artist', 'copyright'=>'copyright', 'comment'=>'comment'); + foreach ($commentkeystocopy as $key => $val) { + if ($thisfile_real_chunks_currentchunk[$key]) { + $info['real']['comments'][$val][] = trim($thisfile_real_chunks_currentchunk[$key]); + } + } + + } + break; + + + case 'DATA': // Data Chunk Header + // do nothing + break; + + case 'INDX': // Index Section Header + $thisfile_real_chunks_currentchunk['object_version'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + if ($thisfile_real_chunks_currentchunk['object_version'] == 0) { + $thisfile_real_chunks_currentchunk['num_indices'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + $thisfile_real_chunks_currentchunk['stream_number'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 2)); + $offset += 2; + $thisfile_real_chunks_currentchunk['next_index_header'] = getid3_lib::BigEndian2Int(substr($ChunkData, $offset, 4)); + $offset += 4; + + if ($thisfile_real_chunks_currentchunk['next_index_header'] == 0) { + // last index chunk found, ignore rest of file + break 2; + } else { + // non-last index chunk, seek to next index chunk (skipping actual index data) + fseek($this->getid3->fp, $thisfile_real_chunks_currentchunk['next_index_header'], SEEK_SET); + } + } + break; + + default: + $info['warning'][] = 'Unhandled RealMedia chunk "'.$ChunkName.'" at offset '.$thisfile_real_chunks_currentchunk['offset']; + break; + } + $ChunkCounter++; + } + + if (!empty($info['audio']['streams'])) { + $info['audio']['bitrate'] = 0; + foreach ($info['audio']['streams'] as $key => $valuearray) { + $info['audio']['bitrate'] += $valuearray['bitrate']; + } + } + + return true; + } + + + public function ParseOldRAheader($OldRAheaderData, &$ParsedArray) { + // http://www.freelists.org/archives/matroska-devel/07-2003/msg00010.html + + $ParsedArray = array(); + $ParsedArray['magic'] = substr($OldRAheaderData, 0, 4); + if ($ParsedArray['magic'] != '.ra'."\xFD") { + return false; + } + $ParsedArray['version1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 4, 2)); + + if ($ParsedArray['version1'] < 3) { + + return false; + + } elseif ($ParsedArray['version1'] == 3) { + + $ParsedArray['fourcc1'] = '.ra3'; + $ParsedArray['bits_per_sample'] = 16; // hard-coded for old versions? + $ParsedArray['sample_rate'] = 8000; // hard-coded for old versions? + + $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); + $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 8, 2)); // always 1 (?) + //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 10, 2)); + //$ParsedArray['unknown2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 2)); + //$ParsedArray['unknown3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 14, 2)); + $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); + $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); + $ParsedArray['comments_raw'] = substr($OldRAheaderData, 22, $ParsedArray['header_size'] - 22 + 1); // not including null terminator + + $commentoffset = 0; + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + + $commentoffset++; // final null terminator (?) + $commentoffset++; // fourcc length (?) should be 4 + $ParsedArray['fourcc'] = substr($OldRAheaderData, 23 + $commentoffset, 4); + + } elseif ($ParsedArray['version1'] <= 5) { + + //$ParsedArray['unknown1'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 6, 2)); + $ParsedArray['fourcc1'] = substr($OldRAheaderData, 8, 4); + $ParsedArray['file_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 12, 4)); + $ParsedArray['version2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 16, 2)); + $ParsedArray['header_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 18, 4)); + $ParsedArray['codec_flavor_id'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 22, 2)); + $ParsedArray['coded_frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 24, 4)); + $ParsedArray['audio_bytes'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 28, 4)); + $ParsedArray['bytes_per_minute'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 32, 4)); + //$ParsedArray['unknown5'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 36, 4)); + $ParsedArray['sub_packet_h'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 40, 2)); + $ParsedArray['frame_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 42, 2)); + $ParsedArray['sub_packet_size'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 44, 2)); + //$ParsedArray['unknown6'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 46, 2)); + + switch ($ParsedArray['version1']) { + + case 4: + $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 2)); + //$ParsedArray['unknown8'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 50, 2)); + $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 2)); + $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 54, 2)); + $ParsedArray['length_fourcc2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 1)); + $ParsedArray['fourcc2'] = substr($OldRAheaderData, 57, 4); + $ParsedArray['length_fourcc3'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 61, 1)); + $ParsedArray['fourcc3'] = substr($OldRAheaderData, 62, 4); + //$ParsedArray['unknown9'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 66, 1)); + //$ParsedArray['unknown10'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 67, 2)); + $ParsedArray['comments_raw'] = substr($OldRAheaderData, 69, $ParsedArray['header_size'] - 69 + 16); + + $commentoffset = 0; + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['title'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['artist'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + + $commentlength = getid3_lib::BigEndian2Int(substr($ParsedArray['comments_raw'], $commentoffset++, 1)); + $ParsedArray['comments']['copyright'][] = substr($ParsedArray['comments_raw'], $commentoffset, $commentlength); + $commentoffset += $commentlength; + break; + + case 5: + $ParsedArray['sample_rate'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 48, 4)); + $ParsedArray['sample_rate2'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 52, 4)); + $ParsedArray['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 56, 4)); + $ParsedArray['channels'] = getid3_lib::BigEndian2Int(substr($OldRAheaderData, 60, 2)); + $ParsedArray['genr'] = substr($OldRAheaderData, 62, 4); + $ParsedArray['fourcc3'] = substr($OldRAheaderData, 66, 4); + $ParsedArray['comments'] = array(); + break; + } + $ParsedArray['fourcc'] = $ParsedArray['fourcc3']; + + } + foreach ($ParsedArray['comments'] as $key => $value) { + if ($ParsedArray['comments'][$key][0] === false) { + $ParsedArray['comments'][$key][0] = ''; + } + } + + return true; + } + + public function RealAudioCodecFourCClookup($fourcc, $bitrate) { + static $RealAudioCodecFourCClookup = array(); + if (empty($RealAudioCodecFourCClookup)) { + // http://www.its.msstate.edu/net/real/reports/config/tags.stats + // http://www.freelists.org/archives/matroska-devel/06-2003/fullthread18.html + + $RealAudioCodecFourCClookup['14_4'][8000] = 'RealAudio v2 (14.4kbps)'; + $RealAudioCodecFourCClookup['14.4'][8000] = 'RealAudio v2 (14.4kbps)'; + $RealAudioCodecFourCClookup['lpcJ'][8000] = 'RealAudio v2 (14.4kbps)'; + $RealAudioCodecFourCClookup['28_8'][15200] = 'RealAudio v2 (28.8kbps)'; + $RealAudioCodecFourCClookup['28.8'][15200] = 'RealAudio v2 (28.8kbps)'; + $RealAudioCodecFourCClookup['sipr'][4933] = 'RealAudio v4 (5kbps Voice)'; + $RealAudioCodecFourCClookup['sipr'][6444] = 'RealAudio v4 (6.5kbps Voice)'; + $RealAudioCodecFourCClookup['sipr'][8444] = 'RealAudio v4 (8.5kbps Voice)'; + $RealAudioCodecFourCClookup['sipr'][16000] = 'RealAudio v4 (16kbps Wideband)'; + $RealAudioCodecFourCClookup['dnet'][8000] = 'RealAudio v3 (8kbps Music)'; + $RealAudioCodecFourCClookup['dnet'][16000] = 'RealAudio v3 (16kbps Music Low Response)'; + $RealAudioCodecFourCClookup['dnet'][15963] = 'RealAudio v3 (16kbps Music Mid/High Response)'; + $RealAudioCodecFourCClookup['dnet'][20000] = 'RealAudio v3 (20kbps Music Stereo)'; + $RealAudioCodecFourCClookup['dnet'][32000] = 'RealAudio v3 (32kbps Music Mono)'; + $RealAudioCodecFourCClookup['dnet'][31951] = 'RealAudio v3 (32kbps Music Stereo)'; + $RealAudioCodecFourCClookup['dnet'][39965] = 'RealAudio v3 (40kbps Music Mono)'; + $RealAudioCodecFourCClookup['dnet'][40000] = 'RealAudio v3 (40kbps Music Stereo)'; + $RealAudioCodecFourCClookup['dnet'][79947] = 'RealAudio v3 (80kbps Music Mono)'; + $RealAudioCodecFourCClookup['dnet'][80000] = 'RealAudio v3 (80kbps Music Stereo)'; + + $RealAudioCodecFourCClookup['dnet'][0] = 'RealAudio v3'; + $RealAudioCodecFourCClookup['sipr'][0] = 'RealAudio v4'; + $RealAudioCodecFourCClookup['cook'][0] = 'RealAudio G2'; + $RealAudioCodecFourCClookup['atrc'][0] = 'RealAudio 8'; + } + $roundbitrate = intval(round($bitrate)); + if (isset($RealAudioCodecFourCClookup[$fourcc][$roundbitrate])) { + return $RealAudioCodecFourCClookup[$fourcc][$roundbitrate]; + } elseif (isset($RealAudioCodecFourCClookup[$fourcc][0])) { + return $RealAudioCodecFourCClookup[$fourcc][0]; + } + return $fourcc; + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.riff.php b/app/libs/vendor/getid3/module.audio-video.riff.php index fbb94732..8f431009 100644 --- a/app/libs/vendor/getid3/module.audio-video.riff.php +++ b/app/libs/vendor/getid3/module.audio-video.riff.php @@ -1,2435 +1,2435 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.riff.php // -// module for analyzing RIFF files // -// multiple formats supported by this module: // -// Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX // -// dependencies: module.audio.mp3.php // -// module.audio.ac3.php // -// module.audio.dts.php // -// /// -///////////////////////////////////////////////////////////////// - -/** -* @todo Parse AC-3/DTS audio inside WAVE correctly -* @todo Rewrite RIFF parser totally -*/ - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true); - -class getid3_riff extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - // initialize these values to an empty array, otherwise they default to NULL - // and you can't append array values to a NULL value - $info['riff'] = array('raw'=>array()); - - // Shortcuts - $thisfile_riff = &$info['riff']; - $thisfile_riff_raw = &$thisfile_riff['raw']; - $thisfile_audio = &$info['audio']; - $thisfile_video = &$info['video']; - $thisfile_audio_dataformat = &$thisfile_audio['dataformat']; - $thisfile_riff_audio = &$thisfile_riff['audio']; - $thisfile_riff_video = &$thisfile_riff['video']; - - $Original['avdataoffset'] = $info['avdataoffset']; - $Original['avdataend'] = $info['avdataend']; - - $this->fseek($info['avdataoffset']); - $RIFFheader = $this->fread(12); - $offset = $this->ftell(); - $RIFFtype = substr($RIFFheader, 0, 4); - $RIFFsize = substr($RIFFheader, 4, 4); - $RIFFsubtype = substr($RIFFheader, 8, 4); - - switch ($RIFFtype) { - - case 'FORM': // AIFF, AIFC - $info['fileformat'] = 'aiff'; - $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); - $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); - break; - - case 'RIFF': // AVI, WAV, etc - case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com) - case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s - $info['fileformat'] = 'riff'; - $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); - if ($RIFFsubtype == 'RMP3') { - // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s - $RIFFsubtype = 'WAVE'; - } - $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); - if (($info['avdataend'] - $info['filesize']) == 1) { - // LiteWave appears to incorrectly *not* pad actual output file - // to nearest WORD boundary so may appear to be short by one - // byte, in which case - skip warning - $info['avdataend'] = $info['filesize']; - } - - $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset - while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) { - try { - $this->fseek($nextRIFFoffset); - } catch (getid3_exception $e) { - if ($e->getCode() == 10) { - //$this->warning('RIFF parser: '.$e->getMessage()); - $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong'); - $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present'); - break; - } else { - throw $e; - } - } - $nextRIFFheader = $this->fread(12); - if ($nextRIFFoffset == ($info['avdataend'] - 1)) { - if (substr($nextRIFFheader, 0, 1) == "\x00") { - // RIFF padded to WORD boundary, we're actually already at the end - break; - } - } - $nextRIFFheaderID = substr($nextRIFFheader, 0, 4); - $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4)); - $nextRIFFtype = substr($nextRIFFheader, 8, 4); - $chunkdata = array(); - $chunkdata['offset'] = $nextRIFFoffset + 8; - $chunkdata['size'] = $nextRIFFsize; - $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size']; - - switch ($nextRIFFheaderID) { - - case 'RIFF': - $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset); - - if (!isset($thisfile_riff[$nextRIFFtype])) { - $thisfile_riff[$nextRIFFtype] = array(); - } - $thisfile_riff[$nextRIFFtype][] = $chunkdata; - break; - - case 'JUNK': - // ignore - $thisfile_riff[$nextRIFFheaderID][] = $chunkdata; - break; - - case 'IDVX': - $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size'])); - break; - - default: - if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) { - $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12); - if (substr($DIVXTAG, -7) == 'DIVXTAG') { - // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file - $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway'); - $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG); - break 2; - } - } - $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file'); - break 2; - - } - - } - if ($RIFFsubtype == 'WAVE') { - $thisfile_riff_WAVE = &$thisfile_riff['WAVE']; - } - break; - - default: - $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead'); - unset($info['fileformat']); - return false; - } - - $streamindex = 0; - switch ($RIFFsubtype) { - case 'WAVE': - if (empty($thisfile_audio['bitrate_mode'])) { - $thisfile_audio['bitrate_mode'] = 'cbr'; - } - if (empty($thisfile_audio_dataformat)) { - $thisfile_audio_dataformat = 'wav'; - } - - if (isset($thisfile_riff_WAVE['data'][0]['offset'])) { - $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8; - $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size']; - } - if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) { - - $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']); - $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; - if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { - $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero'; - return false; - } - $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw']; - unset($thisfile_riff_audio[$streamindex]['raw']); - $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; - - $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); - if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { - $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec']; - } - $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; - - if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); - } - - $thisfile_audio['lossless'] = false; - if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { - switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { - - case 0x0001: // PCM - $thisfile_audio['lossless'] = true; - break; - - case 0x2000: // AC-3 - $thisfile_audio_dataformat = 'ac3'; - break; - - default: - // do nothing - break; - - } - } - $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag']; - $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; - $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless']; - $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat; - } - - if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) { - - // shortcuts - $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data']; - $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array()); - $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad']; - $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track']; - $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album']; - - $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4)); - $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2)); - $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2)); - - $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT); - $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT); - $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3)); - $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3)); - $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1)); - $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9)); - $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3)); - $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3)); - $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1)); - $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9)); - - $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude']; - if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) { - $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']); - $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']); - $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']); - } - if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) { - $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']); - $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']); - $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']); - } - } - - if (isset($thisfile_riff_WAVE['fact'][0]['data'])) { - $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4)); - - // This should be a good way of calculating exact playtime, - // but some sample files have had incorrect number of samples, - // so cannot use this method - - // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) { - // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec']; - // } - } - if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) { - $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8); - } - - if (isset($thisfile_riff_WAVE['bext'][0]['data'])) { - // shortcut - $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0]; - - $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256)); - $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32)); - $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32)); - $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); - $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8); - $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8)); - $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1)); - $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254); - $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601))); - if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) { - if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { - list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date; - list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time; - $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']); - } else { - $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid'; - } - } else { - $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid'; - } - $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; - $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title']; - } - - if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) { - // shortcut - $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0]; - - $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2)); - $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001); - if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) { - $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true; - $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004); - $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008); - - $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2)); - } - $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2)); - $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2)); - $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001); - $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002); - $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004); - } - - if (isset($thisfile_riff_WAVE['cart'][0]['data'])) { - // shortcut - $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0]; - - $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4); - $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64)); - $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64)); - $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64)); - $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64)); - $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64)); - $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64)); - $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64)); - $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10)); - $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8)); - $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10)); - $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8)); - $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64)); - $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64)); - $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64)); - $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true); - for ($i = 0; $i < 8; $i++) { - $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4); - $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4)); - } - $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024)); - $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772))); - - $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist']; - $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title']; - } - - if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) { - // SoundMiner metadata - - // shortcuts - $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0]; - $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data']; - $SNDM_startoffset = 0; - $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size']; - - while ($SNDM_startoffset < $SNDM_endoffset) { - $SNDM_thisTagOffset = 0; - $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4)); - $SNDM_thisTagOffset += 4; - $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4); - $SNDM_thisTagOffset += 4; - $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); - $SNDM_thisTagOffset += 2; - $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); - $SNDM_thisTagOffset += 2; - $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize); - $SNDM_thisTagOffset += $SNDM_thisTagDataSize; - - if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { - $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; - break; - } elseif ($SNDM_thisTagSize <= 0) { - $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; - break; - } - $SNDM_startoffset += $SNDM_thisTagSize; - - $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText; - if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) { - $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; - } else { - $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; - } - } - - $tagmapping = array( - 'tracktitle'=>'title', - 'category' =>'genre', - 'cdtitle' =>'album', - 'tracktitle'=>'title', - ); - foreach ($tagmapping as $fromkey => $tokey) { - if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) { - $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey]; - } - } - } - - if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) { - // requires functions simplexml_load_string and get_object_vars - if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) { - $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; - if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { - @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); - $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); - } - if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { - @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); - $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); - } - if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { - $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); - $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']; - $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); - $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); - $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60)); - $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate']; - $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); - $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f)); - } - unset($parsedXML); - } - } - - - - if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { - $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); - } - - if (!empty($info['wavpack'])) { - $thisfile_audio_dataformat = 'wavpack'; - $thisfile_audio['bitrate_mode'] = 'vbr'; - $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version']; - - // Reset to the way it was - RIFF parsing will have messed this up - $info['avdataend'] = $Original['avdataend']; - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - $this->fseek($info['avdataoffset'] - 44); - $RIFFdata = $this->fread(44); - $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; - $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; - - if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) { - $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize); - $this->fseek($info['avdataend']); - $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize); - } - - // move the data chunk after all other chunks (if any) - // so that the RIFF parser doesn't see EOF when trying - // to skip over the data chunk - $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); - $getid3_riff = new getid3_riff($this->getid3); - $getid3_riff->ParseRIFFdata($RIFFdata); - unset($getid3_riff); - } - - if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { - switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { - case 0x0001: // PCM - if (!empty($info['ac3'])) { - // Dolby Digital WAV files masquerade as PCM-WAV, but they're not - $thisfile_audio['wformattag'] = 0x2000; - $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); - $thisfile_audio['lossless'] = false; - $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; - $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate']; - } - if (!empty($info['dts'])) { - // Dolby DTS files masquerade as PCM-WAV, but they're not - $thisfile_audio['wformattag'] = 0x2001; - $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); - $thisfile_audio['lossless'] = false; - $thisfile_audio['bitrate'] = $info['dts']['bitrate']; - $thisfile_audio['sample_rate'] = $info['dts']['sample_rate']; - } - break; - case 0x08AE: // ClearJump LiteWave - $thisfile_audio['bitrate_mode'] = 'vbr'; - $thisfile_audio_dataformat = 'litewave'; - - //typedef struct tagSLwFormat { - // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags - // DWORD m_dwScale; // scale factor for lossy compression - // DWORD m_dwBlockSize; // number of samples in encoded blocks - // WORD m_wQuality; // alias for the scale factor - // WORD m_wMarkDistance; // distance between marks in bytes - // WORD m_wReserved; - // - // //following paramters are ignored if CF_FILESRC is not set - // DWORD m_dwOrgSize; // original file size in bytes - // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file - // DWORD m_dwRiffChunkSize; // riff chunk size in the original file - // - // PCMWAVEFORMAT m_OrgWf; // original wave format - // }SLwFormat, *PSLwFormat; - - // shortcut - $thisfile_riff['litewave']['raw'] = array(); - $riff_litewave = &$thisfile_riff['litewave']; - $riff_litewave_raw = &$riff_litewave['raw']; - - $flags = array( - 'compression_method' => 1, - 'compression_flags' => 1, - 'm_dwScale' => 4, - 'm_dwBlockSize' => 4, - 'm_wQuality' => 2, - 'm_wMarkDistance' => 2, - 'm_wReserved' => 2, - 'm_dwOrgSize' => 4, - 'm_bFactExists' => 2, - 'm_dwRiffChunkSize' => 4, - ); - $litewave_offset = 18; - foreach ($flags as $flag => $length) { - $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length)); - $litewave_offset += $length; - } - - //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20)); - $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality']; - - $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true; - $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true; - $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04); - - $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false); - $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor']; - break; - - default: - break; - } - } - if ($info['avdataend'] > $info['filesize']) { - switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { - case 'wavpack': // WavPack - case 'lpac': // LPAC - case 'ofr': // OptimFROG - case 'ofs': // OptimFROG DualStream - // lossless compressed audio formats that keep original RIFF headers - skip warning - break; - - case 'litewave': - if (($info['avdataend'] - $info['filesize']) == 1) { - // LiteWave appears to incorrectly *not* pad actual output file - // to nearest WORD boundary so may appear to be short by one - // byte, in which case - skip warning - } else { - // Short by more than one byte, throw warning - $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; - $info['avdataend'] = $info['filesize']; - } - break; - - default: - if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) { - // output file appears to be incorrectly *not* padded to nearest WORD boundary - // Output less severe warning - $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; - $info['avdataend'] = $info['filesize']; - } else { - // Short by more than one byte, throw warning - $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; - $info['avdataend'] = $info['filesize']; - } - break; - } - } - if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) { - if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { - $info['avdataend']--; - $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'; - } - } - if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { - unset($thisfile_audio['bits_per_sample']); - if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { - $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; - } - } - break; - - case 'AVI ': - $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably - $thisfile_video['dataformat'] = 'avi'; - $info['mime_type'] = 'video/avi'; - - if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) { - $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8; - if (isset($thisfile_riff['AVIX'])) { - $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size']; - } else { - $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size']; - } - if ($info['avdataend'] > $info['filesize']) { - $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)'; - $info['avdataend'] = $info['filesize']; - } - } - - if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) { - //$bIndexType = array( - // 0x00 => 'AVI_INDEX_OF_INDEXES', - // 0x01 => 'AVI_INDEX_OF_CHUNKS', - // 0x80 => 'AVI_INDEX_IS_DATA', - //); - //$bIndexSubtype = array( - // 0x01 => array( - // 0x01 => 'AVI_INDEX_2FIELD', - // ), - //); - foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) { - $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data']; - - $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2)); - $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1)); - $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1)); - $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4)); - $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4); - $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4)); - - //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']]; - //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']]; - - unset($ahsisd); - } - } - if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) { - $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data']; - - // shortcut - $thisfile_riff_raw['avih'] = array(); - $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih']; - - $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) - if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { - $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'; - return false; - } - - $flags = array( - 'dwMaxBytesPerSec', // max. transfer rate - 'dwPaddingGranularity', // pad to multiples of this size; normally 2K. - 'dwFlags', // the ever-present flags - 'dwTotalFrames', // # frames in file - 'dwInitialFrames', // - 'dwStreams', // - 'dwSuggestedBufferSize', // - 'dwWidth', // - 'dwHeight', // - 'dwScale', // - 'dwRate', // - 'dwStart', // - 'dwLength', // - ); - $avih_offset = 4; - foreach ($flags as $flag) { - $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4)); - $avih_offset += 4; - } - - $flags = array( - 'hasindex' => 0x00000010, - 'mustuseindex' => 0x00000020, - 'interleaved' => 0x00000100, - 'trustcktype' => 0x00000800, - 'capturedfile' => 0x00010000, - 'copyrighted' => 0x00020010, - ); - foreach ($flags as $flag => $value) { - $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value); - } - - // shortcut - $thisfile_riff_video[$streamindex] = array(); - $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; - - if ($thisfile_riff_raw_avih['dwWidth'] > 0) { - $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; - $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; - } - if ($thisfile_riff_raw_avih['dwHeight'] > 0) { - $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; - $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; - } - if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { - $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; - $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; - } - - $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3); - $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate']; - } - if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { - if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) { - for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) { - if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { - $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data']; - $strhfccType = substr($strhData, 0, 4); - - if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { - $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; - - // shortcut - $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex]; - - switch ($strhfccType) { - case 'auds': - $thisfile_audio['bitrate_mode'] = 'cbr'; - $thisfile_audio_dataformat = 'wav'; - if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) { - $streamindex = count($thisfile_riff_audio); - } - - $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData); - $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; - - // shortcut - $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; - $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex]; - - if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) { - unset($thisfile_audio_streams_currentstream['bits_per_sample']); - } - $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag']; - unset($thisfile_audio_streams_currentstream['raw']); - - // shortcut - $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw']; - - unset($thisfile_riff_audio[$streamindex]['raw']); - $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); - - $thisfile_audio['lossless'] = false; - switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) { - case 0x0001: // PCM - $thisfile_audio_dataformat = 'wav'; - $thisfile_audio['lossless'] = true; - break; - - case 0x0050: // MPEG Layer 2 or Layer 1 - $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2 - break; - - case 0x0055: // MPEG Layer 3 - $thisfile_audio_dataformat = 'mp3'; - break; - - case 0x00FF: // AAC - $thisfile_audio_dataformat = 'aac'; - break; - - case 0x0161: // Windows Media v7 / v8 / v9 - case 0x0162: // Windows Media Professional v9 - case 0x0163: // Windows Media Lossess v9 - $thisfile_audio_dataformat = 'wma'; - break; - - case 0x2000: // AC-3 - $thisfile_audio_dataformat = 'ac3'; - break; - - case 0x2001: // DTS - $thisfile_audio_dataformat = 'dts'; - break; - - default: - $thisfile_audio_dataformat = 'wav'; - break; - } - $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat; - $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless']; - $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode']; - break; - - - case 'iavs': - case 'vids': - // shortcut - $thisfile_riff_raw['strh'][$i] = array(); - $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i]; - - $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType; - $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4); - $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags - $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2)); - $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2)); - $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4)); - $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4)); - $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4)); - $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4)); - $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4)); - $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4)); - $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4)); - $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4)); - $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4)); - - $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']); - $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler']; - if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { - $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']); - $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; - } - $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; - $thisfile_video['pixel_aspect_ratio'] = (float) 1; - switch ($thisfile_riff_raw_strh_current['fccHandler']) { - case 'HFYU': // Huffman Lossless Codec - case 'IRAW': // Intel YUV Uncompressed - case 'YUY2': // Uncompressed YUV 4:2:2 - $thisfile_video['lossless'] = true; - break; - - default: - $thisfile_video['lossless'] = false; - break; - } - - switch ($strhfccType) { - case 'vids': - $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff')); - $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount']; - - if ($thisfile_riff_video_current['codec'] == 'DV') { - $thisfile_riff_video_current['dv_type'] = 2; - } - break; - - case 'iavs': - $thisfile_riff_video_current['dv_type'] = 1; - break; - } - break; - - default: - $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"'; - break; - - } - } - } - - if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { - - $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; - if (self::fourccLookup($thisfile_video['fourcc'])) { - $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']); - $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; - } - - switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) { - case 'HFYU': // Huffman Lossless Codec - case 'IRAW': // Intel YUV Uncompressed - case 'YUY2': // Uncompressed YUV 4:2:2 - $thisfile_video['lossless'] = true; - //$thisfile_video['bits_per_sample'] = 24; - break; - - default: - $thisfile_video['lossless'] = false; - //$thisfile_video['bits_per_sample'] = 24; - break; - } - - } - } - } - } - break; - - case 'CDDA': - $thisfile_audio['bitrate_mode'] = 'cbr'; - $thisfile_audio_dataformat = 'cda'; - $thisfile_audio['lossless'] = true; - unset($info['mime_type']); - - $info['avdataoffset'] = 44; - - if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) { - // shortcut - $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0]; - - $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2)); - $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2)); - $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4)); - $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4)); - $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4)); - $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4)); - $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4)); - - $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75; - $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75; - $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num']; - $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds']; - - // hardcoded data for CD-audio - $thisfile_audio['sample_rate'] = 44100; - $thisfile_audio['channels'] = 2; - $thisfile_audio['bits_per_sample'] = 16; - $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample']; - $thisfile_audio['bitrate_mode'] = 'cbr'; - } - break; - - - case 'AIFF': - case 'AIFC': - $thisfile_audio['bitrate_mode'] = 'cbr'; - $thisfile_audio_dataformat = 'aiff'; - $thisfile_audio['lossless'] = true; - $info['mime_type'] = 'audio/x-aiff'; - - if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) { - $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8; - $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size']; - if ($info['avdataend'] > $info['filesize']) { - if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) { - // structures rounded to 2-byte boundary, but dumb encoders - // forget to pad end of file to make this actually work - } else { - $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; - } - $info['avdataend'] = $info['filesize']; - } - } - - if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) { - - // shortcut - $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data']; - - $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true); - $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false); - $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true); - $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10)); - - if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) { - $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4); - $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false); - $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize); - switch ($thisfile_riff_audio['codec_name']) { - case 'NONE': - $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; - $thisfile_audio['lossless'] = true; - break; - - case '': - switch ($thisfile_riff_audio['codec_fourcc']) { - // http://developer.apple.com/qa/snd/snd07.html - case 'sowt': - $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM'; - $thisfile_audio['lossless'] = true; - break; - - case 'twos': - $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM'; - $thisfile_audio['lossless'] = true; - break; - - default: - break; - } - break; - - default: - $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name']; - $thisfile_audio['lossless'] = false; - break; - } - } - - $thisfile_audio['channels'] = $thisfile_riff_audio['channels']; - if ($thisfile_riff_audio['bits_per_sample'] > 0) { - $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample']; - } - $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate']; - if ($thisfile_audio['sample_rate'] == 0) { - $info['error'][] = 'Corrupted AIFF file: sample_rate == zero'; - return false; - } - $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate']; - } - - if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) { - $offset = 0; - $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); - $offset += 2; - for ($i = 0; $i < $CommentCount; $i++) { - $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false); - $offset += 4; - $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true); - $offset += 2; - $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); - $offset += 2; - $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength); - $offset += $CommentLength; - - $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']); - $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment']; - } - } - - $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); - foreach ($CommentsChunkNames as $key => $value) { - if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; - } - } -/* - if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) { - getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_id3v2 = new getid3_id3v2($getid3_temp); - $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; - if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) { - $info['id3v2'] = $getid3_temp->info['id3v2']; - } - unset($getid3_temp, $getid3_id3v2); - } -*/ - break; - - case '8SVX': - $thisfile_audio['bitrate_mode'] = 'cbr'; - $thisfile_audio_dataformat = '8svx'; - $thisfile_audio['bits_per_sample'] = 8; - $thisfile_audio['channels'] = 1; // overridden below, if need be - $info['mime_type'] = 'audio/x-aiff'; - - if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { - $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; - $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; - if ($info['avdataend'] > $info['filesize']) { - $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; - } - } - - if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) { - // shortcut - $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0]; - - $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4)); - $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4)); - $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4)); - $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2)); - $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1)); - $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1)); - $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4)); - - $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec']; - - switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) { - case 0: - $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; - $thisfile_audio['lossless'] = true; - $ActualBitsPerSample = 8; - break; - - case 1: - $thisfile_audio['codec'] = 'Fibonacci-delta encoding'; - $thisfile_audio['lossless'] = false; - $ActualBitsPerSample = 4; - break; - - default: - $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"'; - break; - } - } - - if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) { - $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4)); - switch ($ChannelsIndex) { - case 6: // Stereo - $thisfile_audio['channels'] = 2; - break; - - case 2: // Left channel only - case 4: // Right channel only - $thisfile_audio['channels'] = 1; - break; - - default: - $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"'; - break; - } - - } - - $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); - foreach ($CommentsChunkNames as $key => $value) { - if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { - $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; - } - } - - $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels']; - if (!empty($thisfile_audio['bitrate'])) { - $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8); - } - break; - - - case 'CDXA': - $info['mime_type'] = 'video/mpeg'; - if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) { - if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) { - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_mpeg = new getid3_mpeg($getid3_temp); - $getid3_mpeg->Analyze(); - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['video'] = $getid3_temp->info['video']; - $info['mpeg'] = $getid3_temp->info['mpeg']; - $info['warning'] = $getid3_temp->info['warning']; - } - unset($getid3_temp, $getid3_mpeg); - } - } - break; - - - default: - $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead'; - unset($info['fileformat']); - break; - } - - switch ($RIFFsubtype) { - case 'WAVE': - case 'AIFF': - case 'AIFC': - $ID3v2_key_good = 'id3 '; - $ID3v2_keys_bad = array('ID3 ', 'tag '); - foreach ($ID3v2_keys_bad as $ID3v2_key_bad) { - if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { - $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; - $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'; - } - } - - if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) { - getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_id3v2 = new getid3_id3v2($getid3_temp); - $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; - if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) { - $info['id3v2'] = $getid3_temp->info['id3v2']; - } - unset($getid3_temp, $getid3_id3v2); - } - break; - } - - if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) { - $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4)); - } - if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) { - self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']); - } - if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) { - self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']); - } - - if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) { - $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version']; - } - - if (!isset($info['playtime_seconds'])) { - $info['playtime_seconds'] = 0; - } - if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { - // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie - $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); - } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { - $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); - } - - if ($info['playtime_seconds'] > 0) { - if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { - - if (!isset($info['bitrate'])) { - $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); - } - - } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) { - - if (!isset($thisfile_audio['bitrate'])) { - $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); - } - - } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { - - if (!isset($thisfile_video['bitrate'])) { - $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); - } - - } - } - - - if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) { - - $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); - $thisfile_audio['bitrate'] = 0; - $thisfile_video['bitrate'] = $info['bitrate']; - foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) { - $thisfile_video['bitrate'] -= $audioinfoarray['bitrate']; - $thisfile_audio['bitrate'] += $audioinfoarray['bitrate']; - } - if ($thisfile_video['bitrate'] <= 0) { - unset($thisfile_video['bitrate']); - } - if ($thisfile_audio['bitrate'] <= 0) { - unset($thisfile_audio['bitrate']); - } - } - - if (isset($info['mpeg']['audio'])) { - $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer']; - $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate']; - $thisfile_audio['channels'] = $info['mpeg']['audio']['channels']; - $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate']; - $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); - if (!empty($info['mpeg']['audio']['codec'])) { - $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec']; - } - if (!empty($thisfile_audio['streams'])) { - foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) { - if ($streamdata['dataformat'] == $thisfile_audio_dataformat) { - $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate']; - $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels']; - $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; - $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; - $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec']; - } - } - } - $getid3_mp3 = new getid3_mp3($this->getid3); - $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions(); - unset($getid3_mp3); - } - - - if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) { - switch ($thisfile_audio_dataformat) { - case 'ac3': - // ignore bits_per_sample - break; - - default: - $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample']; - break; - } - } - - - if (empty($thisfile_riff_raw)) { - unset($thisfile_riff['raw']); - } - if (empty($thisfile_riff_audio)) { - unset($thisfile_riff['audio']); - } - if (empty($thisfile_riff_video)) { - unset($thisfile_riff['video']); - } - - return true; - } - - public function ParseRIFF($startoffset, $maxoffset) { - $info = &$this->getid3->info; - - $RIFFchunk = false; - $FoundAllChunksWeNeed = false; - - try { - $this->fseek($startoffset); - $maxoffset = min($maxoffset, $info['avdataend']); - while ($this->ftell() < $maxoffset) { - $chunknamesize = $this->fread(8); - //$chunkname = substr($chunknamesize, 0, 4); - $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult - $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4)); - //if (strlen(trim($chunkname, "\x00")) < 4) { - if (strlen($chunkname) < 4) { - $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.'); - break; - } - if (($chunksize == 0) && ($chunkname != 'JUNK')) { - $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); - break; - } - if (($chunksize % 2) != 0) { - // all structures are packed on word boundaries - $chunksize++; - } - - switch ($chunkname) { - case 'LIST': - $listname = $this->fread(4); - if (preg_match('#^(movi|rec )$#i', $listname)) { - $RIFFchunk[$listname]['offset'] = $this->ftell() - 4; - $RIFFchunk[$listname]['size'] = $chunksize; - - if (!$FoundAllChunksWeNeed) { - $WhereWeWere = $this->ftell(); - $AudioChunkHeader = $this->fread(12); - $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2); - $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2); - $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4)); - - if ($AudioChunkStreamType == 'wb') { - $FirstFourBytes = substr($AudioChunkHeader, 8, 4); - if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) { - // MP3 - if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; - $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; - $getid3_mp3 = new getid3_mp3($getid3_temp); - $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); - if (isset($getid3_temp->info['mpeg']['audio'])) { - $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio']; - $info['audio'] = $getid3_temp->info['audio']; - $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; - $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; - $info['audio']['channels'] = $info['mpeg']['audio']['channels']; - $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; - $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); - //$info['bitrate'] = $info['audio']['bitrate']; - } - unset($getid3_temp, $getid3_mp3); - } - - } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) { - - // AC3 - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; - $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; - $getid3_ac3 = new getid3_ac3($getid3_temp); - $getid3_ac3->Analyze(); - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['ac3'] = $getid3_temp->info['ac3']; - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $key => $value) { - $info['warning'][] = $value; - } - } - } - unset($getid3_temp, $getid3_ac3); - } - } - $FoundAllChunksWeNeed = true; - $this->fseek($WhereWeWere); - } - $this->fseek($chunksize - 4, SEEK_CUR); - - } else { - - if (!isset($RIFFchunk[$listname])) { - $RIFFchunk[$listname] = array(); - } - $LISTchunkParent = $listname; - $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize; - if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) { - $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk); - } - - } - break; - - default: - if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) { - $this->fseek($chunksize, SEEK_CUR); - break; - } - $thisindex = 0; - if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) { - $thisindex = count($RIFFchunk[$chunkname]); - } - $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8; - $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize; - switch ($chunkname) { - case 'data': - $info['avdataoffset'] = $this->ftell(); - $info['avdataend'] = $info['avdataoffset'] + $chunksize; - - $testData = $this->fread(36); - if ($testData === '') { - break; - } - if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) { - - // Probably is MP3 data - if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_temp->info['avdataend'] = $info['avdataend']; - $getid3_mp3 = new getid3_mp3($getid3_temp); - $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false); - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['mpeg'] = $getid3_temp->info['mpeg']; - } - unset($getid3_temp, $getid3_mp3); - } - - } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) { - - // This is probably AC-3 data - $getid3_temp = new getID3(); - if ($isRegularAC3) { - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_temp->info['avdataend'] = $info['avdataend']; - } - $getid3_ac3 = new getid3_ac3($getid3_temp); - if ($isRegularAC3) { - $getid3_ac3->Analyze(); - } else { - // Dolby Digital WAV - // AC-3 content, but not encoded in same format as normal AC-3 file - // For one thing, byte order is swapped - $ac3_data = ''; - for ($i = 0; $i < 28; $i += 2) { - $ac3_data .= substr($testData, 8 + $i + 1, 1); - $ac3_data .= substr($testData, 8 + $i + 0, 1); - } - $getid3_ac3->AnalyzeString($ac3_data); - } - - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['ac3'] = $getid3_temp->info['ac3']; - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $newerror) { - $this->warning('getid3_ac3() says: ['.$newerror.']'); - } - } - } - unset($getid3_temp, $getid3_ac3); - - } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) { - - // This is probably DTS data - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_dts = new getid3_dts($getid3_temp); - $getid3_dts->Analyze(); - if (empty($getid3_temp->info['error'])) { - $info['audio'] = $getid3_temp->info['audio']; - $info['dts'] = $getid3_temp->info['dts']; - $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing - if (!empty($getid3_temp->info['warning'])) { - foreach ($getid3_temp->info['warning'] as $newerror) { - $this->warning('getid3_dts() says: ['.$newerror.']'); - } - } - } - - unset($getid3_temp, $getid3_dts); - - } elseif (substr($testData, 0, 4) == 'wvpk') { - - // This is WavPack data - $info['wavpack']['offset'] = $info['avdataoffset']; - $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4)); - $this->parseWavPackHeader(substr($testData, 8, 28)); - - } else { - // This is some other kind of data (quite possibly just PCM) - // do nothing special, just skip it - } - $nextoffset = $info['avdataend']; - $this->fseek($nextoffset); - break; - - case 'iXML': - case 'bext': - case 'cart': - case 'fmt ': - case 'strh': - case 'strf': - case 'indx': - case 'MEXT': - case 'DISP': - // always read data in - case 'JUNK': - // should be: never read data in - // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc) - if ($chunksize < 1048576) { - if ($chunksize > 0) { - $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); - if ($chunkname == 'JUNK') { - if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) { - // only keep text characters [chr(32)-chr(127)] - $info['riff']['comments']['junk'][] = trim($matches[1]); - } - // but if nothing there, ignore - // remove the key in either case - unset($RIFFchunk[$chunkname][$thisindex]['data']); - } - } - } else { - $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data'); - $this->fseek($chunksize, SEEK_CUR); - } - break; - - //case 'IDVX': - // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize)); - // break; - - default: - if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) { - $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset']; - $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size']; - unset($RIFFchunk[$chunkname][$thisindex]['offset']); - unset($RIFFchunk[$chunkname][$thisindex]['size']); - if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { - unset($RIFFchunk[$chunkname][$thisindex]); - } - if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { - unset($RIFFchunk[$chunkname]); - } - $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); - } elseif ($chunksize < 2048) { - // only read data in if smaller than 2kB - $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); - } else { - $this->fseek($chunksize, SEEK_CUR); - } - break; - } - break; - } - } - - } catch (getid3_exception $e) { - if ($e->getCode() == 10) { - $this->warning('RIFF parser: '.$e->getMessage()); - } else { - throw $e; - } - } - - return $RIFFchunk; - } - - public function ParseRIFFdata(&$RIFFdata) { - $info = &$this->getid3->info; - if ($RIFFdata) { - $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3'); - $fp_temp = fopen($tempfile, 'wb'); - $RIFFdataLength = strlen($RIFFdata); - $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4); - for ($i = 0; $i < 4; $i++) { - $RIFFdata[($i + 4)] = $NewLengthString[$i]; - } - fwrite($fp_temp, $RIFFdata); - fclose($fp_temp); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($tempfile); - $getid3_temp->info['filesize'] = $RIFFdataLength; - $getid3_temp->info['filenamepath'] = $info['filenamepath']; - $getid3_temp->info['tags'] = $info['tags']; - $getid3_temp->info['warning'] = $info['warning']; - $getid3_temp->info['error'] = $info['error']; - $getid3_temp->info['comments'] = $info['comments']; - $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array()); - $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array()); - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->Analyze(); - - $info['riff'] = $getid3_temp->info['riff']; - $info['warning'] = $getid3_temp->info['warning']; - $info['error'] = $getid3_temp->info['error']; - $info['tags'] = $getid3_temp->info['tags']; - $info['comments'] = $getid3_temp->info['comments']; - unset($getid3_riff, $getid3_temp); - unlink($tempfile); - } - return false; - } - - public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) { - $RIFFinfoKeyLookup = array( - 'IARL'=>'archivallocation', - 'IART'=>'artist', - 'ICDS'=>'costumedesigner', - 'ICMS'=>'commissionedby', - 'ICMT'=>'comment', - 'ICNT'=>'country', - 'ICOP'=>'copyright', - 'ICRD'=>'creationdate', - 'IDIM'=>'dimensions', - 'IDIT'=>'digitizationdate', - 'IDPI'=>'resolution', - 'IDST'=>'distributor', - 'IEDT'=>'editor', - 'IENG'=>'engineers', - 'IFRM'=>'accountofparts', - 'IGNR'=>'genre', - 'IKEY'=>'keywords', - 'ILGT'=>'lightness', - 'ILNG'=>'language', - 'IMED'=>'orignalmedium', - 'IMUS'=>'composer', - 'INAM'=>'title', - 'IPDS'=>'productiondesigner', - 'IPLT'=>'palette', - 'IPRD'=>'product', - 'IPRO'=>'producer', - 'IPRT'=>'part', - 'IRTD'=>'rating', - 'ISBJ'=>'subject', - 'ISFT'=>'software', - 'ISGN'=>'secondarygenre', - 'ISHP'=>'sharpness', - 'ISRC'=>'sourcesupplier', - 'ISRF'=>'digitizationsource', - 'ISTD'=>'productionstudio', - 'ISTR'=>'starring', - 'ITCH'=>'encoded_by', - 'IWEB'=>'url', - 'IWRI'=>'writer', - '____'=>'comment', - ); - foreach ($RIFFinfoKeyLookup as $key => $value) { - if (isset($RIFFinfoArray[$key])) { - foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { - if (trim($commentdata['data']) != '') { - if (isset($CommentsTargetArray[$value])) { - $CommentsTargetArray[$value][] = trim($commentdata['data']); - } else { - $CommentsTargetArray[$value] = array(trim($commentdata['data'])); - } - } - } - } - } - return true; - } - - public static function parseWAVEFORMATex($WaveFormatExData) { - // shortcut - $WaveFormatEx['raw'] = array(); - $WaveFormatEx_raw = &$WaveFormatEx['raw']; - - $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2); - $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2); - $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4); - $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4); - $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2); - $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2); - if (strlen($WaveFormatExData) > 16) { - $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2); - } - $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw); - - $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']); - $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels']; - $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec']; - $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8; - $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample']; - - return $WaveFormatEx; - } - - public function parseWavPackHeader($WavPackChunkData) { - // typedef struct { - // char ckID [4]; - // long ckSize; - // short version; - // short bits; // added for version 2.00 - // short flags, shift; // added for version 3.00 - // long total_samples, crc, crc2; - // char extension [4], extra_bc, extras [3]; - // } WavpackHeader; - - // shortcut - $info = &$this->getid3->info; - $info['wavpack'] = array(); - $thisfile_wavpack = &$info['wavpack']; - - $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2)); - if ($thisfile_wavpack['version'] >= 2) { - $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2)); - } - if ($thisfile_wavpack['version'] >= 3) { - $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2)); - $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2)); - $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4)); - $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4)); - $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4)); - $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4); - $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1)); - for ($i = 0; $i <= 2; $i++) { - $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1)); - } - - // shortcut - $thisfile_wavpack['flags'] = array(); - $thisfile_wavpack_flags = &$thisfile_wavpack['flags']; - - $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001); - $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002); - $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004); - $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008); - $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010); - $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020); - $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040); - $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080); - $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100); - $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200); - $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400); - $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800); - $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000); - $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000); - $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000); - $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000); - $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000); - $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000); - $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000); - $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000); - } - - return true; - } - - public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { - - $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure - $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels - $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner - $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1 - $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels - $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures) - $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device - $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device - $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression - $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important - $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed); - - $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier - - return $parsed; - } - - public static function ParseDIVXTAG($DIVXTAG, $raw=false) { - // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/ - // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip - // 'Byte Layout: '1111111111111111 - // '32 for Movie - 1 '1111111111111111 - // '28 for Author - 6 '6666666666666666 - // '4 for year - 2 '6666666666662222 - // '3 for genre - 3 '7777777777777777 - // '48 for Comments - 7 '7777777777777777 - // '1 for Rating - 4 '7777777777777777 - // '5 for Future Additions - 0 '333400000DIVXTAG - // '128 bytes total - - static $DIVXTAGgenre = array( - 0 => 'Action', - 1 => 'Action/Adventure', - 2 => 'Adventure', - 3 => 'Adult', - 4 => 'Anime', - 5 => 'Cartoon', - 6 => 'Claymation', - 7 => 'Comedy', - 8 => 'Commercial', - 9 => 'Documentary', - 10 => 'Drama', - 11 => 'Home Video', - 12 => 'Horror', - 13 => 'Infomercial', - 14 => 'Interactive', - 15 => 'Mystery', - 16 => 'Music Video', - 17 => 'Other', - 18 => 'Religion', - 19 => 'Sci Fi', - 20 => 'Thriller', - 21 => 'Western', - ), - $DIVXTAGrating = array( - 0 => 'Unrated', - 1 => 'G', - 2 => 'PG', - 3 => 'PG-13', - 4 => 'R', - 5 => 'NC-17', - ); - - $parsed['title'] = trim(substr($DIVXTAG, 0, 32)); - $parsed['artist'] = trim(substr($DIVXTAG, 32, 28)); - $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4))); - $parsed['comment'] = trim(substr($DIVXTAG, 64, 48)); - $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3))); - $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1)); - //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null - //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG" - - $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']); - $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']); - - if (!$raw) { - unset($parsed['genre_id'], $parsed['rating_id']); - foreach ($parsed as $key => $value) { - if (!$value === '') { - unset($parsed['key']); - } - } - } - - foreach ($parsed as $tag => $value) { - $parsed[$tag] = array($value); - } - - return $parsed; - } - - public static function waveSNDMtagLookup($tagshortname) { - $begin = __LINE__; - - /** This is not a comment! - - ©kwd keywords - ©BPM bpm - ©trt tracktitle - ©des description - ©gen category - ©fin featuredinstrument - ©LID longid - ©bex bwdescription - ©pub publisher - ©cdt cdtitle - ©alb library - ©com composer - - */ - - return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm'); - } - - public static function wFormatTagLookup($wFormatTag) { - - $begin = __LINE__; - - /** This is not a comment! - - 0x0000 Microsoft Unknown Wave Format - 0x0001 Pulse Code Modulation (PCM) - 0x0002 Microsoft ADPCM - 0x0003 IEEE Float - 0x0004 Compaq Computer VSELP - 0x0005 IBM CVSD - 0x0006 Microsoft A-Law - 0x0007 Microsoft mu-Law - 0x0008 Microsoft DTS - 0x0010 OKI ADPCM - 0x0011 Intel DVI/IMA ADPCM - 0x0012 Videologic MediaSpace ADPCM - 0x0013 Sierra Semiconductor ADPCM - 0x0014 Antex Electronics G.723 ADPCM - 0x0015 DSP Solutions DigiSTD - 0x0016 DSP Solutions DigiFIX - 0x0017 Dialogic OKI ADPCM - 0x0018 MediaVision ADPCM - 0x0019 Hewlett-Packard CU - 0x0020 Yamaha ADPCM - 0x0021 Speech Compression Sonarc - 0x0022 DSP Group TrueSpeech - 0x0023 Echo Speech EchoSC1 - 0x0024 Audiofile AF36 - 0x0025 Audio Processing Technology APTX - 0x0026 AudioFile AF10 - 0x0027 Prosody 1612 - 0x0028 LRC - 0x0030 Dolby AC2 - 0x0031 Microsoft GSM 6.10 - 0x0032 MSNAudio - 0x0033 Antex Electronics ADPCME - 0x0034 Control Resources VQLPC - 0x0035 DSP Solutions DigiREAL - 0x0036 DSP Solutions DigiADPCM - 0x0037 Control Resources CR10 - 0x0038 Natural MicroSystems VBXADPCM - 0x0039 Crystal Semiconductor IMA ADPCM - 0x003A EchoSC3 - 0x003B Rockwell ADPCM - 0x003C Rockwell Digit LK - 0x003D Xebec - 0x0040 Antex Electronics G.721 ADPCM - 0x0041 G.728 CELP - 0x0042 MSG723 - 0x0050 MPEG Layer-2 or Layer-1 - 0x0052 RT24 - 0x0053 PAC - 0x0055 MPEG Layer-3 - 0x0059 Lucent G.723 - 0x0060 Cirrus - 0x0061 ESPCM - 0x0062 Voxware - 0x0063 Canopus Atrac - 0x0064 G.726 ADPCM - 0x0065 G.722 ADPCM - 0x0066 DSAT - 0x0067 DSAT Display - 0x0069 Voxware Byte Aligned - 0x0070 Voxware AC8 - 0x0071 Voxware AC10 - 0x0072 Voxware AC16 - 0x0073 Voxware AC20 - 0x0074 Voxware MetaVoice - 0x0075 Voxware MetaSound - 0x0076 Voxware RT29HW - 0x0077 Voxware VR12 - 0x0078 Voxware VR18 - 0x0079 Voxware TQ40 - 0x0080 Softsound - 0x0081 Voxware TQ60 - 0x0082 MSRT24 - 0x0083 G.729A - 0x0084 MVI MV12 - 0x0085 DF G.726 - 0x0086 DF GSM610 - 0x0088 ISIAudio - 0x0089 Onlive - 0x0091 SBC24 - 0x0092 Dolby AC3 SPDIF - 0x0093 MediaSonic G.723 - 0x0094 Aculab PLC Prosody 8kbps - 0x0097 ZyXEL ADPCM - 0x0098 Philips LPCBB - 0x0099 Packed - 0x00FF AAC - 0x0100 Rhetorex ADPCM - 0x0101 IBM mu-law - 0x0102 IBM A-law - 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM) - 0x0111 Vivo G.723 - 0x0112 Vivo Siren - 0x0123 Digital G.723 - 0x0125 Sanyo LD ADPCM - 0x0130 Sipro Lab Telecom ACELP NET - 0x0131 Sipro Lab Telecom ACELP 4800 - 0x0132 Sipro Lab Telecom ACELP 8V3 - 0x0133 Sipro Lab Telecom G.729 - 0x0134 Sipro Lab Telecom G.729A - 0x0135 Sipro Lab Telecom Kelvin - 0x0140 Windows Media Video V8 - 0x0150 Qualcomm PureVoice - 0x0151 Qualcomm HalfRate - 0x0155 Ring Zero Systems TUB GSM - 0x0160 Microsoft Audio 1 - 0x0161 Windows Media Audio V7 / V8 / V9 - 0x0162 Windows Media Audio Professional V9 - 0x0163 Windows Media Audio Lossless V9 - 0x0200 Creative Labs ADPCM - 0x0202 Creative Labs Fastspeech8 - 0x0203 Creative Labs Fastspeech10 - 0x0210 UHER Informatic GmbH ADPCM - 0x0220 Quarterdeck - 0x0230 I-link Worldwide VC - 0x0240 Aureal RAW Sport - 0x0250 Interactive Products HSX - 0x0251 Interactive Products RPELP - 0x0260 Consistent Software CS2 - 0x0270 Sony SCX - 0x0300 Fujitsu FM Towns Snd - 0x0400 BTV Digital - 0x0401 Intel Music Coder - 0x0450 QDesign Music - 0x0680 VME VMPCM - 0x0681 AT&T Labs TPC - 0x08AE ClearJump LiteWave - 0x1000 Olivetti GSM - 0x1001 Olivetti ADPCM - 0x1002 Olivetti CELP - 0x1003 Olivetti SBC - 0x1004 Olivetti OPR - 0x1100 Lernout & Hauspie Codec (0x1100) - 0x1101 Lernout & Hauspie CELP Codec (0x1101) - 0x1102 Lernout & Hauspie SBC Codec (0x1102) - 0x1103 Lernout & Hauspie SBC Codec (0x1103) - 0x1104 Lernout & Hauspie SBC Codec (0x1104) - 0x1400 Norris - 0x1401 AT&T ISIAudio - 0x1500 Soundspace Music Compression - 0x181C VoxWare RT24 Speech - 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com) - 0x2000 Dolby AC3 - 0x2001 Dolby DTS - 0x2002 WAVE_FORMAT_14_4 - 0x2003 WAVE_FORMAT_28_8 - 0x2004 WAVE_FORMAT_COOK - 0x2005 WAVE_FORMAT_DNET - 0x674F Ogg Vorbis 1 - 0x6750 Ogg Vorbis 2 - 0x6751 Ogg Vorbis 3 - 0x676F Ogg Vorbis 1+ - 0x6770 Ogg Vorbis 2+ - 0x6771 Ogg Vorbis 3+ - 0x7A21 GSM-AMR (CBR, no SID) - 0x7A22 GSM-AMR (VBR, including SID) - 0xFFFE WAVE_FORMAT_EXTENSIBLE - 0xFFFF WAVE_FORMAT_DEVELOPMENT - - */ - - return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag'); - } - - public static function fourccLookup($fourcc) { - - $begin = __LINE__; - - /** This is not a comment! - - swot http://developer.apple.com/qa/snd/snd07.html - ____ No Codec (____) - _BIT BI_BITFIELDS (Raw RGB) - _JPG JPEG compressed - _PNG PNG compressed W3C/ISO/IEC (RFC-2083) - _RAW Full Frames (Uncompressed) - _RGB Raw RGB Bitmap - _RL4 RLE 4bpp RGB - _RL8 RLE 8bpp RGB - 3IV1 3ivx MPEG-4 v1 - 3IV2 3ivx MPEG-4 v2 - 3IVX 3ivx MPEG-4 - AASC Autodesk Animator - ABYR Kensington ?ABYR? - AEMI Array Microsystems VideoONE MPEG1-I Capture - AFLC Autodesk Animator FLC - AFLI Autodesk Animator FLI - AMPG Array Microsystems VideoONE MPEG - ANIM Intel RDX (ANIM) - AP41 AngelPotion Definitive - ASV1 Asus Video v1 - ASV2 Asus Video v2 - ASVX Asus Video 2.0 (audio) - AUR2 AuraVision Aura 2 Codec - YUV 4:2:2 - AURA AuraVision Aura 1 Codec - YUV 4:1:1 - AVDJ Independent JPEG Group\'s codec (AVDJ) - AVRN Independent JPEG Group\'s codec (AVRN) - AYUV 4:4:4 YUV (AYUV) - AZPR Quicktime Apple Video (AZPR) - BGR Raw RGB32 - BLZ0 Blizzard DivX MPEG-4 - BTVC Conexant Composite Video - BINK RAD Game Tools Bink Video - BT20 Conexant Prosumer Video - BTCV Conexant Composite Video Codec - BW10 Data Translation Broadway MPEG Capture - CC12 Intel YUV12 - CDVC Canopus DV - CFCC Digital Processing Systems DPS Perception - CGDI Microsoft Office 97 Camcorder Video - CHAM Winnov Caviara Champagne - CJPG Creative WebCam JPEG - CLJR Cirrus Logic YUV 4:1:1 - CMYK Common Data Format in Printing (Colorgraph) - CPLA Weitek 4:2:0 YUV Planar - CRAM Microsoft Video 1 (CRAM) - cvid Radius Cinepak - CVID Radius Cinepak - CWLT Microsoft Color WLT DIB - CYUV Creative Labs YUV - CYUY ATI YUV - D261 H.261 - D263 H.263 - DIB Device Independent Bitmap - DIV1 FFmpeg OpenDivX - DIV2 Microsoft MPEG-4 v1/v2 - DIV3 DivX ;-) MPEG-4 v3.x Low-Motion - DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion - DIV5 DivX MPEG-4 v5.x - DIV6 DivX ;-) (MS MPEG-4 v3.x) - DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo) - divx DivX MPEG-4 - DMB1 Matrox Rainbow Runner hardware MJPEG - DMB2 Paradigm MJPEG - DSVD ?DSVD? - DUCK Duck TrueMotion 1.0 - DPS0 DPS/Leitch Reality Motion JPEG - DPSC DPS/Leitch PAR Motion JPEG - DV25 Matrox DVCPRO codec - DV50 Matrox DVCPRO50 codec - DVC IEC 61834 and SMPTE 314M (DVC/DV Video) - DVCP IEC 61834 and SMPTE 314M (DVC/DV Video) - DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps - DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com) - DVSL IEC Standard DV compressed in SD (SDL) - DVAN ?DVAN? - DVE2 InSoft DVE-2 Videoconferencing - dvsd IEC 61834 and SMPTE 314M DVC/DV Video - DVSD IEC 61834 and SMPTE 314M DVC/DV Video - DVX1 Lucent DVX1000SP Video Decoder - DVX2 Lucent DVX2000S Video Decoder - DVX3 Lucent DVX3000S Video Decoder - DX50 DivX v5 - DXT1 Microsoft DirectX Compressed Texture (DXT1) - DXT2 Microsoft DirectX Compressed Texture (DXT2) - DXT3 Microsoft DirectX Compressed Texture (DXT3) - DXT4 Microsoft DirectX Compressed Texture (DXT4) - DXT5 Microsoft DirectX Compressed Texture (DXT5) - DXTC Microsoft DirectX Compressed Texture (DXTC) - DXTn Microsoft DirectX Compressed Texture (DXTn) - EM2V Etymonix MPEG-2 I-frame (www.etymonix.com) - EKQ0 Elsa ?EKQ0? - ELK0 Elsa ?ELK0? - ESCP Eidos Escape - ETV1 eTreppid Video ETV1 - ETV2 eTreppid Video ETV2 - ETVC eTreppid Video ETVC - FLIC Autodesk FLI/FLC Animation - FLV1 Sorenson Spark - FLV4 On2 TrueMotion VP6 - FRWT Darim Vision Forward Motion JPEG (www.darvision.com) - FRWU Darim Vision Forward Uncompressed (www.darvision.com) - FLJP D-Vision Field Encoded Motion JPEG - FPS1 FRAPS v1 - FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel - FRWD SoftLab-Nsk Forward Motion JPEG - FVF1 Iterated Systems Fractal Video Frame - GLZW Motion LZW (gabest@freemail.hu) - GPEG Motion JPEG (gabest@freemail.hu) - GWLT Microsoft Greyscale WLT DIB - H260 Intel ITU H.260 Videoconferencing - H261 Intel ITU H.261 Videoconferencing - H262 Intel ITU H.262 Videoconferencing - H263 Intel ITU H.263 Videoconferencing - H264 Intel ITU H.264 Videoconferencing - H265 Intel ITU H.265 Videoconferencing - H266 Intel ITU H.266 Videoconferencing - H267 Intel ITU H.267 Videoconferencing - H268 Intel ITU H.268 Videoconferencing - H269 Intel ITU H.269 Videoconferencing - HFYU Huffman Lossless Codec - HMCR Rendition Motion Compensation Format (HMCR) - HMRR Rendition Motion Compensation Format (HMRR) - I263 FFmpeg I263 decoder - IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane") - IUYV Interlaced version of UYVY (www.leadtools.com) - IY41 Interlaced version of Y41P (www.leadtools.com) - IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard - IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard - IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes) - i263 Intel ITU H.263 Videoconferencing (i263) - I420 Intel Indeo 4 - IAN Intel Indeo 4 (RDX) - ICLB InSoft CellB Videoconferencing - IGOR Power DVD - IJPG Intergraph JPEG - ILVC Intel Layered Video - ILVR ITU-T H.263+ - IPDV I-O Data Device Giga AVI DV Codec - IR21 Intel Indeo 2.1 - IRAW Intel YUV Uncompressed - IV30 Intel Indeo 3.0 - IV31 Intel Indeo 3.1 - IV32 Ligos Indeo 3.2 - IV33 Ligos Indeo 3.3 - IV34 Ligos Indeo 3.4 - IV35 Ligos Indeo 3.5 - IV36 Ligos Indeo 3.6 - IV37 Ligos Indeo 3.7 - IV38 Ligos Indeo 3.8 - IV39 Ligos Indeo 3.9 - IV40 Ligos Indeo Interactive 4.0 - IV41 Ligos Indeo Interactive 4.1 - IV42 Ligos Indeo Interactive 4.2 - IV43 Ligos Indeo Interactive 4.3 - IV44 Ligos Indeo Interactive 4.4 - IV45 Ligos Indeo Interactive 4.5 - IV46 Ligos Indeo Interactive 4.6 - IV47 Ligos Indeo Interactive 4.7 - IV48 Ligos Indeo Interactive 4.8 - IV49 Ligos Indeo Interactive 4.9 - IV50 Ligos Indeo Interactive 5.0 - JBYR Kensington ?JBYR? - JPEG Still Image JPEG DIB - JPGL Pegasus Lossless Motion JPEG - KMVC Team17 Software Karl Morton\'s Video Codec - LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com) - LEAD LEAD Video Codec - Ljpg LEAD MJPEG Codec - MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de) - MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com) - MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com) - MMES Matrox MPEG-2 I-frame - MP2v Microsoft S-Mpeg 4 version 1 (MP2v) - MP42 Microsoft S-Mpeg 4 version 2 (MP42) - MP43 Microsoft S-Mpeg 4 version 3 (MP43) - MP4S Microsoft S-Mpeg 4 version 3 (MP4S) - MP4V FFmpeg MPEG-4 - MPG1 FFmpeg MPEG 1/2 - MPG2 FFmpeg MPEG 1/2 - MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3) - MPG4 Microsoft MPEG-4 - MPGI Sigma Designs MPEG - MPNG PNG images decoder - MSS1 Microsoft Windows Screen Video - MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) - M261 Microsoft H.261 - M263 Microsoft H.263 - M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2) - m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2) - MC12 ATI Motion Compensation Format (MC12) - MCAM ATI Motion Compensation Format (MCAM) - MJ2C Morgan Multimedia Motion JPEG2000 - mJPG IBM Motion JPEG w/ Huffman Tables - MJPG Microsoft Motion JPEG DIB - MP42 Microsoft MPEG-4 (low-motion) - MP43 Microsoft MPEG-4 (fast-motion) - MP4S Microsoft MPEG-4 (MP4S) - mp4s Microsoft MPEG-4 (mp4s) - MPEG Chromatic Research MPEG-1 Video I-Frame - MPG4 Microsoft MPEG-4 Video High Speed Compressor - MPGI Sigma Designs MPEG - MRCA FAST Multimedia Martin Regen Codec - MRLE Microsoft Run Length Encoding - MSVC Microsoft Video 1 - MTX1 Matrox ?MTX1? - MTX2 Matrox ?MTX2? - MTX3 Matrox ?MTX3? - MTX4 Matrox ?MTX4? - MTX5 Matrox ?MTX5? - MTX6 Matrox ?MTX6? - MTX7 Matrox ?MTX7? - MTX8 Matrox ?MTX8? - MTX9 Matrox ?MTX9? - MV12 Motion Pixels Codec (old) - MWV1 Aware Motion Wavelets - nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm) - NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com) - NUV1 NuppelVideo - NTN1 Nogatech Video Compression 1 - NVS0 nVidia GeForce Texture (NVS0) - NVS1 nVidia GeForce Texture (NVS1) - NVS2 nVidia GeForce Texture (NVS2) - NVS3 nVidia GeForce Texture (NVS3) - NVS4 nVidia GeForce Texture (NVS4) - NVS5 nVidia GeForce Texture (NVS5) - NVT0 nVidia GeForce Texture (NVT0) - NVT1 nVidia GeForce Texture (NVT1) - NVT2 nVidia GeForce Texture (NVT2) - NVT3 nVidia GeForce Texture (NVT3) - NVT4 nVidia GeForce Texture (NVT4) - NVT5 nVidia GeForce Texture (NVT5) - PIXL MiroXL, Pinnacle PCTV - PDVC I-O Data Device Digital Video Capture DV codec - PGVV Radius Video Vision - PHMO IBM Photomotion - PIM1 MPEG Realtime (Pinnacle Cards) - PIM2 Pegasus Imaging ?PIM2? - PIMJ Pegasus Imaging Lossless JPEG - PVEZ Horizons Technology PowerEZ - PVMM PacketVideo Corporation MPEG-4 - PVW2 Pegasus Imaging Wavelet Compression - Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de) - Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de) - QPEG Q-Team QPEG 1.0 - qpeq Q-Team QPEG 1.1 - RGB Raw BGR32 - RGBA Raw RGB w/ Alpha - RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com) - ROQV Id RoQ File Video Decoder - RPZA Quicktime Apple Video (RPZA) - RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/) - RV10 RealVideo 1.0 (aka RealVideo 5.0) - RV13 RealVideo 1.0 (RV13) - RV20 RealVideo G2 - RV30 RealVideo 8 - RV40 RealVideo 9 - RGBT Raw RGB w/ Transparency - RLE Microsoft Run Length Encoder - RLE4 Run Length Encoded (4bpp, 16-color) - RLE8 Run Length Encoded (8bpp, 256-color) - RT21 Intel Indeo RealTime Video 2.1 - rv20 RealVideo G2 - rv30 RealVideo 8 - RVX Intel RDX (RVX ) - SMC Apple Graphics (SMC ) - SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2 - SPIG Radius Spigot - SVQ3 Sorenson Video 3 (Apple Quicktime 5) - s422 Tekram VideoCap C210 YUV 4:2:2 - SDCC Sun Communication Digital Camera Codec - SFMC CrystalNet Surface Fitting Method - SMSC Radius SMSC - SMSD Radius SMSD - smsv WorldConnect Wavelet Video - SPIG Radius Spigot - SPLC Splash Studios ACM Audio Codec (www.splashstudios.net) - SQZ2 Microsoft VXTreme Video Codec V2 - STVA ST Microelectronics CMOS Imager Data (Bayer) - STVB ST Microelectronics CMOS Imager Data (Nudged Bayer) - STVC ST Microelectronics CMOS Imager Data (Bunched) - STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format) - STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data) - SV10 Sorenson Video R1 - SVQ1 Sorenson Video - T420 Toshiba YUV 4:2:0 - TM2A Duck TrueMotion Archiver 2.0 (www.duck.com) - TVJP Pinnacle/Truevision Targa 2000 board (TVJP) - TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ) - TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com) - TY2C Trident Decompression Driver - TLMS TeraLogic Motion Intraframe Codec (TLMS) - TLST TeraLogic Motion Intraframe Codec (TLST) - TM20 Duck TrueMotion 2.0 - TM2X Duck TrueMotion 2X - TMIC TeraLogic Motion Intraframe Codec (TMIC) - TMOT Horizons Technology TrueMotion S - tmot Horizons TrueMotion Video Compression - TR20 Duck TrueMotion RealTime 2.0 - TSCC TechSmith Screen Capture Codec - TV10 Tecomac Low-Bit Rate Codec - TY2N Trident ?TY2N? - U263 UB Video H.263/H.263+/H.263++ Decoder - UMP4 UB Video MPEG 4 (www.ubvideo.com) - UYNV Nvidia UYVY packed 4:2:2 - UYVP Evans & Sutherland YCbCr 4:2:2 extended precision - UCOD eMajix.com ClearVideo - ULTI IBM Ultimotion - UYVY UYVY packed 4:2:2 - V261 Lucent VX2000S - VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/) - VIV1 FFmpeg H263+ decoder - VIV2 Vivo H.263 - VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf) - VTLP Alaris VideoGramPiX - VYU9 ATI YUV (VYU9) - VYUY ATI YUV (VYUY) - V261 Lucent VX2000S - V422 Vitec Multimedia 24-bit YUV 4:2:2 Format - V655 Vitec Multimedia 16-bit YUV 4:2:2 Format - VCR1 ATI Video Codec 1 - VCR2 ATI Video Codec 2 - VCR3 ATI VCR 3.0 - VCR4 ATI VCR 4.0 - VCR5 ATI VCR 5.0 - VCR6 ATI VCR 6.0 - VCR7 ATI VCR 7.0 - VCR8 ATI VCR 8.0 - VCR9 ATI VCR 9.0 - VDCT Vitec Multimedia Video Maker Pro DIB - VDOM VDOnet VDOWave - VDOW VDOnet VDOLive (H.263) - VDTZ Darim Vison VideoTizer YUV - VGPX Alaris VideoGramPiX - VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422 - VIVO Vivo H.263 v2.00 - vivo Vivo H.263 - VIXL Miro/Pinnacle Video XL - VLV1 VideoLogic/PURE Digital Videologic Capture - VP30 On2 VP3.0 - VP31 On2 VP3.1 - VP6F On2 TrueMotion VP6 - VX1K Lucent VX1000S Video Codec - VX2K Lucent VX2000S Video Codec - VXSP Lucent VX1000SP Video Codec - WBVC Winbond W9960 - WHAM Microsoft Video 1 (WHAM) - WINX Winnov Software Compression - WJPG AverMedia Winbond JPEG - WMV1 Windows Media Video V7 - WMV2 Windows Media Video V8 - WMV3 Windows Media Video V9 - WNV1 Winnov Hardware Compression - XYZP Extended PAL format XYZ palette (www.riff.org) - x263 Xirlink H.263 - XLV0 NetXL Video Decoder - XMPG Xing MPEG (I-Frame only) - XVID XviD MPEG-4 (www.xvid.org) - XXAN ?XXAN? - YU92 Intel YUV (YU92) - YUNV Nvidia Uncompressed YUV 4:2:2 - YUVP Extended PAL format YUV palette (www.riff.org) - Y211 YUV 2:1:1 Packed - Y411 YUV 4:1:1 Packed - Y41B Weitek YUV 4:1:1 Planar - Y41P Brooktree PC1 YUV 4:1:1 Packed - Y41T Brooktree PC1 YUV 4:1:1 with transparency - Y42B Weitek YUV 4:2:2 Planar - Y42T Brooktree UYUV 4:2:2 with transparency - Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera - Y800 Simple, single Y plane for monochrome images - Y8 Grayscale video - YC12 Intel YUV 12 codec - YUV8 Winnov Caviar YUV8 - YUV9 Intel YUV9 - YUY2 Uncompressed YUV 4:2:2 - YUYV Canopus YUV - YV12 YVU12 Planar - YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes) - YVYU YVYU 4:2:2 Packed - ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) - ZPEG Metheus Video Zipper - - */ - - return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc'); - } - - private function EitherEndian2Int($byteword, $signed=false) { - if ($this->getid3->info['fileformat'] == 'riff') { - return getid3_lib::LittleEndian2Int($byteword, $signed); - } - return getid3_lib::BigEndian2Int($byteword, false, $signed); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.riff.php // +// module for analyzing RIFF files // +// multiple formats supported by this module: // +// Wave, AVI, AIFF/AIFC, (MP3,AC3)/RIFF, Wavpack v3, 8SVX // +// dependencies: module.audio.mp3.php // +// module.audio.ac3.php // +// module.audio.dts.php // +// /// +///////////////////////////////////////////////////////////////// + +/** +* @todo Parse AC-3/DTS audio inside WAVE correctly +* @todo Rewrite RIFF parser totally +*/ + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.mp3.php', __FILE__, true); +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.dts.php', __FILE__, true); + +class getid3_riff extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + // initialize these values to an empty array, otherwise they default to NULL + // and you can't append array values to a NULL value + $info['riff'] = array('raw'=>array()); + + // Shortcuts + $thisfile_riff = &$info['riff']; + $thisfile_riff_raw = &$thisfile_riff['raw']; + $thisfile_audio = &$info['audio']; + $thisfile_video = &$info['video']; + $thisfile_audio_dataformat = &$thisfile_audio['dataformat']; + $thisfile_riff_audio = &$thisfile_riff['audio']; + $thisfile_riff_video = &$thisfile_riff['video']; + + $Original['avdataoffset'] = $info['avdataoffset']; + $Original['avdataend'] = $info['avdataend']; + + $this->fseek($info['avdataoffset']); + $RIFFheader = $this->fread(12); + $offset = $this->ftell(); + $RIFFtype = substr($RIFFheader, 0, 4); + $RIFFsize = substr($RIFFheader, 4, 4); + $RIFFsubtype = substr($RIFFheader, 8, 4); + + switch ($RIFFtype) { + + case 'FORM': // AIFF, AIFC + $info['fileformat'] = 'aiff'; + $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); + $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); + break; + + case 'RIFF': // AVI, WAV, etc + case 'SDSS': // SDSS is identical to RIFF, just renamed. Used by SmartSound QuickTracks (www.smartsound.com) + case 'RMP3': // RMP3 is identical to RIFF, just renamed. Used by [unknown program] when creating RIFF-MP3s + $info['fileformat'] = 'riff'; + $thisfile_riff['header_size'] = $this->EitherEndian2Int($RIFFsize); + if ($RIFFsubtype == 'RMP3') { + // RMP3 is identical to WAVE, just renamed. Used by [unknown program] when creating RIFF-MP3s + $RIFFsubtype = 'WAVE'; + } + $thisfile_riff[$RIFFsubtype] = $this->ParseRIFF($offset, ($offset + $thisfile_riff['header_size'] - 4)); + if (($info['avdataend'] - $info['filesize']) == 1) { + // LiteWave appears to incorrectly *not* pad actual output file + // to nearest WORD boundary so may appear to be short by one + // byte, in which case - skip warning + $info['avdataend'] = $info['filesize']; + } + + $nextRIFFoffset = $Original['avdataoffset'] + 8 + $thisfile_riff['header_size']; // 8 = "RIFF" + 32-bit offset + while ($nextRIFFoffset < min($info['filesize'], $info['avdataend'])) { + try { + $this->fseek($nextRIFFoffset); + } catch (getid3_exception $e) { + if ($e->getCode() == 10) { + //$this->warning('RIFF parser: '.$e->getMessage()); + $this->error('AVI extends beyond '.round(PHP_INT_MAX / 1073741824).'GB and PHP filesystem functions cannot read that far, playtime may be wrong'); + $this->warning('[avdataend] value may be incorrect, multiple AVIX chunks may be present'); + break; + } else { + throw $e; + } + } + $nextRIFFheader = $this->fread(12); + if ($nextRIFFoffset == ($info['avdataend'] - 1)) { + if (substr($nextRIFFheader, 0, 1) == "\x00") { + // RIFF padded to WORD boundary, we're actually already at the end + break; + } + } + $nextRIFFheaderID = substr($nextRIFFheader, 0, 4); + $nextRIFFsize = $this->EitherEndian2Int(substr($nextRIFFheader, 4, 4)); + $nextRIFFtype = substr($nextRIFFheader, 8, 4); + $chunkdata = array(); + $chunkdata['offset'] = $nextRIFFoffset + 8; + $chunkdata['size'] = $nextRIFFsize; + $nextRIFFoffset = $chunkdata['offset'] + $chunkdata['size']; + + switch ($nextRIFFheaderID) { + + case 'RIFF': + $chunkdata['chunks'] = $this->ParseRIFF($chunkdata['offset'] + 4, $nextRIFFoffset); + + if (!isset($thisfile_riff[$nextRIFFtype])) { + $thisfile_riff[$nextRIFFtype] = array(); + } + $thisfile_riff[$nextRIFFtype][] = $chunkdata; + break; + + case 'JUNK': + // ignore + $thisfile_riff[$nextRIFFheaderID][] = $chunkdata; + break; + + case 'IDVX': + $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunkdata['size'])); + break; + + default: + if ($info['filesize'] == ($chunkdata['offset'] - 8 + 128)) { + $DIVXTAG = $nextRIFFheader.$this->fread(128 - 12); + if (substr($DIVXTAG, -7) == 'DIVXTAG') { + // DIVXTAG is supposed to be inside an IDVX chunk in a LIST chunk, but some bad encoders just slap it on the end of a file + $this->warning('Found wrongly-structured DIVXTAG at offset '.($this->ftell() - 128).', parsing anyway'); + $info['divxtag']['comments'] = self::ParseDIVXTAG($DIVXTAG); + break 2; + } + } + $this->warning('Expecting "RIFF|JUNK|IDVX" at '.$nextRIFFoffset.', found "'.$nextRIFFheaderID.'" ('.getid3_lib::PrintHexBytes($nextRIFFheaderID).') - skipping rest of file'); + break 2; + + } + + } + if ($RIFFsubtype == 'WAVE') { + $thisfile_riff_WAVE = &$thisfile_riff['WAVE']; + } + break; + + default: + $this->error('Cannot parse RIFF (this is maybe not a RIFF / WAV / AVI file?) - expecting "FORM|RIFF|SDSS|RMP3" found "'.$RIFFsubtype.'" instead'); + unset($info['fileformat']); + return false; + } + + $streamindex = 0; + switch ($RIFFsubtype) { + case 'WAVE': + if (empty($thisfile_audio['bitrate_mode'])) { + $thisfile_audio['bitrate_mode'] = 'cbr'; + } + if (empty($thisfile_audio_dataformat)) { + $thisfile_audio_dataformat = 'wav'; + } + + if (isset($thisfile_riff_WAVE['data'][0]['offset'])) { + $info['avdataoffset'] = $thisfile_riff_WAVE['data'][0]['offset'] + 8; + $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff_WAVE['data'][0]['size']; + } + if (isset($thisfile_riff_WAVE['fmt '][0]['data'])) { + + $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($thisfile_riff_WAVE['fmt '][0]['data']); + $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; + if (!isset($thisfile_riff_audio[$streamindex]['bitrate']) || ($thisfile_riff_audio[$streamindex]['bitrate'] == 0)) { + $info['error'][] = 'Corrupt RIFF file: bitrate_audio == zero'; + return false; + } + $thisfile_riff_raw['fmt '] = $thisfile_riff_audio[$streamindex]['raw']; + unset($thisfile_riff_audio[$streamindex]['raw']); + $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; + + $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); + if (substr($thisfile_audio['codec'], 0, strlen('unknown: 0x')) == 'unknown: 0x') { + $info['warning'][] = 'Audio codec = '.$thisfile_audio['codec']; + } + $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; + + if (empty($info['playtime_seconds'])) { // may already be set (e.g. DTS-WAV) + $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + } + + $thisfile_audio['lossless'] = false; + if (isset($thisfile_riff_WAVE['data'][0]['offset']) && isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { + switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { + + case 0x0001: // PCM + $thisfile_audio['lossless'] = true; + break; + + case 0x2000: // AC-3 + $thisfile_audio_dataformat = 'ac3'; + break; + + default: + // do nothing + break; + + } + } + $thisfile_audio['streams'][$streamindex]['wformattag'] = $thisfile_audio['wformattag']; + $thisfile_audio['streams'][$streamindex]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; + $thisfile_audio['streams'][$streamindex]['lossless'] = $thisfile_audio['lossless']; + $thisfile_audio['streams'][$streamindex]['dataformat'] = $thisfile_audio_dataformat; + } + + if (isset($thisfile_riff_WAVE['rgad'][0]['data'])) { + + // shortcuts + $rgadData = &$thisfile_riff_WAVE['rgad'][0]['data']; + $thisfile_riff_raw['rgad'] = array('track'=>array(), 'album'=>array()); + $thisfile_riff_raw_rgad = &$thisfile_riff_raw['rgad']; + $thisfile_riff_raw_rgad_track = &$thisfile_riff_raw_rgad['track']; + $thisfile_riff_raw_rgad_album = &$thisfile_riff_raw_rgad['album']; + + $thisfile_riff_raw_rgad['fPeakAmplitude'] = getid3_lib::LittleEndian2Float(substr($rgadData, 0, 4)); + $thisfile_riff_raw_rgad['nRadioRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 4, 2)); + $thisfile_riff_raw_rgad['nAudiophileRgAdjust'] = $this->EitherEndian2Int(substr($rgadData, 6, 2)); + + $nRadioRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nRadioRgAdjust']), 16, '0', STR_PAD_LEFT); + $nAudiophileRgAdjustBitstring = str_pad(getid3_lib::Dec2Bin($thisfile_riff_raw_rgad['nAudiophileRgAdjust']), 16, '0', STR_PAD_LEFT); + $thisfile_riff_raw_rgad_track['name'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 0, 3)); + $thisfile_riff_raw_rgad_track['originator'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 3, 3)); + $thisfile_riff_raw_rgad_track['signbit'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 6, 1)); + $thisfile_riff_raw_rgad_track['adjustment'] = getid3_lib::Bin2Dec(substr($nRadioRgAdjustBitstring, 7, 9)); + $thisfile_riff_raw_rgad_album['name'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 0, 3)); + $thisfile_riff_raw_rgad_album['originator'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 3, 3)); + $thisfile_riff_raw_rgad_album['signbit'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 6, 1)); + $thisfile_riff_raw_rgad_album['adjustment'] = getid3_lib::Bin2Dec(substr($nAudiophileRgAdjustBitstring, 7, 9)); + + $thisfile_riff['rgad']['peakamplitude'] = $thisfile_riff_raw_rgad['fPeakAmplitude']; + if (($thisfile_riff_raw_rgad_track['name'] != 0) && ($thisfile_riff_raw_rgad_track['originator'] != 0)) { + $thisfile_riff['rgad']['track']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_track['name']); + $thisfile_riff['rgad']['track']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_track['originator']); + $thisfile_riff['rgad']['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_track['adjustment'], $thisfile_riff_raw_rgad_track['signbit']); + } + if (($thisfile_riff_raw_rgad_album['name'] != 0) && ($thisfile_riff_raw_rgad_album['originator'] != 0)) { + $thisfile_riff['rgad']['album']['name'] = getid3_lib::RGADnameLookup($thisfile_riff_raw_rgad_album['name']); + $thisfile_riff['rgad']['album']['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_riff_raw_rgad_album['originator']); + $thisfile_riff['rgad']['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($thisfile_riff_raw_rgad_album['adjustment'], $thisfile_riff_raw_rgad_album['signbit']); + } + } + + if (isset($thisfile_riff_WAVE['fact'][0]['data'])) { + $thisfile_riff_raw['fact']['NumberOfSamples'] = $this->EitherEndian2Int(substr($thisfile_riff_WAVE['fact'][0]['data'], 0, 4)); + + // This should be a good way of calculating exact playtime, + // but some sample files have had incorrect number of samples, + // so cannot use this method + + // if (!empty($thisfile_riff_raw['fmt ']['nSamplesPerSec'])) { + // $info['playtime_seconds'] = (float) $thisfile_riff_raw['fact']['NumberOfSamples'] / $thisfile_riff_raw['fmt ']['nSamplesPerSec']; + // } + } + if (!empty($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'])) { + $thisfile_audio['bitrate'] = getid3_lib::CastAsInt($thisfile_riff_raw['fmt ']['nAvgBytesPerSec'] * 8); + } + + if (isset($thisfile_riff_WAVE['bext'][0]['data'])) { + // shortcut + $thisfile_riff_WAVE_bext_0 = &$thisfile_riff_WAVE['bext'][0]; + + $thisfile_riff_WAVE_bext_0['title'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 0, 256)); + $thisfile_riff_WAVE_bext_0['author'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 256, 32)); + $thisfile_riff_WAVE_bext_0['reference'] = trim(substr($thisfile_riff_WAVE_bext_0['data'], 288, 32)); + $thisfile_riff_WAVE_bext_0['origin_date'] = substr($thisfile_riff_WAVE_bext_0['data'], 320, 10); + $thisfile_riff_WAVE_bext_0['origin_time'] = substr($thisfile_riff_WAVE_bext_0['data'], 330, 8); + $thisfile_riff_WAVE_bext_0['time_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 338, 8)); + $thisfile_riff_WAVE_bext_0['bwf_version'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_bext_0['data'], 346, 1)); + $thisfile_riff_WAVE_bext_0['reserved'] = substr($thisfile_riff_WAVE_bext_0['data'], 347, 254); + $thisfile_riff_WAVE_bext_0['coding_history'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_bext_0['data'], 601))); + if (preg_match('#^([0-9]{4}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_date'], $matches_bext_date)) { + if (preg_match('#^([0-9]{2}).([0-9]{2}).([0-9]{2})$#', $thisfile_riff_WAVE_bext_0['origin_time'], $matches_bext_time)) { + list($dummy, $bext_timestamp['year'], $bext_timestamp['month'], $bext_timestamp['day']) = $matches_bext_date; + list($dummy, $bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second']) = $matches_bext_time; + $thisfile_riff_WAVE_bext_0['origin_date_unix'] = gmmktime($bext_timestamp['hour'], $bext_timestamp['minute'], $bext_timestamp['second'], $bext_timestamp['month'], $bext_timestamp['day'], $bext_timestamp['year']); + } else { + $info['warning'][] = 'RIFF.WAVE.BEXT.origin_time is invalid'; + } + } else { + $info['warning'][] = 'RIFF.WAVE.BEXT.origin_date is invalid'; + } + $thisfile_riff['comments']['author'][] = $thisfile_riff_WAVE_bext_0['author']; + $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_bext_0['title']; + } + + if (isset($thisfile_riff_WAVE['MEXT'][0]['data'])) { + // shortcut + $thisfile_riff_WAVE_MEXT_0 = &$thisfile_riff_WAVE['MEXT'][0]; + + $thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 0, 2)); + $thisfile_riff_WAVE_MEXT_0['flags']['homogenous'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0001); + if ($thisfile_riff_WAVE_MEXT_0['flags']['homogenous']) { + $thisfile_riff_WAVE_MEXT_0['flags']['padding'] = ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0002) ? false : true; + $thisfile_riff_WAVE_MEXT_0['flags']['22_or_44'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0004); + $thisfile_riff_WAVE_MEXT_0['flags']['free_format'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['sound_information'] & 0x0008); + + $thisfile_riff_WAVE_MEXT_0['nominal_frame_size'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 2, 2)); + } + $thisfile_riff_WAVE_MEXT_0['anciliary_data_length'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 6, 2)); + $thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_MEXT_0['data'], 8, 2)); + $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_left'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0001); + $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_free'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0002); + $thisfile_riff_WAVE_MEXT_0['flags']['anciliary_data_right'] = (bool) ($thisfile_riff_WAVE_MEXT_0['raw']['anciliary_data_def'] & 0x0004); + } + + if (isset($thisfile_riff_WAVE['cart'][0]['data'])) { + // shortcut + $thisfile_riff_WAVE_cart_0 = &$thisfile_riff_WAVE['cart'][0]; + + $thisfile_riff_WAVE_cart_0['version'] = substr($thisfile_riff_WAVE_cart_0['data'], 0, 4); + $thisfile_riff_WAVE_cart_0['title'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 4, 64)); + $thisfile_riff_WAVE_cart_0['artist'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 68, 64)); + $thisfile_riff_WAVE_cart_0['cut_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 132, 64)); + $thisfile_riff_WAVE_cart_0['client_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 196, 64)); + $thisfile_riff_WAVE_cart_0['category'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 260, 64)); + $thisfile_riff_WAVE_cart_0['classification'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 324, 64)); + $thisfile_riff_WAVE_cart_0['out_cue'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 388, 64)); + $thisfile_riff_WAVE_cart_0['start_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 452, 10)); + $thisfile_riff_WAVE_cart_0['start_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 462, 8)); + $thisfile_riff_WAVE_cart_0['end_date'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 470, 10)); + $thisfile_riff_WAVE_cart_0['end_time'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 480, 8)); + $thisfile_riff_WAVE_cart_0['producer_app_id'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 488, 64)); + $thisfile_riff_WAVE_cart_0['producer_app_version'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 552, 64)); + $thisfile_riff_WAVE_cart_0['user_defined_text'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 616, 64)); + $thisfile_riff_WAVE_cart_0['zero_db_reference'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 680, 4), true); + for ($i = 0; $i < 8; $i++) { + $thisfile_riff_WAVE_cart_0['post_time'][$i]['usage_fourcc'] = substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8), 4); + $thisfile_riff_WAVE_cart_0['post_time'][$i]['timer_value'] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE_cart_0['data'], 684 + ($i * 8) + 4, 4)); + } + $thisfile_riff_WAVE_cart_0['url'] = trim(substr($thisfile_riff_WAVE_cart_0['data'], 748, 1024)); + $thisfile_riff_WAVE_cart_0['tag_text'] = explode("\r\n", trim(substr($thisfile_riff_WAVE_cart_0['data'], 1772))); + + $thisfile_riff['comments']['artist'][] = $thisfile_riff_WAVE_cart_0['artist']; + $thisfile_riff['comments']['title'][] = $thisfile_riff_WAVE_cart_0['title']; + } + + if (isset($thisfile_riff_WAVE['SNDM'][0]['data'])) { + // SoundMiner metadata + + // shortcuts + $thisfile_riff_WAVE_SNDM_0 = &$thisfile_riff_WAVE['SNDM'][0]; + $thisfile_riff_WAVE_SNDM_0_data = &$thisfile_riff_WAVE_SNDM_0['data']; + $SNDM_startoffset = 0; + $SNDM_endoffset = $thisfile_riff_WAVE_SNDM_0['size']; + + while ($SNDM_startoffset < $SNDM_endoffset) { + $SNDM_thisTagOffset = 0; + $SNDM_thisTagSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4)); + $SNDM_thisTagOffset += 4; + $SNDM_thisTagKey = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 4); + $SNDM_thisTagOffset += 4; + $SNDM_thisTagDataSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); + $SNDM_thisTagOffset += 2; + $SNDM_thisTagDataFlags = getid3_lib::BigEndian2Int(substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, 2)); + $SNDM_thisTagOffset += 2; + $SNDM_thisTagDataText = substr($thisfile_riff_WAVE_SNDM_0_data, $SNDM_startoffset + $SNDM_thisTagOffset, $SNDM_thisTagDataSize); + $SNDM_thisTagOffset += $SNDM_thisTagDataSize; + + if ($SNDM_thisTagSize != (4 + 4 + 2 + 2 + $SNDM_thisTagDataSize)) { + $info['warning'][] = 'RIFF.WAVE.SNDM.data contains tag not expected length (expected: '.$SNDM_thisTagSize.', found: '.(4 + 4 + 2 + 2 + $SNDM_thisTagDataSize).') at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; + break; + } elseif ($SNDM_thisTagSize <= 0) { + $info['warning'][] = 'RIFF.WAVE.SNDM.data contains zero-size tag at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; + break; + } + $SNDM_startoffset += $SNDM_thisTagSize; + + $thisfile_riff_WAVE_SNDM_0['parsed_raw'][$SNDM_thisTagKey] = $SNDM_thisTagDataText; + if ($parsedkey = self::waveSNDMtagLookup($SNDM_thisTagKey)) { + $thisfile_riff_WAVE_SNDM_0['parsed'][$parsedkey] = $SNDM_thisTagDataText; + } else { + $info['warning'][] = 'RIFF.WAVE.SNDM contains unknown tag "'.$SNDM_thisTagKey.'" at offset '.$SNDM_startoffset.' (file offset '.($thisfile_riff_WAVE_SNDM_0['offset'] + $SNDM_startoffset).')'; + } + } + + $tagmapping = array( + 'tracktitle'=>'title', + 'category' =>'genre', + 'cdtitle' =>'album', + 'tracktitle'=>'title', + ); + foreach ($tagmapping as $fromkey => $tokey) { + if (isset($thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey])) { + $thisfile_riff['comments'][$tokey][] = $thisfile_riff_WAVE_SNDM_0['parsed'][$fromkey]; + } + } + } + + if (isset($thisfile_riff_WAVE['iXML'][0]['data'])) { + // requires functions simplexml_load_string and get_object_vars + if ($parsedXML = getid3_lib::XML2array($thisfile_riff_WAVE['iXML'][0]['data'])) { + $thisfile_riff_WAVE['iXML'][0]['parsed'] = $parsedXML; + if (isset($parsedXML['SPEED']['MASTER_SPEED'])) { + @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['MASTER_SPEED']); + $thisfile_riff_WAVE['iXML'][0]['master_speed'] = $numerator / ($denominator ? $denominator : 1000); + } + if (isset($parsedXML['SPEED']['TIMECODE_RATE'])) { + @list($numerator, $denominator) = explode('/', $parsedXML['SPEED']['TIMECODE_RATE']); + $thisfile_riff_WAVE['iXML'][0]['timecode_rate'] = $numerator / ($denominator ? $denominator : 1000); + } + if (isset($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO']) && !empty($parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']) && !empty($thisfile_riff_WAVE['iXML'][0]['timecode_rate'])) { + $samples_since_midnight = floatval(ltrim($parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_HI'].$parsedXML['SPEED']['TIMESTAMP_SAMPLES_SINCE_MIDNIGHT_LO'], '0')); + $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] = $samples_since_midnight / $parsedXML['SPEED']['TIMESTAMP_SAMPLE_RATE']; + $h = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] / 3600); + $m = floor(($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600)) / 60); + $s = floor( $thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60)); + $f = ($thisfile_riff_WAVE['iXML'][0]['timecode_seconds'] - ($h * 3600) - ($m * 60) - $s) * $thisfile_riff_WAVE['iXML'][0]['timecode_rate']; + $thisfile_riff_WAVE['iXML'][0]['timecode_string'] = sprintf('%02d:%02d:%02d:%05.2f', $h, $m, $s, $f); + $thisfile_riff_WAVE['iXML'][0]['timecode_string_round'] = sprintf('%02d:%02d:%02d:%02d', $h, $m, $s, round($f)); + } + unset($parsedXML); + } + } + + + + if (!isset($thisfile_audio['bitrate']) && isset($thisfile_riff_audio[$streamindex]['bitrate'])) { + $thisfile_audio['bitrate'] = $thisfile_riff_audio[$streamindex]['bitrate']; + $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $thisfile_audio['bitrate']); + } + + if (!empty($info['wavpack'])) { + $thisfile_audio_dataformat = 'wavpack'; + $thisfile_audio['bitrate_mode'] = 'vbr'; + $thisfile_audio['encoder'] = 'WavPack v'.$info['wavpack']['version']; + + // Reset to the way it was - RIFF parsing will have messed this up + $info['avdataend'] = $Original['avdataend']; + $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + $this->fseek($info['avdataoffset'] - 44); + $RIFFdata = $this->fread(44); + $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; + $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; + + if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) { + $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize); + $this->fseek($info['avdataend']); + $RIFFdata .= $this->fread($OrignalRIFFheaderSize - $OrignalRIFFdataSize); + } + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); + $getid3_riff = new getid3_riff($this->getid3); + $getid3_riff->ParseRIFFdata($RIFFdata); + unset($getid3_riff); + } + + if (isset($thisfile_riff_raw['fmt ']['wFormatTag'])) { + switch ($thisfile_riff_raw['fmt ']['wFormatTag']) { + case 0x0001: // PCM + if (!empty($info['ac3'])) { + // Dolby Digital WAV files masquerade as PCM-WAV, but they're not + $thisfile_audio['wformattag'] = 0x2000; + $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); + $thisfile_audio['lossless'] = false; + $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; + $thisfile_audio['sample_rate'] = $info['ac3']['sample_rate']; + } + if (!empty($info['dts'])) { + // Dolby DTS files masquerade as PCM-WAV, but they're not + $thisfile_audio['wformattag'] = 0x2001; + $thisfile_audio['codec'] = self::wFormatTagLookup($thisfile_audio['wformattag']); + $thisfile_audio['lossless'] = false; + $thisfile_audio['bitrate'] = $info['dts']['bitrate']; + $thisfile_audio['sample_rate'] = $info['dts']['sample_rate']; + } + break; + case 0x08AE: // ClearJump LiteWave + $thisfile_audio['bitrate_mode'] = 'vbr'; + $thisfile_audio_dataformat = 'litewave'; + + //typedef struct tagSLwFormat { + // WORD m_wCompFormat; // low byte defines compression method, high byte is compression flags + // DWORD m_dwScale; // scale factor for lossy compression + // DWORD m_dwBlockSize; // number of samples in encoded blocks + // WORD m_wQuality; // alias for the scale factor + // WORD m_wMarkDistance; // distance between marks in bytes + // WORD m_wReserved; + // + // //following paramters are ignored if CF_FILESRC is not set + // DWORD m_dwOrgSize; // original file size in bytes + // WORD m_bFactExists; // indicates if 'fact' chunk exists in the original file + // DWORD m_dwRiffChunkSize; // riff chunk size in the original file + // + // PCMWAVEFORMAT m_OrgWf; // original wave format + // }SLwFormat, *PSLwFormat; + + // shortcut + $thisfile_riff['litewave']['raw'] = array(); + $riff_litewave = &$thisfile_riff['litewave']; + $riff_litewave_raw = &$riff_litewave['raw']; + + $flags = array( + 'compression_method' => 1, + 'compression_flags' => 1, + 'm_dwScale' => 4, + 'm_dwBlockSize' => 4, + 'm_wQuality' => 2, + 'm_wMarkDistance' => 2, + 'm_wReserved' => 2, + 'm_dwOrgSize' => 4, + 'm_bFactExists' => 2, + 'm_dwRiffChunkSize' => 4, + ); + $litewave_offset = 18; + foreach ($flags as $flag => $length) { + $riff_litewave_raw[$flag] = getid3_lib::LittleEndian2Int(substr($thisfile_riff_WAVE['fmt '][0]['data'], $litewave_offset, $length)); + $litewave_offset += $length; + } + + //$riff_litewave['quality_factor'] = intval(round((2000 - $riff_litewave_raw['m_dwScale']) / 20)); + $riff_litewave['quality_factor'] = $riff_litewave_raw['m_wQuality']; + + $riff_litewave['flags']['raw_source'] = ($riff_litewave_raw['compression_flags'] & 0x01) ? false : true; + $riff_litewave['flags']['vbr_blocksize'] = ($riff_litewave_raw['compression_flags'] & 0x02) ? false : true; + $riff_litewave['flags']['seekpoints'] = (bool) ($riff_litewave_raw['compression_flags'] & 0x04); + + $thisfile_audio['lossless'] = (($riff_litewave_raw['m_wQuality'] == 100) ? true : false); + $thisfile_audio['encoder_options'] = '-q'.$riff_litewave['quality_factor']; + break; + + default: + break; + } + } + if ($info['avdataend'] > $info['filesize']) { + switch (!empty($thisfile_audio_dataformat) ? $thisfile_audio_dataformat : '') { + case 'wavpack': // WavPack + case 'lpac': // LPAC + case 'ofr': // OptimFROG + case 'ofs': // OptimFROG DualStream + // lossless compressed audio formats that keep original RIFF headers - skip warning + break; + + case 'litewave': + if (($info['avdataend'] - $info['filesize']) == 1) { + // LiteWave appears to incorrectly *not* pad actual output file + // to nearest WORD boundary so may appear to be short by one + // byte, in which case - skip warning + } else { + // Short by more than one byte, throw warning + $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; + $info['avdataend'] = $info['filesize']; + } + break; + + default: + if ((($info['avdataend'] - $info['filesize']) == 1) && (($thisfile_riff[$RIFFsubtype]['data'][0]['size'] % 2) == 0) && ((($info['filesize'] - $info['avdataoffset']) % 2) == 1)) { + // output file appears to be incorrectly *not* padded to nearest WORD boundary + // Output less severe warning + $info['warning'][] = 'File should probably be padded to nearest WORD boundary, but it is not (expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' therefore short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; + $info['avdataend'] = $info['filesize']; + } else { + // Short by more than one byte, throw warning + $info['warning'][] = 'Probably truncated file - expecting '.$thisfile_riff[$RIFFsubtype]['data'][0]['size'].' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($thisfile_riff[$RIFFsubtype]['data'][0]['size'] - ($info['filesize'] - $info['avdataoffset'])).' bytes)'; + $info['avdataend'] = $info['filesize']; + } + break; + } + } + if (!empty($info['mpeg']['audio']['LAME']['audio_bytes'])) { + if ((($info['avdataend'] - $info['avdataoffset']) - $info['mpeg']['audio']['LAME']['audio_bytes']) == 1) { + $info['avdataend']--; + $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'; + } + } + if (isset($thisfile_audio_dataformat) && ($thisfile_audio_dataformat == 'ac3')) { + unset($thisfile_audio['bits_per_sample']); + if (!empty($info['ac3']['bitrate']) && ($info['ac3']['bitrate'] != $thisfile_audio['bitrate'])) { + $thisfile_audio['bitrate'] = $info['ac3']['bitrate']; + } + } + break; + + case 'AVI ': + $thisfile_video['bitrate_mode'] = 'vbr'; // maybe not, but probably + $thisfile_video['dataformat'] = 'avi'; + $info['mime_type'] = 'video/avi'; + + if (isset($thisfile_riff[$RIFFsubtype]['movi']['offset'])) { + $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['movi']['offset'] + 8; + if (isset($thisfile_riff['AVIX'])) { + $info['avdataend'] = $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['offset'] + $thisfile_riff['AVIX'][(count($thisfile_riff['AVIX']) - 1)]['chunks']['movi']['size']; + } else { + $info['avdataend'] = $thisfile_riff['AVI ']['movi']['offset'] + $thisfile_riff['AVI ']['movi']['size']; + } + if ($info['avdataend'] > $info['filesize']) { + $info['warning'][] = 'Probably truncated file - expecting '.($info['avdataend'] - $info['avdataoffset']).' bytes of data, only found '.($info['filesize'] - $info['avdataoffset']).' (short by '.($info['avdataend'] - $info['filesize']).' bytes)'; + $info['avdataend'] = $info['filesize']; + } + } + + if (isset($thisfile_riff['AVI ']['hdrl']['strl']['indx'])) { + //$bIndexType = array( + // 0x00 => 'AVI_INDEX_OF_INDEXES', + // 0x01 => 'AVI_INDEX_OF_CHUNKS', + // 0x80 => 'AVI_INDEX_IS_DATA', + //); + //$bIndexSubtype = array( + // 0x01 => array( + // 0x01 => 'AVI_INDEX_2FIELD', + // ), + //); + foreach ($thisfile_riff['AVI ']['hdrl']['strl']['indx'] as $streamnumber => $steamdataarray) { + $ahsisd = &$thisfile_riff['AVI ']['hdrl']['strl']['indx'][$streamnumber]['data']; + + $thisfile_riff_raw['indx'][$streamnumber]['wLongsPerEntry'] = $this->EitherEndian2Int(substr($ahsisd, 0, 2)); + $thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType'] = $this->EitherEndian2Int(substr($ahsisd, 2, 1)); + $thisfile_riff_raw['indx'][$streamnumber]['bIndexType'] = $this->EitherEndian2Int(substr($ahsisd, 3, 1)); + $thisfile_riff_raw['indx'][$streamnumber]['nEntriesInUse'] = $this->EitherEndian2Int(substr($ahsisd, 4, 4)); + $thisfile_riff_raw['indx'][$streamnumber]['dwChunkId'] = substr($ahsisd, 8, 4); + $thisfile_riff_raw['indx'][$streamnumber]['dwReserved'] = $this->EitherEndian2Int(substr($ahsisd, 12, 4)); + + //$thisfile_riff_raw['indx'][$streamnumber]['bIndexType_name'] = $bIndexType[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']]; + //$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType_name'] = $bIndexSubtype[$thisfile_riff_raw['indx'][$streamnumber]['bIndexType']][$thisfile_riff_raw['indx'][$streamnumber]['bIndexSubType']]; + + unset($ahsisd); + } + } + if (isset($thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data'])) { + $avihData = $thisfile_riff['AVI ']['hdrl']['avih'][$streamindex]['data']; + + // shortcut + $thisfile_riff_raw['avih'] = array(); + $thisfile_riff_raw_avih = &$thisfile_riff_raw['avih']; + + $thisfile_riff_raw_avih['dwMicroSecPerFrame'] = $this->EitherEndian2Int(substr($avihData, 0, 4)); // frame display rate (or 0L) + if ($thisfile_riff_raw_avih['dwMicroSecPerFrame'] == 0) { + $info['error'][] = 'Corrupt RIFF file: avih.dwMicroSecPerFrame == zero'; + return false; + } + + $flags = array( + 'dwMaxBytesPerSec', // max. transfer rate + 'dwPaddingGranularity', // pad to multiples of this size; normally 2K. + 'dwFlags', // the ever-present flags + 'dwTotalFrames', // # frames in file + 'dwInitialFrames', // + 'dwStreams', // + 'dwSuggestedBufferSize', // + 'dwWidth', // + 'dwHeight', // + 'dwScale', // + 'dwRate', // + 'dwStart', // + 'dwLength', // + ); + $avih_offset = 4; + foreach ($flags as $flag) { + $thisfile_riff_raw_avih[$flag] = $this->EitherEndian2Int(substr($avihData, $avih_offset, 4)); + $avih_offset += 4; + } + + $flags = array( + 'hasindex' => 0x00000010, + 'mustuseindex' => 0x00000020, + 'interleaved' => 0x00000100, + 'trustcktype' => 0x00000800, + 'capturedfile' => 0x00010000, + 'copyrighted' => 0x00020010, + ); + foreach ($flags as $flag => $value) { + $thisfile_riff_raw_avih['flags'][$flag] = (bool) ($thisfile_riff_raw_avih['dwFlags'] & $value); + } + + // shortcut + $thisfile_riff_video[$streamindex] = array(); + $thisfile_riff_video_current = &$thisfile_riff_video[$streamindex]; + + if ($thisfile_riff_raw_avih['dwWidth'] > 0) { + $thisfile_riff_video_current['frame_width'] = $thisfile_riff_raw_avih['dwWidth']; + $thisfile_video['resolution_x'] = $thisfile_riff_video_current['frame_width']; + } + if ($thisfile_riff_raw_avih['dwHeight'] > 0) { + $thisfile_riff_video_current['frame_height'] = $thisfile_riff_raw_avih['dwHeight']; + $thisfile_video['resolution_y'] = $thisfile_riff_video_current['frame_height']; + } + if ($thisfile_riff_raw_avih['dwTotalFrames'] > 0) { + $thisfile_riff_video_current['total_frames'] = $thisfile_riff_raw_avih['dwTotalFrames']; + $thisfile_video['total_frames'] = $thisfile_riff_video_current['total_frames']; + } + + $thisfile_riff_video_current['frame_rate'] = round(1000000 / $thisfile_riff_raw_avih['dwMicroSecPerFrame'], 3); + $thisfile_video['frame_rate'] = $thisfile_riff_video_current['frame_rate']; + } + if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][0]['data'])) { + if (is_array($thisfile_riff['AVI ']['hdrl']['strl']['strh'])) { + for ($i = 0; $i < count($thisfile_riff['AVI ']['hdrl']['strl']['strh']); $i++) { + if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data'])) { + $strhData = $thisfile_riff['AVI ']['hdrl']['strl']['strh'][$i]['data']; + $strhfccType = substr($strhData, 0, 4); + + if (isset($thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data'])) { + $strfData = $thisfile_riff['AVI ']['hdrl']['strl']['strf'][$i]['data']; + + // shortcut + $thisfile_riff_raw_strf_strhfccType_streamindex = &$thisfile_riff_raw['strf'][$strhfccType][$streamindex]; + + switch ($strhfccType) { + case 'auds': + $thisfile_audio['bitrate_mode'] = 'cbr'; + $thisfile_audio_dataformat = 'wav'; + if (isset($thisfile_riff_audio) && is_array($thisfile_riff_audio)) { + $streamindex = count($thisfile_riff_audio); + } + + $thisfile_riff_audio[$streamindex] = self::parseWAVEFORMATex($strfData); + $thisfile_audio['wformattag'] = $thisfile_riff_audio[$streamindex]['raw']['wFormatTag']; + + // shortcut + $thisfile_audio['streams'][$streamindex] = $thisfile_riff_audio[$streamindex]; + $thisfile_audio_streams_currentstream = &$thisfile_audio['streams'][$streamindex]; + + if ($thisfile_audio_streams_currentstream['bits_per_sample'] == 0) { + unset($thisfile_audio_streams_currentstream['bits_per_sample']); + } + $thisfile_audio_streams_currentstream['wformattag'] = $thisfile_audio_streams_currentstream['raw']['wFormatTag']; + unset($thisfile_audio_streams_currentstream['raw']); + + // shortcut + $thisfile_riff_raw['strf'][$strhfccType][$streamindex] = $thisfile_riff_audio[$streamindex]['raw']; + + unset($thisfile_riff_audio[$streamindex]['raw']); + $thisfile_audio = getid3_lib::array_merge_noclobber($thisfile_audio, $thisfile_riff_audio[$streamindex]); + + $thisfile_audio['lossless'] = false; + switch ($thisfile_riff_raw_strf_strhfccType_streamindex['wFormatTag']) { + case 0x0001: // PCM + $thisfile_audio_dataformat = 'wav'; + $thisfile_audio['lossless'] = true; + break; + + case 0x0050: // MPEG Layer 2 or Layer 1 + $thisfile_audio_dataformat = 'mp2'; // Assume Layer-2 + break; + + case 0x0055: // MPEG Layer 3 + $thisfile_audio_dataformat = 'mp3'; + break; + + case 0x00FF: // AAC + $thisfile_audio_dataformat = 'aac'; + break; + + case 0x0161: // Windows Media v7 / v8 / v9 + case 0x0162: // Windows Media Professional v9 + case 0x0163: // Windows Media Lossess v9 + $thisfile_audio_dataformat = 'wma'; + break; + + case 0x2000: // AC-3 + $thisfile_audio_dataformat = 'ac3'; + break; + + case 0x2001: // DTS + $thisfile_audio_dataformat = 'dts'; + break; + + default: + $thisfile_audio_dataformat = 'wav'; + break; + } + $thisfile_audio_streams_currentstream['dataformat'] = $thisfile_audio_dataformat; + $thisfile_audio_streams_currentstream['lossless'] = $thisfile_audio['lossless']; + $thisfile_audio_streams_currentstream['bitrate_mode'] = $thisfile_audio['bitrate_mode']; + break; + + + case 'iavs': + case 'vids': + // shortcut + $thisfile_riff_raw['strh'][$i] = array(); + $thisfile_riff_raw_strh_current = &$thisfile_riff_raw['strh'][$i]; + + $thisfile_riff_raw_strh_current['fccType'] = substr($strhData, 0, 4); // same as $strhfccType; + $thisfile_riff_raw_strh_current['fccHandler'] = substr($strhData, 4, 4); + $thisfile_riff_raw_strh_current['dwFlags'] = $this->EitherEndian2Int(substr($strhData, 8, 4)); // Contains AVITF_* flags + $thisfile_riff_raw_strh_current['wPriority'] = $this->EitherEndian2Int(substr($strhData, 12, 2)); + $thisfile_riff_raw_strh_current['wLanguage'] = $this->EitherEndian2Int(substr($strhData, 14, 2)); + $thisfile_riff_raw_strh_current['dwInitialFrames'] = $this->EitherEndian2Int(substr($strhData, 16, 4)); + $thisfile_riff_raw_strh_current['dwScale'] = $this->EitherEndian2Int(substr($strhData, 20, 4)); + $thisfile_riff_raw_strh_current['dwRate'] = $this->EitherEndian2Int(substr($strhData, 24, 4)); + $thisfile_riff_raw_strh_current['dwStart'] = $this->EitherEndian2Int(substr($strhData, 28, 4)); + $thisfile_riff_raw_strh_current['dwLength'] = $this->EitherEndian2Int(substr($strhData, 32, 4)); + $thisfile_riff_raw_strh_current['dwSuggestedBufferSize'] = $this->EitherEndian2Int(substr($strhData, 36, 4)); + $thisfile_riff_raw_strh_current['dwQuality'] = $this->EitherEndian2Int(substr($strhData, 40, 4)); + $thisfile_riff_raw_strh_current['dwSampleSize'] = $this->EitherEndian2Int(substr($strhData, 44, 4)); + $thisfile_riff_raw_strh_current['rcFrame'] = $this->EitherEndian2Int(substr($strhData, 48, 4)); + + $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strh_current['fccHandler']); + $thisfile_video['fourcc'] = $thisfile_riff_raw_strh_current['fccHandler']; + if (!$thisfile_riff_video_current['codec'] && isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) && self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { + $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']); + $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; + } + $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; + $thisfile_video['pixel_aspect_ratio'] = (float) 1; + switch ($thisfile_riff_raw_strh_current['fccHandler']) { + case 'HFYU': // Huffman Lossless Codec + case 'IRAW': // Intel YUV Uncompressed + case 'YUY2': // Uncompressed YUV 4:2:2 + $thisfile_video['lossless'] = true; + break; + + default: + $thisfile_video['lossless'] = false; + break; + } + + switch ($strhfccType) { + case 'vids': + $thisfile_riff_raw_strf_strhfccType_streamindex = self::ParseBITMAPINFOHEADER(substr($strfData, 0, 40), ($info['fileformat'] == 'riff')); + $thisfile_video['bits_per_sample'] = $thisfile_riff_raw_strf_strhfccType_streamindex['biBitCount']; + + if ($thisfile_riff_video_current['codec'] == 'DV') { + $thisfile_riff_video_current['dv_type'] = 2; + } + break; + + case 'iavs': + $thisfile_riff_video_current['dv_type'] = 1; + break; + } + break; + + default: + $info['warning'][] = 'Unhandled fccType for stream ('.$i.'): "'.$strhfccType.'"'; + break; + + } + } + } + + if (isset($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc'])) { + + $thisfile_video['fourcc'] = $thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']; + if (self::fourccLookup($thisfile_video['fourcc'])) { + $thisfile_riff_video_current['codec'] = self::fourccLookup($thisfile_video['fourcc']); + $thisfile_video['codec'] = $thisfile_riff_video_current['codec']; + } + + switch ($thisfile_riff_raw_strf_strhfccType_streamindex['fourcc']) { + case 'HFYU': // Huffman Lossless Codec + case 'IRAW': // Intel YUV Uncompressed + case 'YUY2': // Uncompressed YUV 4:2:2 + $thisfile_video['lossless'] = true; + //$thisfile_video['bits_per_sample'] = 24; + break; + + default: + $thisfile_video['lossless'] = false; + //$thisfile_video['bits_per_sample'] = 24; + break; + } + + } + } + } + } + break; + + case 'CDDA': + $thisfile_audio['bitrate_mode'] = 'cbr'; + $thisfile_audio_dataformat = 'cda'; + $thisfile_audio['lossless'] = true; + unset($info['mime_type']); + + $info['avdataoffset'] = 44; + + if (isset($thisfile_riff['CDDA']['fmt '][0]['data'])) { + // shortcut + $thisfile_riff_CDDA_fmt_0 = &$thisfile_riff['CDDA']['fmt '][0]; + + $thisfile_riff_CDDA_fmt_0['unknown1'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 0, 2)); + $thisfile_riff_CDDA_fmt_0['track_num'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 2, 2)); + $thisfile_riff_CDDA_fmt_0['disc_id'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 4, 4)); + $thisfile_riff_CDDA_fmt_0['start_offset_frame'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 8, 4)); + $thisfile_riff_CDDA_fmt_0['playtime_frames'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 12, 4)); + $thisfile_riff_CDDA_fmt_0['unknown6'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 16, 4)); + $thisfile_riff_CDDA_fmt_0['unknown7'] = $this->EitherEndian2Int(substr($thisfile_riff_CDDA_fmt_0['data'], 20, 4)); + + $thisfile_riff_CDDA_fmt_0['start_offset_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['start_offset_frame'] / 75; + $thisfile_riff_CDDA_fmt_0['playtime_seconds'] = (float) $thisfile_riff_CDDA_fmt_0['playtime_frames'] / 75; + $info['comments']['track'] = $thisfile_riff_CDDA_fmt_0['track_num']; + $info['playtime_seconds'] = $thisfile_riff_CDDA_fmt_0['playtime_seconds']; + + // hardcoded data for CD-audio + $thisfile_audio['sample_rate'] = 44100; + $thisfile_audio['channels'] = 2; + $thisfile_audio['bits_per_sample'] = 16; + $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $thisfile_audio['channels'] * $thisfile_audio['bits_per_sample']; + $thisfile_audio['bitrate_mode'] = 'cbr'; + } + break; + + + case 'AIFF': + case 'AIFC': + $thisfile_audio['bitrate_mode'] = 'cbr'; + $thisfile_audio_dataformat = 'aiff'; + $thisfile_audio['lossless'] = true; + $info['mime_type'] = 'audio/x-aiff'; + + if (isset($thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'])) { + $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['SSND'][0]['offset'] + 8; + $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['SSND'][0]['size']; + if ($info['avdataend'] > $info['filesize']) { + if (($info['avdataend'] == ($info['filesize'] + 1)) && (($info['filesize'] % 2) == 1)) { + // structures rounded to 2-byte boundary, but dumb encoders + // forget to pad end of file to make this actually work + } else { + $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['SSND'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; + } + $info['avdataend'] = $info['filesize']; + } + } + + if (isset($thisfile_riff[$RIFFsubtype]['COMM'][0]['data'])) { + + // shortcut + $thisfile_riff_RIFFsubtype_COMM_0_data = &$thisfile_riff[$RIFFsubtype]['COMM'][0]['data']; + + $thisfile_riff_audio['channels'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 0, 2), true); + $thisfile_riff_audio['total_samples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 2, 4), false); + $thisfile_riff_audio['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 6, 2), true); + $thisfile_riff_audio['sample_rate'] = (int) getid3_lib::BigEndian2Float(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 8, 10)); + + if ($thisfile_riff[$RIFFsubtype]['COMM'][0]['size'] > 18) { + $thisfile_riff_audio['codec_fourcc'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 18, 4); + $CodecNameSize = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_COMM_0_data, 22, 1), false); + $thisfile_riff_audio['codec_name'] = substr($thisfile_riff_RIFFsubtype_COMM_0_data, 23, $CodecNameSize); + switch ($thisfile_riff_audio['codec_name']) { + case 'NONE': + $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; + $thisfile_audio['lossless'] = true; + break; + + case '': + switch ($thisfile_riff_audio['codec_fourcc']) { + // http://developer.apple.com/qa/snd/snd07.html + case 'sowt': + $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Little-Endian PCM'; + $thisfile_audio['lossless'] = true; + break; + + case 'twos': + $thisfile_riff_audio['codec_name'] = 'Two\'s Compliment Big-Endian PCM'; + $thisfile_audio['lossless'] = true; + break; + + default: + break; + } + break; + + default: + $thisfile_audio['codec'] = $thisfile_riff_audio['codec_name']; + $thisfile_audio['lossless'] = false; + break; + } + } + + $thisfile_audio['channels'] = $thisfile_riff_audio['channels']; + if ($thisfile_riff_audio['bits_per_sample'] > 0) { + $thisfile_audio['bits_per_sample'] = $thisfile_riff_audio['bits_per_sample']; + } + $thisfile_audio['sample_rate'] = $thisfile_riff_audio['sample_rate']; + if ($thisfile_audio['sample_rate'] == 0) { + $info['error'][] = 'Corrupted AIFF file: sample_rate == zero'; + return false; + } + $info['playtime_seconds'] = $thisfile_riff_audio['total_samples'] / $thisfile_audio['sample_rate']; + } + + if (isset($thisfile_riff[$RIFFsubtype]['COMT'])) { + $offset = 0; + $CommentCount = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); + $offset += 2; + for ($i = 0; $i < $CommentCount; $i++) { + $info['comments_raw'][$i]['timestamp'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 4), false); + $offset += 4; + $info['comments_raw'][$i]['marker_id'] = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), true); + $offset += 2; + $CommentLength = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, 2), false); + $offset += 2; + $info['comments_raw'][$i]['comment'] = substr($thisfile_riff[$RIFFsubtype]['COMT'][0]['data'], $offset, $CommentLength); + $offset += $CommentLength; + + $info['comments_raw'][$i]['timestamp_unix'] = getid3_lib::DateMac2Unix($info['comments_raw'][$i]['timestamp']); + $thisfile_riff['comments']['comment'][] = $info['comments_raw'][$i]['comment']; + } + } + + $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); + foreach ($CommentsChunkNames as $key => $value) { + if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { + $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + } + } +/* + if (isset($thisfile_riff[$RIFFsubtype]['ID3 '])) { + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_id3v2 = new getid3_id3v2($getid3_temp); + $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['ID3 '][0]['offset'] + 8; + if ($thisfile_riff[$RIFFsubtype]['ID3 '][0]['valid'] = $getid3_id3v2->Analyze()) { + $info['id3v2'] = $getid3_temp->info['id3v2']; + } + unset($getid3_temp, $getid3_id3v2); + } +*/ + break; + + case '8SVX': + $thisfile_audio['bitrate_mode'] = 'cbr'; + $thisfile_audio_dataformat = '8svx'; + $thisfile_audio['bits_per_sample'] = 8; + $thisfile_audio['channels'] = 1; // overridden below, if need be + $info['mime_type'] = 'audio/x-aiff'; + + if (isset($thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'])) { + $info['avdataoffset'] = $thisfile_riff[$RIFFsubtype]['BODY'][0]['offset'] + 8; + $info['avdataend'] = $info['avdataoffset'] + $thisfile_riff[$RIFFsubtype]['BODY'][0]['size']; + if ($info['avdataend'] > $info['filesize']) { + $info['warning'][] = 'Probable truncated AIFF file: expecting '.$thisfile_riff[$RIFFsubtype]['BODY'][0]['size'].' bytes of audio data, only '.($info['filesize'] - $info['avdataoffset']).' bytes found'; + } + } + + if (isset($thisfile_riff[$RIFFsubtype]['VHDR'][0]['offset'])) { + // shortcut + $thisfile_riff_RIFFsubtype_VHDR_0 = &$thisfile_riff[$RIFFsubtype]['VHDR'][0]; + + $thisfile_riff_RIFFsubtype_VHDR_0['oneShotHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 0, 4)); + $thisfile_riff_RIFFsubtype_VHDR_0['repeatHiSamples'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 4, 4)); + $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerHiCycle'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 8, 4)); + $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 12, 2)); + $thisfile_riff_RIFFsubtype_VHDR_0['ctOctave'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 14, 1)); + $thisfile_riff_RIFFsubtype_VHDR_0['sCompression'] = getid3_lib::BigEndian2Int(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 15, 1)); + $thisfile_riff_RIFFsubtype_VHDR_0['Volume'] = getid3_lib::FixedPoint16_16(substr($thisfile_riff_RIFFsubtype_VHDR_0['data'], 16, 4)); + + $thisfile_audio['sample_rate'] = $thisfile_riff_RIFFsubtype_VHDR_0['samplesPerSec']; + + switch ($thisfile_riff_RIFFsubtype_VHDR_0['sCompression']) { + case 0: + $thisfile_audio['codec'] = 'Pulse Code Modulation (PCM)'; + $thisfile_audio['lossless'] = true; + $ActualBitsPerSample = 8; + break; + + case 1: + $thisfile_audio['codec'] = 'Fibonacci-delta encoding'; + $thisfile_audio['lossless'] = false; + $ActualBitsPerSample = 4; + break; + + default: + $info['warning'][] = 'Unexpected sCompression value in 8SVX.VHDR chunk - expecting 0 or 1, found "'.sCompression.'"'; + break; + } + } + + if (isset($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'])) { + $ChannelsIndex = getid3_lib::BigEndian2Int(substr($thisfile_riff[$RIFFsubtype]['CHAN'][0]['data'], 0, 4)); + switch ($ChannelsIndex) { + case 6: // Stereo + $thisfile_audio['channels'] = 2; + break; + + case 2: // Left channel only + case 4: // Right channel only + $thisfile_audio['channels'] = 1; + break; + + default: + $info['warning'][] = 'Unexpected value in 8SVX.CHAN chunk - expecting 2 or 4 or 6, found "'.$ChannelsIndex.'"'; + break; + } + + } + + $CommentsChunkNames = array('NAME'=>'title', 'author'=>'artist', '(c) '=>'copyright', 'ANNO'=>'comment'); + foreach ($CommentsChunkNames as $key => $value) { + if (isset($thisfile_riff[$RIFFsubtype][$key][0]['data'])) { + $thisfile_riff['comments'][$value][] = $thisfile_riff[$RIFFsubtype][$key][0]['data']; + } + } + + $thisfile_audio['bitrate'] = $thisfile_audio['sample_rate'] * $ActualBitsPerSample * $thisfile_audio['channels']; + if (!empty($thisfile_audio['bitrate'])) { + $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($thisfile_audio['bitrate'] / 8); + } + break; + + + case 'CDXA': + $info['mime_type'] = 'video/mpeg'; + if (!empty($thisfile_riff['CDXA']['data'][0]['size'])) { + if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.mpeg.php', __FILE__, false)) { + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_mpeg = new getid3_mpeg($getid3_temp); + $getid3_mpeg->Analyze(); + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['video'] = $getid3_temp->info['video']; + $info['mpeg'] = $getid3_temp->info['mpeg']; + $info['warning'] = $getid3_temp->info['warning']; + } + unset($getid3_temp, $getid3_mpeg); + } + } + break; + + + default: + $info['error'][] = 'Unknown RIFF type: expecting one of (WAVE|RMP3|AVI |CDDA|AIFF|AIFC|8SVX|CDXA), found "'.$RIFFsubtype.'" instead'; + unset($info['fileformat']); + break; + } + + switch ($RIFFsubtype) { + case 'WAVE': + case 'AIFF': + case 'AIFC': + $ID3v2_key_good = 'id3 '; + $ID3v2_keys_bad = array('ID3 ', 'tag '); + foreach ($ID3v2_keys_bad as $ID3v2_key_bad) { + if (isset($thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]) && !array_key_exists($ID3v2_key_good, $thisfile_riff[$RIFFsubtype])) { + $thisfile_riff[$RIFFsubtype][$ID3v2_key_good] = $thisfile_riff[$RIFFsubtype][$ID3v2_key_bad]; + $info['warning'][] = 'mapping "'.$ID3v2_key_bad.'" chunk to "'.$ID3v2_key_good.'"'; + } + } + + if (isset($thisfile_riff[$RIFFsubtype]['id3 '])) { + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_id3v2 = new getid3_id3v2($getid3_temp); + $getid3_id3v2->StartingOffset = $thisfile_riff[$RIFFsubtype]['id3 '][0]['offset'] + 8; + if ($thisfile_riff[$RIFFsubtype]['id3 '][0]['valid'] = $getid3_id3v2->Analyze()) { + $info['id3v2'] = $getid3_temp->info['id3v2']; + } + unset($getid3_temp, $getid3_id3v2); + } + break; + } + + if (isset($thisfile_riff_WAVE['DISP']) && is_array($thisfile_riff_WAVE['DISP'])) { + $thisfile_riff['comments']['title'][] = trim(substr($thisfile_riff_WAVE['DISP'][count($thisfile_riff_WAVE['DISP']) - 1]['data'], 4)); + } + if (isset($thisfile_riff_WAVE['INFO']) && is_array($thisfile_riff_WAVE['INFO'])) { + self::parseComments($thisfile_riff_WAVE['INFO'], $thisfile_riff['comments']); + } + if (isset($thisfile_riff['AVI ']['INFO']) && is_array($thisfile_riff['AVI ']['INFO'])) { + self::parseComments($thisfile_riff['AVI ']['INFO'], $thisfile_riff['comments']); + } + + if (empty($thisfile_audio['encoder']) && !empty($info['mpeg']['audio']['LAME']['short_version'])) { + $thisfile_audio['encoder'] = $info['mpeg']['audio']['LAME']['short_version']; + } + + if (!isset($info['playtime_seconds'])) { + $info['playtime_seconds'] = 0; + } + if (isset($thisfile_riff_raw['strh'][0]['dwLength']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { + // needed for >2GB AVIs where 'avih' chunk only lists number of frames in that chunk, not entire movie + $info['playtime_seconds'] = $thisfile_riff_raw['strh'][0]['dwLength'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); + } elseif (isset($thisfile_riff_raw['avih']['dwTotalFrames']) && isset($thisfile_riff_raw['avih']['dwMicroSecPerFrame'])) { + $info['playtime_seconds'] = $thisfile_riff_raw['avih']['dwTotalFrames'] * ($thisfile_riff_raw['avih']['dwMicroSecPerFrame'] / 1000000); + } + + if ($info['playtime_seconds'] > 0) { + if (isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + + if (!isset($info['bitrate'])) { + $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); + } + + } elseif (isset($thisfile_riff_audio) && !isset($thisfile_riff_video)) { + + if (!isset($thisfile_audio['bitrate'])) { + $thisfile_audio['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); + } + + } elseif (!isset($thisfile_riff_audio) && isset($thisfile_riff_video)) { + + if (!isset($thisfile_video['bitrate'])) { + $thisfile_video['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); + } + + } + } + + + if (isset($thisfile_riff_video) && isset($thisfile_audio['bitrate']) && ($thisfile_audio['bitrate'] > 0) && ($info['playtime_seconds'] > 0)) { + + $info['bitrate'] = ((($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8); + $thisfile_audio['bitrate'] = 0; + $thisfile_video['bitrate'] = $info['bitrate']; + foreach ($thisfile_riff_audio as $channelnumber => $audioinfoarray) { + $thisfile_video['bitrate'] -= $audioinfoarray['bitrate']; + $thisfile_audio['bitrate'] += $audioinfoarray['bitrate']; + } + if ($thisfile_video['bitrate'] <= 0) { + unset($thisfile_video['bitrate']); + } + if ($thisfile_audio['bitrate'] <= 0) { + unset($thisfile_audio['bitrate']); + } + } + + if (isset($info['mpeg']['audio'])) { + $thisfile_audio_dataformat = 'mp'.$info['mpeg']['audio']['layer']; + $thisfile_audio['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $thisfile_audio['channels'] = $info['mpeg']['audio']['channels']; + $thisfile_audio['bitrate'] = $info['mpeg']['audio']['bitrate']; + $thisfile_audio['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + if (!empty($info['mpeg']['audio']['codec'])) { + $thisfile_audio['codec'] = $info['mpeg']['audio']['codec'].' '.$thisfile_audio['codec']; + } + if (!empty($thisfile_audio['streams'])) { + foreach ($thisfile_audio['streams'] as $streamnumber => $streamdata) { + if ($streamdata['dataformat'] == $thisfile_audio_dataformat) { + $thisfile_audio['streams'][$streamnumber]['sample_rate'] = $thisfile_audio['sample_rate']; + $thisfile_audio['streams'][$streamnumber]['channels'] = $thisfile_audio['channels']; + $thisfile_audio['streams'][$streamnumber]['bitrate'] = $thisfile_audio['bitrate']; + $thisfile_audio['streams'][$streamnumber]['bitrate_mode'] = $thisfile_audio['bitrate_mode']; + $thisfile_audio['streams'][$streamnumber]['codec'] = $thisfile_audio['codec']; + } + } + } + $getid3_mp3 = new getid3_mp3($this->getid3); + $thisfile_audio['encoder_options'] = $getid3_mp3->GuessEncoderOptions(); + unset($getid3_mp3); + } + + + if (!empty($thisfile_riff_raw['fmt ']['wBitsPerSample']) && ($thisfile_riff_raw['fmt ']['wBitsPerSample'] > 0)) { + switch ($thisfile_audio_dataformat) { + case 'ac3': + // ignore bits_per_sample + break; + + default: + $thisfile_audio['bits_per_sample'] = $thisfile_riff_raw['fmt ']['wBitsPerSample']; + break; + } + } + + + if (empty($thisfile_riff_raw)) { + unset($thisfile_riff['raw']); + } + if (empty($thisfile_riff_audio)) { + unset($thisfile_riff['audio']); + } + if (empty($thisfile_riff_video)) { + unset($thisfile_riff['video']); + } + + return true; + } + + public function ParseRIFF($startoffset, $maxoffset) { + $info = &$this->getid3->info; + + $RIFFchunk = false; + $FoundAllChunksWeNeed = false; + + try { + $this->fseek($startoffset); + $maxoffset = min($maxoffset, $info['avdataend']); + while ($this->ftell() < $maxoffset) { + $chunknamesize = $this->fread(8); + //$chunkname = substr($chunknamesize, 0, 4); + $chunkname = str_replace("\x00", '_', substr($chunknamesize, 0, 4)); // note: chunk names of 4 null bytes do appear to be legal (has been observed inside INFO and PRMI chunks, for example), but makes traversing array keys more difficult + $chunksize = $this->EitherEndian2Int(substr($chunknamesize, 4, 4)); + //if (strlen(trim($chunkname, "\x00")) < 4) { + if (strlen($chunkname) < 4) { + $this->error('Expecting chunk name at offset '.($this->ftell() - 8).' but found nothing. Aborting RIFF parsing.'); + break; + } + if (($chunksize == 0) && ($chunkname != 'JUNK')) { + $this->warning('Chunk ('.$chunkname.') size at offset '.($this->ftell() - 4).' is zero. Aborting RIFF parsing.'); + break; + } + if (($chunksize % 2) != 0) { + // all structures are packed on word boundaries + $chunksize++; + } + + switch ($chunkname) { + case 'LIST': + $listname = $this->fread(4); + if (preg_match('#^(movi|rec )$#i', $listname)) { + $RIFFchunk[$listname]['offset'] = $this->ftell() - 4; + $RIFFchunk[$listname]['size'] = $chunksize; + + if (!$FoundAllChunksWeNeed) { + $WhereWeWere = $this->ftell(); + $AudioChunkHeader = $this->fread(12); + $AudioChunkStreamNum = substr($AudioChunkHeader, 0, 2); + $AudioChunkStreamType = substr($AudioChunkHeader, 2, 2); + $AudioChunkSize = getid3_lib::LittleEndian2Int(substr($AudioChunkHeader, 4, 4)); + + if ($AudioChunkStreamType == 'wb') { + $FirstFourBytes = substr($AudioChunkHeader, 8, 4); + if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', $FirstFourBytes)) { + // MP3 + if (getid3_mp3::MPEGaudioHeaderBytesValid($FirstFourBytes)) { + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; + $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; + $getid3_mp3 = new getid3_mp3($getid3_temp); + $getid3_mp3->getOnlyMPEGaudioInfo($getid3_temp->info['avdataoffset'], false); + if (isset($getid3_temp->info['mpeg']['audio'])) { + $info['mpeg']['audio'] = $getid3_temp->info['mpeg']['audio']; + $info['audio'] = $getid3_temp->info['audio']; + $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + //$info['bitrate'] = $info['audio']['bitrate']; + } + unset($getid3_temp, $getid3_mp3); + } + + } elseif (strpos($FirstFourBytes, getid3_ac3::syncword) === 0) { + + // AC3 + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $this->ftell() - 4; + $getid3_temp->info['avdataend'] = $this->ftell() + $AudioChunkSize; + $getid3_ac3 = new getid3_ac3($getid3_temp); + $getid3_ac3->Analyze(); + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['ac3'] = $getid3_temp->info['ac3']; + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $key => $value) { + $info['warning'][] = $value; + } + } + } + unset($getid3_temp, $getid3_ac3); + } + } + $FoundAllChunksWeNeed = true; + $this->fseek($WhereWeWere); + } + $this->fseek($chunksize - 4, SEEK_CUR); + + } else { + + if (!isset($RIFFchunk[$listname])) { + $RIFFchunk[$listname] = array(); + } + $LISTchunkParent = $listname; + $LISTchunkMaxOffset = $this->ftell() - 4 + $chunksize; + if ($parsedChunk = $this->ParseRIFF($this->ftell(), $LISTchunkMaxOffset)) { + $RIFFchunk[$listname] = array_merge_recursive($RIFFchunk[$listname], $parsedChunk); + } + + } + break; + + default: + if (preg_match('#^[0-9]{2}(wb|pc|dc|db)$#', $chunkname)) { + $this->fseek($chunksize, SEEK_CUR); + break; + } + $thisindex = 0; + if (isset($RIFFchunk[$chunkname]) && is_array($RIFFchunk[$chunkname])) { + $thisindex = count($RIFFchunk[$chunkname]); + } + $RIFFchunk[$chunkname][$thisindex]['offset'] = $this->ftell() - 8; + $RIFFchunk[$chunkname][$thisindex]['size'] = $chunksize; + switch ($chunkname) { + case 'data': + $info['avdataoffset'] = $this->ftell(); + $info['avdataend'] = $info['avdataoffset'] + $chunksize; + + $testData = $this->fread(36); + if ($testData === '') { + break; + } + if (preg_match('/^\xFF[\xE2-\xE7\xF2-\xF7\xFA-\xFF][\x00-\xEB]/s', substr($testData, 0, 4))) { + + // Probably is MP3 data + if (getid3_mp3::MPEGaudioHeaderBytesValid(substr($testData, 0, 4))) { + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_temp->info['avdataend'] = $info['avdataend']; + $getid3_mp3 = new getid3_mp3($getid3_temp); + $getid3_mp3->getOnlyMPEGaudioInfo($info['avdataoffset'], false); + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['mpeg'] = $getid3_temp->info['mpeg']; + } + unset($getid3_temp, $getid3_mp3); + } + + } elseif (($isRegularAC3 = (substr($testData, 0, 2) == getid3_ac3::syncword)) || substr($testData, 8, 2) == strrev(getid3_ac3::syncword)) { + + // This is probably AC-3 data + $getid3_temp = new getID3(); + if ($isRegularAC3) { + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_temp->info['avdataend'] = $info['avdataend']; + } + $getid3_ac3 = new getid3_ac3($getid3_temp); + if ($isRegularAC3) { + $getid3_ac3->Analyze(); + } else { + // Dolby Digital WAV + // AC-3 content, but not encoded in same format as normal AC-3 file + // For one thing, byte order is swapped + $ac3_data = ''; + for ($i = 0; $i < 28; $i += 2) { + $ac3_data .= substr($testData, 8 + $i + 1, 1); + $ac3_data .= substr($testData, 8 + $i + 0, 1); + } + $getid3_ac3->AnalyzeString($ac3_data); + } + + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['ac3'] = $getid3_temp->info['ac3']; + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $newerror) { + $this->warning('getid3_ac3() says: ['.$newerror.']'); + } + } + } + unset($getid3_temp, $getid3_ac3); + + } elseif (preg_match('/^('.implode('|', array_map('preg_quote', getid3_dts::$syncwords)).')/', $testData)) { + + // This is probably DTS data + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_dts = new getid3_dts($getid3_temp); + $getid3_dts->Analyze(); + if (empty($getid3_temp->info['error'])) { + $info['audio'] = $getid3_temp->info['audio']; + $info['dts'] = $getid3_temp->info['dts']; + $info['playtime_seconds'] = $getid3_temp->info['playtime_seconds']; // may not match RIFF calculations since DTS-WAV often used 14/16 bit-word packing + if (!empty($getid3_temp->info['warning'])) { + foreach ($getid3_temp->info['warning'] as $newerror) { + $this->warning('getid3_dts() says: ['.$newerror.']'); + } + } + } + + unset($getid3_temp, $getid3_dts); + + } elseif (substr($testData, 0, 4) == 'wvpk') { + + // This is WavPack data + $info['wavpack']['offset'] = $info['avdataoffset']; + $info['wavpack']['size'] = getid3_lib::LittleEndian2Int(substr($testData, 4, 4)); + $this->parseWavPackHeader(substr($testData, 8, 28)); + + } else { + // This is some other kind of data (quite possibly just PCM) + // do nothing special, just skip it + } + $nextoffset = $info['avdataend']; + $this->fseek($nextoffset); + break; + + case 'iXML': + case 'bext': + case 'cart': + case 'fmt ': + case 'strh': + case 'strf': + case 'indx': + case 'MEXT': + case 'DISP': + // always read data in + case 'JUNK': + // should be: never read data in + // but some programs write their version strings in a JUNK chunk (e.g. VirtualDub, AVIdemux, etc) + if ($chunksize < 1048576) { + if ($chunksize > 0) { + $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); + if ($chunkname == 'JUNK') { + if (preg_match('#^([\\x20-\\x7F]+)#', $RIFFchunk[$chunkname][$thisindex]['data'], $matches)) { + // only keep text characters [chr(32)-chr(127)] + $info['riff']['comments']['junk'][] = trim($matches[1]); + } + // but if nothing there, ignore + // remove the key in either case + unset($RIFFchunk[$chunkname][$thisindex]['data']); + } + } + } else { + $this->warning('Chunk "'.$chunkname.'" at offset '.$this->ftell().' is unexpectedly larger than 1MB (claims to be '.number_format($chunksize).' bytes), skipping data'); + $this->fseek($chunksize, SEEK_CUR); + } + break; + + //case 'IDVX': + // $info['divxtag']['comments'] = self::ParseDIVXTAG($this->fread($chunksize)); + // break; + + default: + if (!empty($LISTchunkParent) && (($RIFFchunk[$chunkname][$thisindex]['offset'] + $RIFFchunk[$chunkname][$thisindex]['size']) <= $LISTchunkMaxOffset)) { + $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['offset'] = $RIFFchunk[$chunkname][$thisindex]['offset']; + $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['size'] = $RIFFchunk[$chunkname][$thisindex]['size']; + unset($RIFFchunk[$chunkname][$thisindex]['offset']); + unset($RIFFchunk[$chunkname][$thisindex]['size']); + if (isset($RIFFchunk[$chunkname][$thisindex]) && empty($RIFFchunk[$chunkname][$thisindex])) { + unset($RIFFchunk[$chunkname][$thisindex]); + } + if (isset($RIFFchunk[$chunkname]) && empty($RIFFchunk[$chunkname])) { + unset($RIFFchunk[$chunkname]); + } + $RIFFchunk[$LISTchunkParent][$chunkname][$thisindex]['data'] = $this->fread($chunksize); + } elseif ($chunksize < 2048) { + // only read data in if smaller than 2kB + $RIFFchunk[$chunkname][$thisindex]['data'] = $this->fread($chunksize); + } else { + $this->fseek($chunksize, SEEK_CUR); + } + break; + } + break; + } + } + + } catch (getid3_exception $e) { + if ($e->getCode() == 10) { + $this->warning('RIFF parser: '.$e->getMessage()); + } else { + throw $e; + } + } + + return $RIFFchunk; + } + + public function ParseRIFFdata(&$RIFFdata) { + $info = &$this->getid3->info; + if ($RIFFdata) { + $tempfile = tempnam(GETID3_TEMP_DIR, 'getID3'); + $fp_temp = fopen($tempfile, 'wb'); + $RIFFdataLength = strlen($RIFFdata); + $NewLengthString = getid3_lib::LittleEndian2String($RIFFdataLength, 4); + for ($i = 0; $i < 4; $i++) { + $RIFFdata[($i + 4)] = $NewLengthString[$i]; + } + fwrite($fp_temp, $RIFFdata); + fclose($fp_temp); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($tempfile); + $getid3_temp->info['filesize'] = $RIFFdataLength; + $getid3_temp->info['filenamepath'] = $info['filenamepath']; + $getid3_temp->info['tags'] = $info['tags']; + $getid3_temp->info['warning'] = $info['warning']; + $getid3_temp->info['error'] = $info['error']; + $getid3_temp->info['comments'] = $info['comments']; + $getid3_temp->info['audio'] = (isset($info['audio']) ? $info['audio'] : array()); + $getid3_temp->info['video'] = (isset($info['video']) ? $info['video'] : array()); + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->Analyze(); + + $info['riff'] = $getid3_temp->info['riff']; + $info['warning'] = $getid3_temp->info['warning']; + $info['error'] = $getid3_temp->info['error']; + $info['tags'] = $getid3_temp->info['tags']; + $info['comments'] = $getid3_temp->info['comments']; + unset($getid3_riff, $getid3_temp); + unlink($tempfile); + } + return false; + } + + public static function parseComments(&$RIFFinfoArray, &$CommentsTargetArray) { + $RIFFinfoKeyLookup = array( + 'IARL'=>'archivallocation', + 'IART'=>'artist', + 'ICDS'=>'costumedesigner', + 'ICMS'=>'commissionedby', + 'ICMT'=>'comment', + 'ICNT'=>'country', + 'ICOP'=>'copyright', + 'ICRD'=>'creationdate', + 'IDIM'=>'dimensions', + 'IDIT'=>'digitizationdate', + 'IDPI'=>'resolution', + 'IDST'=>'distributor', + 'IEDT'=>'editor', + 'IENG'=>'engineers', + 'IFRM'=>'accountofparts', + 'IGNR'=>'genre', + 'IKEY'=>'keywords', + 'ILGT'=>'lightness', + 'ILNG'=>'language', + 'IMED'=>'orignalmedium', + 'IMUS'=>'composer', + 'INAM'=>'title', + 'IPDS'=>'productiondesigner', + 'IPLT'=>'palette', + 'IPRD'=>'product', + 'IPRO'=>'producer', + 'IPRT'=>'part', + 'IRTD'=>'rating', + 'ISBJ'=>'subject', + 'ISFT'=>'software', + 'ISGN'=>'secondarygenre', + 'ISHP'=>'sharpness', + 'ISRC'=>'sourcesupplier', + 'ISRF'=>'digitizationsource', + 'ISTD'=>'productionstudio', + 'ISTR'=>'starring', + 'ITCH'=>'encoded_by', + 'IWEB'=>'url', + 'IWRI'=>'writer', + '____'=>'comment', + ); + foreach ($RIFFinfoKeyLookup as $key => $value) { + if (isset($RIFFinfoArray[$key])) { + foreach ($RIFFinfoArray[$key] as $commentid => $commentdata) { + if (trim($commentdata['data']) != '') { + if (isset($CommentsTargetArray[$value])) { + $CommentsTargetArray[$value][] = trim($commentdata['data']); + } else { + $CommentsTargetArray[$value] = array(trim($commentdata['data'])); + } + } + } + } + } + return true; + } + + public static function parseWAVEFORMATex($WaveFormatExData) { + // shortcut + $WaveFormatEx['raw'] = array(); + $WaveFormatEx_raw = &$WaveFormatEx['raw']; + + $WaveFormatEx_raw['wFormatTag'] = substr($WaveFormatExData, 0, 2); + $WaveFormatEx_raw['nChannels'] = substr($WaveFormatExData, 2, 2); + $WaveFormatEx_raw['nSamplesPerSec'] = substr($WaveFormatExData, 4, 4); + $WaveFormatEx_raw['nAvgBytesPerSec'] = substr($WaveFormatExData, 8, 4); + $WaveFormatEx_raw['nBlockAlign'] = substr($WaveFormatExData, 12, 2); + $WaveFormatEx_raw['wBitsPerSample'] = substr($WaveFormatExData, 14, 2); + if (strlen($WaveFormatExData) > 16) { + $WaveFormatEx_raw['cbSize'] = substr($WaveFormatExData, 16, 2); + } + $WaveFormatEx_raw = array_map('getid3_lib::LittleEndian2Int', $WaveFormatEx_raw); + + $WaveFormatEx['codec'] = self::wFormatTagLookup($WaveFormatEx_raw['wFormatTag']); + $WaveFormatEx['channels'] = $WaveFormatEx_raw['nChannels']; + $WaveFormatEx['sample_rate'] = $WaveFormatEx_raw['nSamplesPerSec']; + $WaveFormatEx['bitrate'] = $WaveFormatEx_raw['nAvgBytesPerSec'] * 8; + $WaveFormatEx['bits_per_sample'] = $WaveFormatEx_raw['wBitsPerSample']; + + return $WaveFormatEx; + } + + public function parseWavPackHeader($WavPackChunkData) { + // typedef struct { + // char ckID [4]; + // long ckSize; + // short version; + // short bits; // added for version 2.00 + // short flags, shift; // added for version 3.00 + // long total_samples, crc, crc2; + // char extension [4], extra_bc, extras [3]; + // } WavpackHeader; + + // shortcut + $info = &$this->getid3->info; + $info['wavpack'] = array(); + $thisfile_wavpack = &$info['wavpack']; + + $thisfile_wavpack['version'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 0, 2)); + if ($thisfile_wavpack['version'] >= 2) { + $thisfile_wavpack['bits'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 2, 2)); + } + if ($thisfile_wavpack['version'] >= 3) { + $thisfile_wavpack['flags_raw'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 4, 2)); + $thisfile_wavpack['shift'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 6, 2)); + $thisfile_wavpack['total_samples'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 8, 4)); + $thisfile_wavpack['crc1'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 12, 4)); + $thisfile_wavpack['crc2'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 16, 4)); + $thisfile_wavpack['extension'] = substr($WavPackChunkData, 20, 4); + $thisfile_wavpack['extra_bc'] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 24, 1)); + for ($i = 0; $i <= 2; $i++) { + $thisfile_wavpack['extras'][] = getid3_lib::LittleEndian2Int(substr($WavPackChunkData, 25 + $i, 1)); + } + + // shortcut + $thisfile_wavpack['flags'] = array(); + $thisfile_wavpack_flags = &$thisfile_wavpack['flags']; + + $thisfile_wavpack_flags['mono'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000001); + $thisfile_wavpack_flags['fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000002); + $thisfile_wavpack_flags['raw_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000004); + $thisfile_wavpack_flags['calc_noise'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000008); + $thisfile_wavpack_flags['high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000010); + $thisfile_wavpack_flags['3_byte_samples'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000020); + $thisfile_wavpack_flags['over_20_bits'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000040); + $thisfile_wavpack_flags['use_wvc'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000080); + $thisfile_wavpack_flags['noiseshaping'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000100); + $thisfile_wavpack_flags['very_fast_mode'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000200); + $thisfile_wavpack_flags['new_high_quality'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000400); + $thisfile_wavpack_flags['cancel_extreme'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x000800); + $thisfile_wavpack_flags['cross_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x001000); + $thisfile_wavpack_flags['new_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x002000); + $thisfile_wavpack_flags['joint_stereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x004000); + $thisfile_wavpack_flags['extra_decorrelation'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x008000); + $thisfile_wavpack_flags['override_noiseshape'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x010000); + $thisfile_wavpack_flags['override_jointstereo'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x020000); + $thisfile_wavpack_flags['copy_source_filetime'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x040000); + $thisfile_wavpack_flags['create_exe'] = (bool) ($thisfile_wavpack['flags_raw'] & 0x080000); + } + + return true; + } + + public static function ParseBITMAPINFOHEADER($BITMAPINFOHEADER, $littleEndian=true) { + + $parsed['biSize'] = substr($BITMAPINFOHEADER, 0, 4); // number of bytes required by the BITMAPINFOHEADER structure + $parsed['biWidth'] = substr($BITMAPINFOHEADER, 4, 4); // width of the bitmap in pixels + $parsed['biHeight'] = substr($BITMAPINFOHEADER, 8, 4); // height of the bitmap in pixels. If biHeight is positive, the bitmap is a 'bottom-up' DIB and its origin is the lower left corner. If biHeight is negative, the bitmap is a 'top-down' DIB and its origin is the upper left corner + $parsed['biPlanes'] = substr($BITMAPINFOHEADER, 12, 2); // number of color planes on the target device. In most cases this value must be set to 1 + $parsed['biBitCount'] = substr($BITMAPINFOHEADER, 14, 2); // Specifies the number of bits per pixels + $parsed['biSizeImage'] = substr($BITMAPINFOHEADER, 20, 4); // size of the bitmap data section of the image (the actual pixel data, excluding BITMAPINFOHEADER and RGBQUAD structures) + $parsed['biXPelsPerMeter'] = substr($BITMAPINFOHEADER, 24, 4); // horizontal resolution, in pixels per metre, of the target device + $parsed['biYPelsPerMeter'] = substr($BITMAPINFOHEADER, 28, 4); // vertical resolution, in pixels per metre, of the target device + $parsed['biClrUsed'] = substr($BITMAPINFOHEADER, 32, 4); // actual number of color indices in the color table used by the bitmap. If this value is zero, the bitmap uses the maximum number of colors corresponding to the value of the biBitCount member for the compression mode specified by biCompression + $parsed['biClrImportant'] = substr($BITMAPINFOHEADER, 36, 4); // number of color indices that are considered important for displaying the bitmap. If this value is zero, all colors are important + $parsed = array_map('getid3_lib::'.($littleEndian ? 'Little' : 'Big').'Endian2Int', $parsed); + + $parsed['fourcc'] = substr($BITMAPINFOHEADER, 16, 4); // compression identifier + + return $parsed; + } + + public static function ParseDIVXTAG($DIVXTAG, $raw=false) { + // structure from "IDivX" source, Form1.frm, by "Greg Frazier of Daemonic Software Group", email: gfrazier@icestorm.net, web: http://dsg.cjb.net/ + // source available at http://files.divx-digest.com/download/c663efe7ef8ad2e90bf4af4d3ea6188a/on0SWN2r/edit/IDivX.zip + // 'Byte Layout: '1111111111111111 + // '32 for Movie - 1 '1111111111111111 + // '28 for Author - 6 '6666666666666666 + // '4 for year - 2 '6666666666662222 + // '3 for genre - 3 '7777777777777777 + // '48 for Comments - 7 '7777777777777777 + // '1 for Rating - 4 '7777777777777777 + // '5 for Future Additions - 0 '333400000DIVXTAG + // '128 bytes total + + static $DIVXTAGgenre = array( + 0 => 'Action', + 1 => 'Action/Adventure', + 2 => 'Adventure', + 3 => 'Adult', + 4 => 'Anime', + 5 => 'Cartoon', + 6 => 'Claymation', + 7 => 'Comedy', + 8 => 'Commercial', + 9 => 'Documentary', + 10 => 'Drama', + 11 => 'Home Video', + 12 => 'Horror', + 13 => 'Infomercial', + 14 => 'Interactive', + 15 => 'Mystery', + 16 => 'Music Video', + 17 => 'Other', + 18 => 'Religion', + 19 => 'Sci Fi', + 20 => 'Thriller', + 21 => 'Western', + ), + $DIVXTAGrating = array( + 0 => 'Unrated', + 1 => 'G', + 2 => 'PG', + 3 => 'PG-13', + 4 => 'R', + 5 => 'NC-17', + ); + + $parsed['title'] = trim(substr($DIVXTAG, 0, 32)); + $parsed['artist'] = trim(substr($DIVXTAG, 32, 28)); + $parsed['year'] = intval(trim(substr($DIVXTAG, 60, 4))); + $parsed['comment'] = trim(substr($DIVXTAG, 64, 48)); + $parsed['genre_id'] = intval(trim(substr($DIVXTAG, 112, 3))); + $parsed['rating_id'] = ord(substr($DIVXTAG, 115, 1)); + //$parsed['padding'] = substr($DIVXTAG, 116, 5); // 5-byte null + //$parsed['magic'] = substr($DIVXTAG, 121, 7); // "DIVXTAG" + + $parsed['genre'] = (isset($DIVXTAGgenre[$parsed['genre_id']]) ? $DIVXTAGgenre[$parsed['genre_id']] : $parsed['genre_id']); + $parsed['rating'] = (isset($DIVXTAGrating[$parsed['rating_id']]) ? $DIVXTAGrating[$parsed['rating_id']] : $parsed['rating_id']); + + if (!$raw) { + unset($parsed['genre_id'], $parsed['rating_id']); + foreach ($parsed as $key => $value) { + if (!$value === '') { + unset($parsed['key']); + } + } + } + + foreach ($parsed as $tag => $value) { + $parsed[$tag] = array($value); + } + + return $parsed; + } + + public static function waveSNDMtagLookup($tagshortname) { + $begin = __LINE__; + + /** This is not a comment! + + ©kwd keywords + ©BPM bpm + ©trt tracktitle + ©des description + ©gen category + ©fin featuredinstrument + ©LID longid + ©bex bwdescription + ©pub publisher + ©cdt cdtitle + ©alb library + ©com composer + + */ + + return getid3_lib::EmbeddedLookup($tagshortname, $begin, __LINE__, __FILE__, 'riff-sndm'); + } + + public static function wFormatTagLookup($wFormatTag) { + + $begin = __LINE__; + + /** This is not a comment! + + 0x0000 Microsoft Unknown Wave Format + 0x0001 Pulse Code Modulation (PCM) + 0x0002 Microsoft ADPCM + 0x0003 IEEE Float + 0x0004 Compaq Computer VSELP + 0x0005 IBM CVSD + 0x0006 Microsoft A-Law + 0x0007 Microsoft mu-Law + 0x0008 Microsoft DTS + 0x0010 OKI ADPCM + 0x0011 Intel DVI/IMA ADPCM + 0x0012 Videologic MediaSpace ADPCM + 0x0013 Sierra Semiconductor ADPCM + 0x0014 Antex Electronics G.723 ADPCM + 0x0015 DSP Solutions DigiSTD + 0x0016 DSP Solutions DigiFIX + 0x0017 Dialogic OKI ADPCM + 0x0018 MediaVision ADPCM + 0x0019 Hewlett-Packard CU + 0x0020 Yamaha ADPCM + 0x0021 Speech Compression Sonarc + 0x0022 DSP Group TrueSpeech + 0x0023 Echo Speech EchoSC1 + 0x0024 Audiofile AF36 + 0x0025 Audio Processing Technology APTX + 0x0026 AudioFile AF10 + 0x0027 Prosody 1612 + 0x0028 LRC + 0x0030 Dolby AC2 + 0x0031 Microsoft GSM 6.10 + 0x0032 MSNAudio + 0x0033 Antex Electronics ADPCME + 0x0034 Control Resources VQLPC + 0x0035 DSP Solutions DigiREAL + 0x0036 DSP Solutions DigiADPCM + 0x0037 Control Resources CR10 + 0x0038 Natural MicroSystems VBXADPCM + 0x0039 Crystal Semiconductor IMA ADPCM + 0x003A EchoSC3 + 0x003B Rockwell ADPCM + 0x003C Rockwell Digit LK + 0x003D Xebec + 0x0040 Antex Electronics G.721 ADPCM + 0x0041 G.728 CELP + 0x0042 MSG723 + 0x0050 MPEG Layer-2 or Layer-1 + 0x0052 RT24 + 0x0053 PAC + 0x0055 MPEG Layer-3 + 0x0059 Lucent G.723 + 0x0060 Cirrus + 0x0061 ESPCM + 0x0062 Voxware + 0x0063 Canopus Atrac + 0x0064 G.726 ADPCM + 0x0065 G.722 ADPCM + 0x0066 DSAT + 0x0067 DSAT Display + 0x0069 Voxware Byte Aligned + 0x0070 Voxware AC8 + 0x0071 Voxware AC10 + 0x0072 Voxware AC16 + 0x0073 Voxware AC20 + 0x0074 Voxware MetaVoice + 0x0075 Voxware MetaSound + 0x0076 Voxware RT29HW + 0x0077 Voxware VR12 + 0x0078 Voxware VR18 + 0x0079 Voxware TQ40 + 0x0080 Softsound + 0x0081 Voxware TQ60 + 0x0082 MSRT24 + 0x0083 G.729A + 0x0084 MVI MV12 + 0x0085 DF G.726 + 0x0086 DF GSM610 + 0x0088 ISIAudio + 0x0089 Onlive + 0x0091 SBC24 + 0x0092 Dolby AC3 SPDIF + 0x0093 MediaSonic G.723 + 0x0094 Aculab PLC Prosody 8kbps + 0x0097 ZyXEL ADPCM + 0x0098 Philips LPCBB + 0x0099 Packed + 0x00FF AAC + 0x0100 Rhetorex ADPCM + 0x0101 IBM mu-law + 0x0102 IBM A-law + 0x0103 IBM AVC Adaptive Differential Pulse Code Modulation (ADPCM) + 0x0111 Vivo G.723 + 0x0112 Vivo Siren + 0x0123 Digital G.723 + 0x0125 Sanyo LD ADPCM + 0x0130 Sipro Lab Telecom ACELP NET + 0x0131 Sipro Lab Telecom ACELP 4800 + 0x0132 Sipro Lab Telecom ACELP 8V3 + 0x0133 Sipro Lab Telecom G.729 + 0x0134 Sipro Lab Telecom G.729A + 0x0135 Sipro Lab Telecom Kelvin + 0x0140 Windows Media Video V8 + 0x0150 Qualcomm PureVoice + 0x0151 Qualcomm HalfRate + 0x0155 Ring Zero Systems TUB GSM + 0x0160 Microsoft Audio 1 + 0x0161 Windows Media Audio V7 / V8 / V9 + 0x0162 Windows Media Audio Professional V9 + 0x0163 Windows Media Audio Lossless V9 + 0x0200 Creative Labs ADPCM + 0x0202 Creative Labs Fastspeech8 + 0x0203 Creative Labs Fastspeech10 + 0x0210 UHER Informatic GmbH ADPCM + 0x0220 Quarterdeck + 0x0230 I-link Worldwide VC + 0x0240 Aureal RAW Sport + 0x0250 Interactive Products HSX + 0x0251 Interactive Products RPELP + 0x0260 Consistent Software CS2 + 0x0270 Sony SCX + 0x0300 Fujitsu FM Towns Snd + 0x0400 BTV Digital + 0x0401 Intel Music Coder + 0x0450 QDesign Music + 0x0680 VME VMPCM + 0x0681 AT&T Labs TPC + 0x08AE ClearJump LiteWave + 0x1000 Olivetti GSM + 0x1001 Olivetti ADPCM + 0x1002 Olivetti CELP + 0x1003 Olivetti SBC + 0x1004 Olivetti OPR + 0x1100 Lernout & Hauspie Codec (0x1100) + 0x1101 Lernout & Hauspie CELP Codec (0x1101) + 0x1102 Lernout & Hauspie SBC Codec (0x1102) + 0x1103 Lernout & Hauspie SBC Codec (0x1103) + 0x1104 Lernout & Hauspie SBC Codec (0x1104) + 0x1400 Norris + 0x1401 AT&T ISIAudio + 0x1500 Soundspace Music Compression + 0x181C VoxWare RT24 Speech + 0x1FC4 NCT Soft ALF2CD (www.nctsoft.com) + 0x2000 Dolby AC3 + 0x2001 Dolby DTS + 0x2002 WAVE_FORMAT_14_4 + 0x2003 WAVE_FORMAT_28_8 + 0x2004 WAVE_FORMAT_COOK + 0x2005 WAVE_FORMAT_DNET + 0x674F Ogg Vorbis 1 + 0x6750 Ogg Vorbis 2 + 0x6751 Ogg Vorbis 3 + 0x676F Ogg Vorbis 1+ + 0x6770 Ogg Vorbis 2+ + 0x6771 Ogg Vorbis 3+ + 0x7A21 GSM-AMR (CBR, no SID) + 0x7A22 GSM-AMR (VBR, including SID) + 0xFFFE WAVE_FORMAT_EXTENSIBLE + 0xFFFF WAVE_FORMAT_DEVELOPMENT + + */ + + return getid3_lib::EmbeddedLookup('0x'.str_pad(strtoupper(dechex($wFormatTag)), 4, '0', STR_PAD_LEFT), $begin, __LINE__, __FILE__, 'riff-wFormatTag'); + } + + public static function fourccLookup($fourcc) { + + $begin = __LINE__; + + /** This is not a comment! + + swot http://developer.apple.com/qa/snd/snd07.html + ____ No Codec (____) + _BIT BI_BITFIELDS (Raw RGB) + _JPG JPEG compressed + _PNG PNG compressed W3C/ISO/IEC (RFC-2083) + _RAW Full Frames (Uncompressed) + _RGB Raw RGB Bitmap + _RL4 RLE 4bpp RGB + _RL8 RLE 8bpp RGB + 3IV1 3ivx MPEG-4 v1 + 3IV2 3ivx MPEG-4 v2 + 3IVX 3ivx MPEG-4 + AASC Autodesk Animator + ABYR Kensington ?ABYR? + AEMI Array Microsystems VideoONE MPEG1-I Capture + AFLC Autodesk Animator FLC + AFLI Autodesk Animator FLI + AMPG Array Microsystems VideoONE MPEG + ANIM Intel RDX (ANIM) + AP41 AngelPotion Definitive + ASV1 Asus Video v1 + ASV2 Asus Video v2 + ASVX Asus Video 2.0 (audio) + AUR2 AuraVision Aura 2 Codec - YUV 4:2:2 + AURA AuraVision Aura 1 Codec - YUV 4:1:1 + AVDJ Independent JPEG Group\'s codec (AVDJ) + AVRN Independent JPEG Group\'s codec (AVRN) + AYUV 4:4:4 YUV (AYUV) + AZPR Quicktime Apple Video (AZPR) + BGR Raw RGB32 + BLZ0 Blizzard DivX MPEG-4 + BTVC Conexant Composite Video + BINK RAD Game Tools Bink Video + BT20 Conexant Prosumer Video + BTCV Conexant Composite Video Codec + BW10 Data Translation Broadway MPEG Capture + CC12 Intel YUV12 + CDVC Canopus DV + CFCC Digital Processing Systems DPS Perception + CGDI Microsoft Office 97 Camcorder Video + CHAM Winnov Caviara Champagne + CJPG Creative WebCam JPEG + CLJR Cirrus Logic YUV 4:1:1 + CMYK Common Data Format in Printing (Colorgraph) + CPLA Weitek 4:2:0 YUV Planar + CRAM Microsoft Video 1 (CRAM) + cvid Radius Cinepak + CVID Radius Cinepak + CWLT Microsoft Color WLT DIB + CYUV Creative Labs YUV + CYUY ATI YUV + D261 H.261 + D263 H.263 + DIB Device Independent Bitmap + DIV1 FFmpeg OpenDivX + DIV2 Microsoft MPEG-4 v1/v2 + DIV3 DivX ;-) MPEG-4 v3.x Low-Motion + DIV4 DivX ;-) MPEG-4 v3.x Fast-Motion + DIV5 DivX MPEG-4 v5.x + DIV6 DivX ;-) (MS MPEG-4 v3.x) + DIVX DivX MPEG-4 v4 (OpenDivX / Project Mayo) + divx DivX MPEG-4 + DMB1 Matrox Rainbow Runner hardware MJPEG + DMB2 Paradigm MJPEG + DSVD ?DSVD? + DUCK Duck TrueMotion 1.0 + DPS0 DPS/Leitch Reality Motion JPEG + DPSC DPS/Leitch PAR Motion JPEG + DV25 Matrox DVCPRO codec + DV50 Matrox DVCPRO50 codec + DVC IEC 61834 and SMPTE 314M (DVC/DV Video) + DVCP IEC 61834 and SMPTE 314M (DVC/DV Video) + DVHD IEC Standard DV 1125 lines @ 30fps / 1250 lines @ 25fps + DVMA Darim Vision DVMPEG (dummy for MPEG compressor) (www.darvision.com) + DVSL IEC Standard DV compressed in SD (SDL) + DVAN ?DVAN? + DVE2 InSoft DVE-2 Videoconferencing + dvsd IEC 61834 and SMPTE 314M DVC/DV Video + DVSD IEC 61834 and SMPTE 314M DVC/DV Video + DVX1 Lucent DVX1000SP Video Decoder + DVX2 Lucent DVX2000S Video Decoder + DVX3 Lucent DVX3000S Video Decoder + DX50 DivX v5 + DXT1 Microsoft DirectX Compressed Texture (DXT1) + DXT2 Microsoft DirectX Compressed Texture (DXT2) + DXT3 Microsoft DirectX Compressed Texture (DXT3) + DXT4 Microsoft DirectX Compressed Texture (DXT4) + DXT5 Microsoft DirectX Compressed Texture (DXT5) + DXTC Microsoft DirectX Compressed Texture (DXTC) + DXTn Microsoft DirectX Compressed Texture (DXTn) + EM2V Etymonix MPEG-2 I-frame (www.etymonix.com) + EKQ0 Elsa ?EKQ0? + ELK0 Elsa ?ELK0? + ESCP Eidos Escape + ETV1 eTreppid Video ETV1 + ETV2 eTreppid Video ETV2 + ETVC eTreppid Video ETVC + FLIC Autodesk FLI/FLC Animation + FLV1 Sorenson Spark + FLV4 On2 TrueMotion VP6 + FRWT Darim Vision Forward Motion JPEG (www.darvision.com) + FRWU Darim Vision Forward Uncompressed (www.darvision.com) + FLJP D-Vision Field Encoded Motion JPEG + FPS1 FRAPS v1 + FRWA SoftLab-Nsk Forward Motion JPEG w/ alpha channel + FRWD SoftLab-Nsk Forward Motion JPEG + FVF1 Iterated Systems Fractal Video Frame + GLZW Motion LZW (gabest@freemail.hu) + GPEG Motion JPEG (gabest@freemail.hu) + GWLT Microsoft Greyscale WLT DIB + H260 Intel ITU H.260 Videoconferencing + H261 Intel ITU H.261 Videoconferencing + H262 Intel ITU H.262 Videoconferencing + H263 Intel ITU H.263 Videoconferencing + H264 Intel ITU H.264 Videoconferencing + H265 Intel ITU H.265 Videoconferencing + H266 Intel ITU H.266 Videoconferencing + H267 Intel ITU H.267 Videoconferencing + H268 Intel ITU H.268 Videoconferencing + H269 Intel ITU H.269 Videoconferencing + HFYU Huffman Lossless Codec + HMCR Rendition Motion Compensation Format (HMCR) + HMRR Rendition Motion Compensation Format (HMRR) + I263 FFmpeg I263 decoder + IF09 Indeo YVU9 ("YVU9 with additional delta-frame info after the U plane") + IUYV Interlaced version of UYVY (www.leadtools.com) + IY41 Interlaced version of Y41P (www.leadtools.com) + IYU1 12 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard + IYU2 24 bit format used in mode 2 of the IEEE 1394 Digital Camera 1.04 spec IEEE standard + IYUV Planar YUV format (8-bpp Y plane, followed by 8-bpp 2×2 U and V planes) + i263 Intel ITU H.263 Videoconferencing (i263) + I420 Intel Indeo 4 + IAN Intel Indeo 4 (RDX) + ICLB InSoft CellB Videoconferencing + IGOR Power DVD + IJPG Intergraph JPEG + ILVC Intel Layered Video + ILVR ITU-T H.263+ + IPDV I-O Data Device Giga AVI DV Codec + IR21 Intel Indeo 2.1 + IRAW Intel YUV Uncompressed + IV30 Intel Indeo 3.0 + IV31 Intel Indeo 3.1 + IV32 Ligos Indeo 3.2 + IV33 Ligos Indeo 3.3 + IV34 Ligos Indeo 3.4 + IV35 Ligos Indeo 3.5 + IV36 Ligos Indeo 3.6 + IV37 Ligos Indeo 3.7 + IV38 Ligos Indeo 3.8 + IV39 Ligos Indeo 3.9 + IV40 Ligos Indeo Interactive 4.0 + IV41 Ligos Indeo Interactive 4.1 + IV42 Ligos Indeo Interactive 4.2 + IV43 Ligos Indeo Interactive 4.3 + IV44 Ligos Indeo Interactive 4.4 + IV45 Ligos Indeo Interactive 4.5 + IV46 Ligos Indeo Interactive 4.6 + IV47 Ligos Indeo Interactive 4.7 + IV48 Ligos Indeo Interactive 4.8 + IV49 Ligos Indeo Interactive 4.9 + IV50 Ligos Indeo Interactive 5.0 + JBYR Kensington ?JBYR? + JPEG Still Image JPEG DIB + JPGL Pegasus Lossless Motion JPEG + KMVC Team17 Software Karl Morton\'s Video Codec + LSVM Vianet Lighting Strike Vmail (Streaming) (www.vianet.com) + LEAD LEAD Video Codec + Ljpg LEAD MJPEG Codec + MDVD Alex MicroDVD Video (hacked MS MPEG-4) (www.tiasoft.de) + MJPA Morgan Motion JPEG (MJPA) (www.morgan-multimedia.com) + MJPB Morgan Motion JPEG (MJPB) (www.morgan-multimedia.com) + MMES Matrox MPEG-2 I-frame + MP2v Microsoft S-Mpeg 4 version 1 (MP2v) + MP42 Microsoft S-Mpeg 4 version 2 (MP42) + MP43 Microsoft S-Mpeg 4 version 3 (MP43) + MP4S Microsoft S-Mpeg 4 version 3 (MP4S) + MP4V FFmpeg MPEG-4 + MPG1 FFmpeg MPEG 1/2 + MPG2 FFmpeg MPEG 1/2 + MPG3 FFmpeg DivX ;-) (MS MPEG-4 v3) + MPG4 Microsoft MPEG-4 + MPGI Sigma Designs MPEG + MPNG PNG images decoder + MSS1 Microsoft Windows Screen Video + MSZH LCL (Lossless Codec Library) (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) + M261 Microsoft H.261 + M263 Microsoft H.263 + M4S2 Microsoft Fully Compliant MPEG-4 v2 simple profile (M4S2) + m4s2 Microsoft Fully Compliant MPEG-4 v2 simple profile (m4s2) + MC12 ATI Motion Compensation Format (MC12) + MCAM ATI Motion Compensation Format (MCAM) + MJ2C Morgan Multimedia Motion JPEG2000 + mJPG IBM Motion JPEG w/ Huffman Tables + MJPG Microsoft Motion JPEG DIB + MP42 Microsoft MPEG-4 (low-motion) + MP43 Microsoft MPEG-4 (fast-motion) + MP4S Microsoft MPEG-4 (MP4S) + mp4s Microsoft MPEG-4 (mp4s) + MPEG Chromatic Research MPEG-1 Video I-Frame + MPG4 Microsoft MPEG-4 Video High Speed Compressor + MPGI Sigma Designs MPEG + MRCA FAST Multimedia Martin Regen Codec + MRLE Microsoft Run Length Encoding + MSVC Microsoft Video 1 + MTX1 Matrox ?MTX1? + MTX2 Matrox ?MTX2? + MTX3 Matrox ?MTX3? + MTX4 Matrox ?MTX4? + MTX5 Matrox ?MTX5? + MTX6 Matrox ?MTX6? + MTX7 Matrox ?MTX7? + MTX8 Matrox ?MTX8? + MTX9 Matrox ?MTX9? + MV12 Motion Pixels Codec (old) + MWV1 Aware Motion Wavelets + nAVI SMR Codec (hack of Microsoft MPEG-4) (IRC #shadowrealm) + NT00 NewTek LightWave HDTV YUV w/ Alpha (www.newtek.com) + NUV1 NuppelVideo + NTN1 Nogatech Video Compression 1 + NVS0 nVidia GeForce Texture (NVS0) + NVS1 nVidia GeForce Texture (NVS1) + NVS2 nVidia GeForce Texture (NVS2) + NVS3 nVidia GeForce Texture (NVS3) + NVS4 nVidia GeForce Texture (NVS4) + NVS5 nVidia GeForce Texture (NVS5) + NVT0 nVidia GeForce Texture (NVT0) + NVT1 nVidia GeForce Texture (NVT1) + NVT2 nVidia GeForce Texture (NVT2) + NVT3 nVidia GeForce Texture (NVT3) + NVT4 nVidia GeForce Texture (NVT4) + NVT5 nVidia GeForce Texture (NVT5) + PIXL MiroXL, Pinnacle PCTV + PDVC I-O Data Device Digital Video Capture DV codec + PGVV Radius Video Vision + PHMO IBM Photomotion + PIM1 MPEG Realtime (Pinnacle Cards) + PIM2 Pegasus Imaging ?PIM2? + PIMJ Pegasus Imaging Lossless JPEG + PVEZ Horizons Technology PowerEZ + PVMM PacketVideo Corporation MPEG-4 + PVW2 Pegasus Imaging Wavelet Compression + Q1.0 Q-Team\'s QPEG 1.0 (www.q-team.de) + Q1.1 Q-Team\'s QPEG 1.1 (www.q-team.de) + QPEG Q-Team QPEG 1.0 + qpeq Q-Team QPEG 1.1 + RGB Raw BGR32 + RGBA Raw RGB w/ Alpha + RMP4 REALmagic MPEG-4 (unauthorized XVID copy) (www.sigmadesigns.com) + ROQV Id RoQ File Video Decoder + RPZA Quicktime Apple Video (RPZA) + RUD0 Rududu video codec (http://rududu.ifrance.com/rududu/) + RV10 RealVideo 1.0 (aka RealVideo 5.0) + RV13 RealVideo 1.0 (RV13) + RV20 RealVideo G2 + RV30 RealVideo 8 + RV40 RealVideo 9 + RGBT Raw RGB w/ Transparency + RLE Microsoft Run Length Encoder + RLE4 Run Length Encoded (4bpp, 16-color) + RLE8 Run Length Encoded (8bpp, 256-color) + RT21 Intel Indeo RealTime Video 2.1 + rv20 RealVideo G2 + rv30 RealVideo 8 + RVX Intel RDX (RVX ) + SMC Apple Graphics (SMC ) + SP54 Logitech Sunplus Sp54 Codec for Mustek GSmart Mini 2 + SPIG Radius Spigot + SVQ3 Sorenson Video 3 (Apple Quicktime 5) + s422 Tekram VideoCap C210 YUV 4:2:2 + SDCC Sun Communication Digital Camera Codec + SFMC CrystalNet Surface Fitting Method + SMSC Radius SMSC + SMSD Radius SMSD + smsv WorldConnect Wavelet Video + SPIG Radius Spigot + SPLC Splash Studios ACM Audio Codec (www.splashstudios.net) + SQZ2 Microsoft VXTreme Video Codec V2 + STVA ST Microelectronics CMOS Imager Data (Bayer) + STVB ST Microelectronics CMOS Imager Data (Nudged Bayer) + STVC ST Microelectronics CMOS Imager Data (Bunched) + STVX ST Microelectronics CMOS Imager Data (Extended CODEC Data Format) + STVY ST Microelectronics CMOS Imager Data (Extended CODEC Data Format with Correction Data) + SV10 Sorenson Video R1 + SVQ1 Sorenson Video + T420 Toshiba YUV 4:2:0 + TM2A Duck TrueMotion Archiver 2.0 (www.duck.com) + TVJP Pinnacle/Truevision Targa 2000 board (TVJP) + TVMJ Pinnacle/Truevision Targa 2000 board (TVMJ) + TY0N Tecomac Low-Bit Rate Codec (www.tecomac.com) + TY2C Trident Decompression Driver + TLMS TeraLogic Motion Intraframe Codec (TLMS) + TLST TeraLogic Motion Intraframe Codec (TLST) + TM20 Duck TrueMotion 2.0 + TM2X Duck TrueMotion 2X + TMIC TeraLogic Motion Intraframe Codec (TMIC) + TMOT Horizons Technology TrueMotion S + tmot Horizons TrueMotion Video Compression + TR20 Duck TrueMotion RealTime 2.0 + TSCC TechSmith Screen Capture Codec + TV10 Tecomac Low-Bit Rate Codec + TY2N Trident ?TY2N? + U263 UB Video H.263/H.263+/H.263++ Decoder + UMP4 UB Video MPEG 4 (www.ubvideo.com) + UYNV Nvidia UYVY packed 4:2:2 + UYVP Evans & Sutherland YCbCr 4:2:2 extended precision + UCOD eMajix.com ClearVideo + ULTI IBM Ultimotion + UYVY UYVY packed 4:2:2 + V261 Lucent VX2000S + VIFP VFAPI Reader Codec (www.yks.ne.jp/~hori/) + VIV1 FFmpeg H263+ decoder + VIV2 Vivo H.263 + VQC2 Vector-quantised codec 2 (research) http://eprints.ecs.soton.ac.uk/archive/00001310/01/VTC97-js.pdf) + VTLP Alaris VideoGramPiX + VYU9 ATI YUV (VYU9) + VYUY ATI YUV (VYUY) + V261 Lucent VX2000S + V422 Vitec Multimedia 24-bit YUV 4:2:2 Format + V655 Vitec Multimedia 16-bit YUV 4:2:2 Format + VCR1 ATI Video Codec 1 + VCR2 ATI Video Codec 2 + VCR3 ATI VCR 3.0 + VCR4 ATI VCR 4.0 + VCR5 ATI VCR 5.0 + VCR6 ATI VCR 6.0 + VCR7 ATI VCR 7.0 + VCR8 ATI VCR 8.0 + VCR9 ATI VCR 9.0 + VDCT Vitec Multimedia Video Maker Pro DIB + VDOM VDOnet VDOWave + VDOW VDOnet VDOLive (H.263) + VDTZ Darim Vison VideoTizer YUV + VGPX Alaris VideoGramPiX + VIDS Vitec Multimedia YUV 4:2:2 CCIR 601 for V422 + VIVO Vivo H.263 v2.00 + vivo Vivo H.263 + VIXL Miro/Pinnacle Video XL + VLV1 VideoLogic/PURE Digital Videologic Capture + VP30 On2 VP3.0 + VP31 On2 VP3.1 + VP6F On2 TrueMotion VP6 + VX1K Lucent VX1000S Video Codec + VX2K Lucent VX2000S Video Codec + VXSP Lucent VX1000SP Video Codec + WBVC Winbond W9960 + WHAM Microsoft Video 1 (WHAM) + WINX Winnov Software Compression + WJPG AverMedia Winbond JPEG + WMV1 Windows Media Video V7 + WMV2 Windows Media Video V8 + WMV3 Windows Media Video V9 + WNV1 Winnov Hardware Compression + XYZP Extended PAL format XYZ palette (www.riff.org) + x263 Xirlink H.263 + XLV0 NetXL Video Decoder + XMPG Xing MPEG (I-Frame only) + XVID XviD MPEG-4 (www.xvid.org) + XXAN ?XXAN? + YU92 Intel YUV (YU92) + YUNV Nvidia Uncompressed YUV 4:2:2 + YUVP Extended PAL format YUV palette (www.riff.org) + Y211 YUV 2:1:1 Packed + Y411 YUV 4:1:1 Packed + Y41B Weitek YUV 4:1:1 Planar + Y41P Brooktree PC1 YUV 4:1:1 Packed + Y41T Brooktree PC1 YUV 4:1:1 with transparency + Y42B Weitek YUV 4:2:2 Planar + Y42T Brooktree UYUV 4:2:2 with transparency + Y422 ADS Technologies Copy of UYVY used in Pyro WebCam firewire camera + Y800 Simple, single Y plane for monochrome images + Y8 Grayscale video + YC12 Intel YUV 12 codec + YUV8 Winnov Caviar YUV8 + YUV9 Intel YUV9 + YUY2 Uncompressed YUV 4:2:2 + YUYV Canopus YUV + YV12 YVU12 Planar + YVU9 Intel YVU9 Planar (8-bpp Y plane, followed by 8-bpp 4x4 U and V planes) + YVYU YVYU 4:2:2 Packed + ZLIB Lossless Codec Library zlib compression (www.geocities.co.jp/Playtown-Denei/2837/LRC.htm) + ZPEG Metheus Video Zipper + + */ + + return getid3_lib::EmbeddedLookup($fourcc, $begin, __LINE__, __FILE__, 'riff-fourcc'); + } + + private function EitherEndian2Int($byteword, $signed=false) { + if ($this->getid3->info['fileformat'] == 'riff') { + return getid3_lib::LittleEndian2Int($byteword, $signed); + } + return getid3_lib::BigEndian2Int($byteword, false, $signed); + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.swf.php b/app/libs/vendor/getid3/module.audio-video.swf.php index d2e288c8..48491cbf 100644 --- a/app/libs/vendor/getid3/module.audio-video.swf.php +++ b/app/libs/vendor/getid3/module.audio-video.swf.php @@ -1,139 +1,139 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.swf.php // -// module for analyzing Shockwave Flash files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_swf extends getid3_handler -{ - public $ReturnAllTagData = false; - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'swf'; - $info['video']['dataformat'] = 'swf'; - - // http://www.openswf.org/spec/SWFfileformat.html - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $SWFfileData = fread($this->getid3->fp, $info['avdataend'] - $info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data - - $info['swf']['header']['signature'] = substr($SWFfileData, 0, 3); - switch ($info['swf']['header']['signature']) { - case 'FWS': - $info['swf']['header']['compressed'] = false; - break; - - case 'CWS': - $info['swf']['header']['compressed'] = true; - break; - - default: - $info['error'][] = 'Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"'; - unset($info['swf']); - unset($info['fileformat']); - return false; - break; - } - $info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1)); - $info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4)); - - if ($info['swf']['header']['compressed']) { - $SWFHead = substr($SWFfileData, 0, 8); - $SWFfileData = substr($SWFfileData, 8); - if ($decompressed = @gzuncompress($SWFfileData)) { - $SWFfileData = $SWFHead.$decompressed; - } else { - $info['error'][] = 'Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)'; - return false; - } - } - - $FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3; - $FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8); - $FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT); - for ($i = 1; $i < $FrameSizeDataLength; $i++) { - $FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT); - } - list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1)); - $info['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2); - $info['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2); - - // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm - // Next in the header is the frame rate, which is kind of weird. - // It is supposed to be stored as a 16bit integer, but the first byte - // (or last depending on how you look at it) is completely ignored. - // Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps. - - // Byte at (8 + $FrameSizeDataLength) is always zero and ignored - $info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1)); - $info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2)); - - $info['video']['frame_rate'] = $info['swf']['header']['frame_rate']; - $info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20)); - $info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20)); - $info['video']['pixel_aspect_ratio'] = (float) 1; - - if (($info['swf']['header']['frame_count'] > 0) && ($info['swf']['header']['frame_rate'] > 0)) { - $info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate']; - } -//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
    '; - - - // SWF tags - - $CurrentOffset = 12 + $FrameSizeDataLength; - $SWFdataLength = strlen($SWFfileData); - - while ($CurrentOffset < $SWFdataLength) { -//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
    '; - - $TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2)); - $TagID = ($TagIDTagLength & 0xFFFC) >> 6; - $TagLength = ($TagIDTagLength & 0x003F); - $CurrentOffset += 2; - if ($TagLength == 0x3F) { - $TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4)); - $CurrentOffset += 4; - } - - unset($TagData); - $TagData['offset'] = $CurrentOffset; - $TagData['size'] = $TagLength; - $TagData['id'] = $TagID; - $TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength); - switch ($TagID) { - case 0: // end of movie - break 2; - - case 9: // Set background color - //$info['swf']['tags'][] = $TagData; - $info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT)); - break; - - default: - if ($this->ReturnAllTagData) { - $info['swf']['tags'][] = $TagData; - } - break; - } - - $CurrentOffset += $TagLength; - } - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.swf.php // +// module for analyzing Shockwave Flash files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_swf extends getid3_handler +{ + public $ReturnAllTagData = false; + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'swf'; + $info['video']['dataformat'] = 'swf'; + + // http://www.openswf.org/spec/SWFfileformat.html + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $SWFfileData = fread($this->getid3->fp, $info['avdataend'] - $info['avdataoffset']); // 8 + 2 + 2 + max(9) bytes NOT including Frame_Size RECT data + + $info['swf']['header']['signature'] = substr($SWFfileData, 0, 3); + switch ($info['swf']['header']['signature']) { + case 'FWS': + $info['swf']['header']['compressed'] = false; + break; + + case 'CWS': + $info['swf']['header']['compressed'] = true; + break; + + default: + $info['error'][] = 'Expecting "FWS" or "CWS" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['swf']['header']['signature']).'"'; + unset($info['swf']); + unset($info['fileformat']); + return false; + break; + } + $info['swf']['header']['version'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 3, 1)); + $info['swf']['header']['length'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 4, 4)); + + if ($info['swf']['header']['compressed']) { + $SWFHead = substr($SWFfileData, 0, 8); + $SWFfileData = substr($SWFfileData, 8); + if ($decompressed = @gzuncompress($SWFfileData)) { + $SWFfileData = $SWFHead.$decompressed; + } else { + $info['error'][] = 'Error decompressing compressed SWF data ('.strlen($SWFfileData).' bytes compressed, should be '.($info['swf']['header']['length'] - 8).' bytes uncompressed)'; + return false; + } + } + + $FrameSizeBitsPerValue = (ord(substr($SWFfileData, 8, 1)) & 0xF8) >> 3; + $FrameSizeDataLength = ceil((5 + (4 * $FrameSizeBitsPerValue)) / 8); + $FrameSizeDataString = str_pad(decbin(ord(substr($SWFfileData, 8, 1)) & 0x07), 3, '0', STR_PAD_LEFT); + for ($i = 1; $i < $FrameSizeDataLength; $i++) { + $FrameSizeDataString .= str_pad(decbin(ord(substr($SWFfileData, 8 + $i, 1))), 8, '0', STR_PAD_LEFT); + } + list($X1, $X2, $Y1, $Y2) = explode("\n", wordwrap($FrameSizeDataString, $FrameSizeBitsPerValue, "\n", 1)); + $info['swf']['header']['frame_width'] = getid3_lib::Bin2Dec($X2); + $info['swf']['header']['frame_height'] = getid3_lib::Bin2Dec($Y2); + + // http://www-lehre.informatik.uni-osnabrueck.de/~fbstark/diplom/docs/swf/Flash_Uncovered.htm + // Next in the header is the frame rate, which is kind of weird. + // It is supposed to be stored as a 16bit integer, but the first byte + // (or last depending on how you look at it) is completely ignored. + // Example: 0x000C -> 0x0C -> 12 So the frame rate is 12 fps. + + // Byte at (8 + $FrameSizeDataLength) is always zero and ignored + $info['swf']['header']['frame_rate'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 9 + $FrameSizeDataLength, 1)); + $info['swf']['header']['frame_count'] = getid3_lib::LittleEndian2Int(substr($SWFfileData, 10 + $FrameSizeDataLength, 2)); + + $info['video']['frame_rate'] = $info['swf']['header']['frame_rate']; + $info['video']['resolution_x'] = intval(round($info['swf']['header']['frame_width'] / 20)); + $info['video']['resolution_y'] = intval(round($info['swf']['header']['frame_height'] / 20)); + $info['video']['pixel_aspect_ratio'] = (float) 1; + + if (($info['swf']['header']['frame_count'] > 0) && ($info['swf']['header']['frame_rate'] > 0)) { + $info['playtime_seconds'] = $info['swf']['header']['frame_count'] / $info['swf']['header']['frame_rate']; + } +//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
    '; + + + // SWF tags + + $CurrentOffset = 12 + $FrameSizeDataLength; + $SWFdataLength = strlen($SWFfileData); + + while ($CurrentOffset < $SWFdataLength) { +//echo __LINE__.'='.number_format(microtime(true) - $start_time, 3).'
    '; + + $TagIDTagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 2)); + $TagID = ($TagIDTagLength & 0xFFFC) >> 6; + $TagLength = ($TagIDTagLength & 0x003F); + $CurrentOffset += 2; + if ($TagLength == 0x3F) { + $TagLength = getid3_lib::LittleEndian2Int(substr($SWFfileData, $CurrentOffset, 4)); + $CurrentOffset += 4; + } + + unset($TagData); + $TagData['offset'] = $CurrentOffset; + $TagData['size'] = $TagLength; + $TagData['id'] = $TagID; + $TagData['data'] = substr($SWFfileData, $CurrentOffset, $TagLength); + switch ($TagID) { + case 0: // end of movie + break 2; + + case 9: // Set background color + //$info['swf']['tags'][] = $TagData; + $info['swf']['bgcolor'] = strtoupper(str_pad(dechex(getid3_lib::BigEndian2Int($TagData['data'])), 6, '0', STR_PAD_LEFT)); + break; + + default: + if ($this->ReturnAllTagData) { + $info['swf']['tags'][] = $TagData; + } + break; + } + + $CurrentOffset += $TagLength; + } + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio-video.ts.php b/app/libs/vendor/getid3/module.audio-video.ts.php index 3aabad4f..3fcf71ea 100644 --- a/app/libs/vendor/getid3/module.audio-video.ts.php +++ b/app/libs/vendor/getid3/module.audio-video.ts.php @@ -1,78 +1,78 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio-video.ts.php // -// module for analyzing MPEG Transport Stream (.ts) files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_ts extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $TSheader = fread($this->getid3->fp, 19); - $magic = "\x47"; - if (substr($TSheader, 0, 1) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.'; - return false; - } - $info['fileformat'] = 'ts'; - - // http://en.wikipedia.org/wiki/.ts - - $offset = 0; - $info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; - $pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; - $SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; - $info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error - $info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only. - $info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID. - $info['ts']['packet']['packet_id'] = ($pid_flags_raw & 0x1FFF) >> 0; - - $info['ts']['packet']['raw']['scrambling_control'] = ($SAC_raw & 0xC0) >> 6; - $info['ts']['packet']['flags']['adaption_field_exists'] = (bool) ($SAC_raw & 0x20); - $info['ts']['packet']['flags']['payload_exists'] = (bool) ($SAC_raw & 0x10); - $info['ts']['packet']['continuity_counter'] = ($SAC_raw & 0x0F) >> 0; // Incremented only when a payload is present - $info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']); - - if ($info['ts']['packet']['flags']['adaption_field_exists']) { - $AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; - $info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte - $info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference - $info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence - $info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020); // 1 = higher priority - $info['ts']['packet']['adaption']['flags']['pcr'] = (bool) ($AdaptionField_raw & 0x0010); // 1 means adaptation field does contain a PCR field - $info['ts']['packet']['adaption']['flags']['opcr'] = (bool) ($AdaptionField_raw & 0x0008); // 1 means adaptation field does contain an OPCR field - $info['ts']['packet']['adaption']['flags']['splice_point'] = (bool) ($AdaptionField_raw & 0x0004); // 1 means presence of splice countdown field in adaptation field - $info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field - $info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension - if ($info['ts']['packet']['adaption']['flags']['pcr']) { - $info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; - } - if ($info['ts']['packet']['adaption']['flags']['opcr']) { - $info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; - } - } - -$info['error'][] = 'MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - - } - - - public function TSscramblingControlLookup($raw) { - $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key'); - return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid'); - } -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio-video.ts.php // +// module for analyzing MPEG Transport Stream (.ts) files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_ts extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $TSheader = fread($this->getid3->fp, 19); + $magic = "\x47"; + if (substr($TSheader, 0, 1) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($TSheader, 0, 1)).' instead.'; + return false; + } + $info['fileformat'] = 'ts'; + + // http://en.wikipedia.org/wiki/.ts + + $offset = 0; + $info['ts']['packet']['sync'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; + $pid_flags_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; + $SAC_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 1)); $offset += 1; + $info['ts']['packet']['flags']['transport_error_indicator'] = (bool) ($pid_flags_raw & 0x8000); // Set by demodulator if can't correct errors in the stream, to tell the demultiplexer that the packet has an uncorrectable error + $info['ts']['packet']['flags']['payload_unit_start_indicator'] = (bool) ($pid_flags_raw & 0x4000); // 1 means start of PES data or PSI otherwise zero only. + $info['ts']['packet']['flags']['transport_high_priority'] = (bool) ($pid_flags_raw & 0x2000); // 1 means higher priority than other packets with the same PID. + $info['ts']['packet']['packet_id'] = ($pid_flags_raw & 0x1FFF) >> 0; + + $info['ts']['packet']['raw']['scrambling_control'] = ($SAC_raw & 0xC0) >> 6; + $info['ts']['packet']['flags']['adaption_field_exists'] = (bool) ($SAC_raw & 0x20); + $info['ts']['packet']['flags']['payload_exists'] = (bool) ($SAC_raw & 0x10); + $info['ts']['packet']['continuity_counter'] = ($SAC_raw & 0x0F) >> 0; // Incremented only when a payload is present + $info['ts']['packet']['scrambling_control'] = $this->TSscramblingControlLookup($info['ts']['packet']['raw']['scrambling_control']); + + if ($info['ts']['packet']['flags']['adaption_field_exists']) { + $AdaptionField_raw = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 2)); $offset += 2; + $info['ts']['packet']['adaption']['field_length'] = ($AdaptionField_raw & 0xFF00) >> 8; // Number of bytes in the adaptation field immediately following this byte + $info['ts']['packet']['adaption']['flags']['discontinuity'] = (bool) ($AdaptionField_raw & 0x0080); // Set to 1 if current TS packet is in a discontinuity state with respect to either the continuity counter or the program clock reference + $info['ts']['packet']['adaption']['flags']['random_access'] = (bool) ($AdaptionField_raw & 0x0040); // Set to 1 if the PES packet in this TS packet starts a video/audio sequence + $info['ts']['packet']['adaption']['flags']['high_priority'] = (bool) ($AdaptionField_raw & 0x0020); // 1 = higher priority + $info['ts']['packet']['adaption']['flags']['pcr'] = (bool) ($AdaptionField_raw & 0x0010); // 1 means adaptation field does contain a PCR field + $info['ts']['packet']['adaption']['flags']['opcr'] = (bool) ($AdaptionField_raw & 0x0008); // 1 means adaptation field does contain an OPCR field + $info['ts']['packet']['adaption']['flags']['splice_point'] = (bool) ($AdaptionField_raw & 0x0004); // 1 means presence of splice countdown field in adaptation field + $info['ts']['packet']['adaption']['flags']['private_data'] = (bool) ($AdaptionField_raw & 0x0002); // 1 means presence of private data bytes in adaptation field + $info['ts']['packet']['adaption']['flags']['extension'] = (bool) ($AdaptionField_raw & 0x0001); // 1 means presence of adaptation field extension + if ($info['ts']['packet']['adaption']['flags']['pcr']) { + $info['ts']['packet']['adaption']['raw']['pcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; + } + if ($info['ts']['packet']['adaption']['flags']['opcr']) { + $info['ts']['packet']['adaption']['raw']['opcr'] = getid3_lib::BigEndian2Int(substr($TSheader, $offset, 6)); $offset += 6; + } + } + +$info['error'][] = 'MPEG Transport Stream (.ts) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + + } + + + public function TSscramblingControlLookup($raw) { + $TSscramblingControlLookup = array(0x00=>'not scrambled', 0x01=>'reserved', 0x02=>'scrambled, even key', 0x03=>'scrambled, odd key'); + return (isset($TSscramblingControlLookup[$raw]) ? $TSscramblingControlLookup[$raw] : 'invalid'); + } +} diff --git a/app/libs/vendor/getid3/module.audio.aa.php b/app/libs/vendor/getid3/module.audio.aa.php index 22ef44e1..dbf1b7c8 100644 --- a/app/libs/vendor/getid3/module.audio.aa.php +++ b/app/libs/vendor/getid3/module.audio.aa.php @@ -1,58 +1,58 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.aa.php // -// module for analyzing Audible Audiobook files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_aa extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $AAheader = fread($this->getid3->fp, 8); - - $magic = "\x57\x90\x75\x36"; - if (substr($AAheader, 4, 4) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"'; - return false; - } - - // shortcut - $info['aa'] = array(); - $thisfile_au = &$info['aa']; - - $info['fileformat'] = 'aa'; - $info['audio']['dataformat'] = 'aa'; -$info['error'][] = 'Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - $info['audio']['bitrate_mode'] = 'cbr'; // is it? - $thisfile_au['encoding'] = 'ISO-8859-1'; - - $thisfile_au['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4)); - if ($thisfile_au['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) { - $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'; - } - - $info['audio']['bits_per_sample'] = 16; // is it? - $info['audio']['sample_rate'] = $thisfile_au['sample_rate']; - $info['audio']['channels'] = $thisfile_au['channels']; - - //$info['playtime_seconds'] = 0; - //$info['audio']['bitrate'] = 0; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.aa.php // +// module for analyzing Audible Audiobook files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_aa extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $AAheader = fread($this->getid3->fp, 8); + + $magic = "\x57\x90\x75\x36"; + if (substr($AAheader, 4, 4) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AAheader, 4, 4)).'"'; + return false; + } + + // shortcut + $info['aa'] = array(); + $thisfile_au = &$info['aa']; + + $info['fileformat'] = 'aa'; + $info['audio']['dataformat'] = 'aa'; +$info['error'][] = 'Audible Audiobook (.aa) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + $info['audio']['bitrate_mode'] = 'cbr'; // is it? + $thisfile_au['encoding'] = 'ISO-8859-1'; + + $thisfile_au['filesize'] = getid3_lib::BigEndian2Int(substr($AUheader, 0, 4)); + if ($thisfile_au['filesize'] > ($info['avdataend'] - $info['avdataoffset'])) { + $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['filesize'].'" bytes of data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'; + } + + $info['audio']['bits_per_sample'] = 16; // is it? + $info['audio']['sample_rate'] = $thisfile_au['sample_rate']; + $info['audio']['channels'] = $thisfile_au['channels']; + + //$info['playtime_seconds'] = 0; + //$info['audio']['bitrate'] = 0; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.aac.php b/app/libs/vendor/getid3/module.audio.aac.php index 1d642b36..06537abb 100644 --- a/app/libs/vendor/getid3/module.audio.aac.php +++ b/app/libs/vendor/getid3/module.audio.aac.php @@ -1,512 +1,512 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.aac.php // -// module for analyzing AAC Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_aac extends getid3_handler -{ - public function Analyze() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - if (fread($this->getid3->fp, 4) == 'ADIF') { - $this->getAACADIFheaderFilepointer(); - } else { - $this->getAACADTSheaderFilepointer(); - } - return true; - } - - - - public function getAACADIFheaderFilepointer() { - $info = &$this->getid3->info; - $info['fileformat'] = 'aac'; - $info['audio']['dataformat'] = 'aac'; - $info['audio']['lossless'] = false; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $AACheader = fread($this->getid3->fp, 1024); - $offset = 0; - - if (substr($AACheader, 0, 4) == 'ADIF') { - - // http://faac.sourceforge.net/wiki/index.php?page=ADIF - - // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf - // adif_header() { - // adif_id 32 - // copyright_id_present 1 - // if( copyright_id_present ) - // copyright_id 72 - // original_copy 1 - // home 1 - // bitstream_type 1 - // bitrate 23 - // num_program_config_elements 4 - // for (i = 0; i < num_program_config_elements + 1; i++ ) { - // if( bitstream_type == '0' ) - // adif_buffer_fullness 20 - // program_config_element() - // } - // } - - $AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader); - $bitoffset = 0; - - $info['aac']['header_type'] = 'ADIF'; - $bitoffset += 32; - $info['aac']['header']['mpeg_version'] = 4; - - $info['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); - $bitoffset += 1; - if ($info['aac']['header']['copyright']) { - $info['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72)); - $bitoffset += 72; - } - $info['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); - $bitoffset += 1; - $info['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); - $bitoffset += 1; - $info['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); - $bitoffset += 1; - if ($info['aac']['header']['is_vbr']) { - $info['audio']['bitrate_mode'] = 'vbr'; - $info['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); - $bitoffset += 23; - } else { - $info['audio']['bitrate_mode'] = 'cbr'; - $info['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); - $bitoffset += 23; - $info['audio']['bitrate'] = $info['aac']['header']['bitrate']; - } - if ($info['audio']['bitrate'] == 0) { - $info['error'][] = 'Corrupt AAC file: bitrate_audio == zero'; - return false; - } - $info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - - for ($i = 0; $i < $info['aac']['header']['num_program_configs']; $i++) { - // http://www.audiocoding.com/wiki/index.php?page=program_config_element - - // buffer_fullness 20 - - // element_instance_tag 4 - // object_type 2 - // sampling_frequency_index 4 - // num_front_channel_elements 4 - // num_side_channel_elements 4 - // num_back_channel_elements 4 - // num_lfe_channel_elements 2 - // num_assoc_data_elements 3 - // num_valid_cc_elements 4 - // mono_mixdown_present 1 - // mono_mixdown_element_number 4 if mono_mixdown_present == 1 - // stereo_mixdown_present 1 - // stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 - // matrix_mixdown_idx_present 1 - // matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1 - // pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1 - // for (i = 0; i < num_front_channel_elements; i++) { - // front_element_is_cpe[i] 1 - // front_element_tag_select[i] 4 - // } - // for (i = 0; i < num_side_channel_elements; i++) { - // side_element_is_cpe[i] 1 - // side_element_tag_select[i] 4 - // } - // for (i = 0; i < num_back_channel_elements; i++) { - // back_element_is_cpe[i] 1 - // back_element_tag_select[i] 4 - // } - // for (i = 0; i < num_lfe_channel_elements; i++) { - // lfe_element_tag_select[i] 4 - // } - // for (i = 0; i < num_assoc_data_elements; i++) { - // assoc_data_element_tag_select[i] 4 - // } - // for (i = 0; i < num_valid_cc_elements; i++) { - // cc_element_is_ind_sw[i] 1 - // valid_cc_element_tag_select[i] 4 - // } - // byte_alignment() VAR - // comment_field_bytes 8 - // for (i = 0; i < comment_field_bytes; i++) { - // comment_field_data[i] 8 - // } - - if (!$info['aac']['header']['is_vbr']) { - $info['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20)); - $bitoffset += 20; - } - $info['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); - $bitoffset += 2; - $info['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); - $bitoffset += 2; - $info['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3)); - $bitoffset += 3; - $info['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - $info['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - if ($info['aac']['program_configs'][$i]['mono_mixdown_present']) { - $info['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - $info['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - if ($info['aac']['program_configs'][$i]['stereo_mixdown_present']) { - $info['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - $info['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - if ($info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) { - $info['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); - $bitoffset += 2; - $info['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) { - $info['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - $info['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) { - $info['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - $info['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) { - $info['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - $info['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) { - $info['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) { - $info['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) { - $info['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); - $bitoffset += 1; - $info['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); - $bitoffset += 4; - } - - $bitoffset = ceil($bitoffset / 8) * 8; - - $info['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8)); - $bitoffset += 8; - $info['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info['aac']['program_configs'][$i]['comment_field_bytes'])); - $bitoffset += 8 * $info['aac']['program_configs'][$i]['comment_field_bytes']; - - - $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['program_configs'][$i]['object_type'], $info['aac']['header']['mpeg_version']); - $info['aac']['program_configs'][$i]['sampling_frequency'] = self::AACsampleRateLookup($info['aac']['program_configs'][$i]['sampling_frequency_index']); - $info['audio']['sample_rate'] = $info['aac']['program_configs'][$i]['sampling_frequency']; - $info['audio']['channels'] = self::AACchannelCountCalculate($info['aac']['program_configs'][$i]); - if ($info['aac']['program_configs'][$i]['comment_field']) { - $info['aac']['comments'][] = $info['aac']['program_configs'][$i]['comment_field']; - } - } - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']; - - $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile']; - - - - return true; - - } else { - - unset($info['fileformat']); - unset($info['aac']); - $info['error'][] = 'AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)'; - return false; - - } - - } - - - public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) { - $info = &$this->getid3->info; - - // based loosely on code from AACfile by Jurgen Faul - // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html - - - // http://faac.sourceforge.net/wiki/index.php?page=ADTS // dead link - // http://wiki.multimedia.cx/index.php?title=ADTS - - // * ADTS Fixed Header: these don't change from frame to frame - // syncword 12 always: '111111111111' - // ID 1 0: MPEG-4, 1: MPEG-2 - // MPEG layer 2 If you send AAC in MPEG-TS, set to 0 - // protection_absent 1 0: CRC present; 1: no CRC - // profile 2 0: AAC Main; 1: AAC LC (Low Complexity); 2: AAC SSR (Scalable Sample Rate); 3: AAC LTP (Long Term Prediction) - // sampling_frequency_index 4 15 not allowed - // private_bit 1 usually 0 - // channel_configuration 3 - // original/copy 1 0: original; 1: copy - // home 1 usually 0 - // emphasis 2 only if ID == 0 (ie MPEG-4) // not present in some documentation? - - // * ADTS Variable Header: these can change from frame to frame - // copyright_identification_bit 1 - // copyright_identification_start 1 - // aac_frame_length 13 length of the frame including header (in bytes) - // adts_buffer_fullness 11 0x7FF indicates VBR - // no_raw_data_blocks_in_frame 2 - - // * ADTS Error check - // crc_check 16 only if protection_absent == 0 - - $byteoffset = $info['avdataoffset']; - $framenumber = 0; - - // Init bit pattern array - static $decbin = array(); - - // Populate $bindec - for ($i = 0; $i < 256; $i++) { - $decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); - } - - // used to calculate bitrate below - $BitrateCache = array(); - - - while (true) { - // breaks out when end-of-file encountered, or invalid data found, - // or MaxFramesToScan frames have been scanned - - if (!getid3_lib::intValueSupported($byteoffset)) { - $info['warning'][] = 'Unable to parse AAC file beyond '.ftell($this->getid3->fp).' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)'; - return false; - } - fseek($this->getid3->fp, $byteoffset, SEEK_SET); - - // First get substring - $substring = fread($this->getid3->fp, 9); // header is 7 bytes (or 9 if CRC is present) - $substringlength = strlen($substring); - if ($substringlength != 9) { - $info['error'][] = 'Failed to read 7 bytes at offset '.(ftell($this->getid3->fp) - $substringlength).' (only read '.$substringlength.' bytes)'; - return false; - } - // this would be easier with 64-bit math, but split it up to allow for 32-bit: - $header1 = getid3_lib::BigEndian2Int(substr($substring, 0, 2)); - $header2 = getid3_lib::BigEndian2Int(substr($substring, 2, 4)); - $header3 = getid3_lib::BigEndian2Int(substr($substring, 6, 1)); - - $info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4; - if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) { - $info['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($this->getid3->fp) - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)'; - //if ($info['fileformat'] == 'aac') { - // return true; - //} - unset($info['aac']); - return false; - } - - // Gather info for first frame only - this takes time to do 1000 times! - if ($framenumber == 0) { - $info['aac']['header_type'] = 'ADTS'; - $info['fileformat'] = 'aac'; - $info['audio']['dataformat'] = 'aac'; - - $info['aac']['header']['raw']['mpeg_version'] = ($header1 & 0x0008) >> 3; - $info['aac']['header']['raw']['mpeg_layer'] = ($header1 & 0x0006) >> 1; - $info['aac']['header']['raw']['protection_absent'] = ($header1 & 0x0001) >> 0; - - $info['aac']['header']['raw']['profile_code'] = ($header2 & 0xC0000000) >> 30; - $info['aac']['header']['raw']['sample_rate_code'] = ($header2 & 0x3C000000) >> 26; - $info['aac']['header']['raw']['private_stream'] = ($header2 & 0x02000000) >> 25; - $info['aac']['header']['raw']['channels_code'] = ($header2 & 0x01C00000) >> 22; - $info['aac']['header']['raw']['original'] = ($header2 & 0x00200000) >> 21; - $info['aac']['header']['raw']['home'] = ($header2 & 0x00100000) >> 20; - $info['aac']['header']['raw']['copyright_stream'] = ($header2 & 0x00080000) >> 19; - $info['aac']['header']['raw']['copyright_start'] = ($header2 & 0x00040000) >> 18; - $info['aac']['header']['raw']['frame_length'] = ($header2 & 0x0003FFE0) >> 5; - - $info['aac']['header']['mpeg_version'] = ($info['aac']['header']['raw']['mpeg_version'] ? 2 : 4); - $info['aac']['header']['crc_present'] = ($info['aac']['header']['raw']['protection_absent'] ? false: true); - $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['header']['raw']['profile_code'], $info['aac']['header']['mpeg_version']); - $info['aac']['header']['sample_frequency'] = self::AACsampleRateLookup($info['aac']['header']['raw']['sample_rate_code']); - $info['aac']['header']['private'] = (bool) $info['aac']['header']['raw']['private_stream']; - $info['aac']['header']['original'] = (bool) $info['aac']['header']['raw']['original']; - $info['aac']['header']['home'] = (bool) $info['aac']['header']['raw']['home']; - $info['aac']['header']['channels'] = (($info['aac']['header']['raw']['channels_code'] == 7) ? 8 : $info['aac']['header']['raw']['channels_code']); - if ($ReturnExtendedInfo) { - $info['aac'][$framenumber]['copyright_id_bit'] = (bool) $info['aac']['header']['raw']['copyright_stream']; - $info['aac'][$framenumber]['copyright_id_start'] = (bool) $info['aac']['header']['raw']['copyright_start']; - } - - if ($info['aac']['header']['raw']['mpeg_layer'] != 0) { - $info['warning'][] = 'Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead'; - } - if ($info['aac']['header']['sample_frequency'] == 0) { - $info['error'][] = 'Corrupt AAC file: sample_frequency == zero'; - return false; - } - - $info['audio']['sample_rate'] = $info['aac']['header']['sample_frequency']; - $info['audio']['channels'] = $info['aac']['header']['channels']; - } - - $FrameLength = ($header2 & 0x0003FFE0) >> 5; - - if (!isset($BitrateCache[$FrameLength])) { - $BitrateCache[$FrameLength] = ($info['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8; - } - getid3_lib::safe_inc($info['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1); - - $info['aac'][$framenumber]['aac_frame_length'] = $FrameLength; - - $info['aac'][$framenumber]['adts_buffer_fullness'] = (($header2 & 0x0000001F) << 6) & (($header3 & 0xFC) >> 2); - if ($info['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) { - $info['audio']['bitrate_mode'] = 'vbr'; - } else { - $info['audio']['bitrate_mode'] = 'cbr'; - } - $info['aac'][$framenumber]['num_raw_data_blocks'] = (($header3 & 0x03) >> 0); - - if ($info['aac']['header']['crc_present']) { - //$info['aac'][$framenumber]['crc'] = getid3_lib::BigEndian2Int(substr($substring, 7, 2); - } - - if (!$ReturnExtendedInfo) { - unset($info['aac'][$framenumber]); - } - - /* - $rounded_precision = 5000; - $info['aac']['bitrate_distribution_rounded'] = array(); - foreach ($info['aac']['bitrate_distribution'] as $bitrate => $count) { - $rounded_bitrate = round($bitrate / $rounded_precision) * $rounded_precision; - getid3_lib::safe_inc($info['aac']['bitrate_distribution_rounded'][$rounded_bitrate], $count); - } - ksort($info['aac']['bitrate_distribution_rounded']); - */ - - $byteoffset += $FrameLength; - if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $info['avdataend'])) { - - // keep scanning - - } else { - - $info['aac']['frames'] = $framenumber; - $info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds - if ($info['playtime_seconds'] == 0) { - $info['error'][] = 'Corrupt AAC file: playtime_seconds == zero'; - return false; - } - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - ksort($info['aac']['bitrate_distribution']); - - $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile']; - - return true; - - } - } - // should never get here. - } - - public static function AACsampleRateLookup($samplerateid) { - static $AACsampleRateLookup = array(); - if (empty($AACsampleRateLookup)) { - $AACsampleRateLookup[0] = 96000; - $AACsampleRateLookup[1] = 88200; - $AACsampleRateLookup[2] = 64000; - $AACsampleRateLookup[3] = 48000; - $AACsampleRateLookup[4] = 44100; - $AACsampleRateLookup[5] = 32000; - $AACsampleRateLookup[6] = 24000; - $AACsampleRateLookup[7] = 22050; - $AACsampleRateLookup[8] = 16000; - $AACsampleRateLookup[9] = 12000; - $AACsampleRateLookup[10] = 11025; - $AACsampleRateLookup[11] = 8000; - $AACsampleRateLookup[12] = 0; - $AACsampleRateLookup[13] = 0; - $AACsampleRateLookup[14] = 0; - $AACsampleRateLookup[15] = 0; - } - return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid'); - } - - public static function AACprofileLookup($profileid, $mpegversion) { - static $AACprofileLookup = array(); - if (empty($AACprofileLookup)) { - $AACprofileLookup[2][0] = 'Main profile'; - $AACprofileLookup[2][1] = 'Low Complexity profile (LC)'; - $AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)'; - $AACprofileLookup[2][3] = '(reserved)'; - $AACprofileLookup[4][0] = 'AAC_MAIN'; - $AACprofileLookup[4][1] = 'AAC_LC'; - $AACprofileLookup[4][2] = 'AAC_SSR'; - $AACprofileLookup[4][3] = 'AAC_LTP'; - } - return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid'); - } - - public static function AACchannelCountCalculate($program_configs) { - $channels = 0; - for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) { - $channels++; - if ($program_configs['front_element_is_cpe'][$i]) { - // each front element is channel pair (CPE = Channel Pair Element) - $channels++; - } - } - for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) { - $channels++; - if ($program_configs['side_element_is_cpe'][$i]) { - // each side element is channel pair (CPE = Channel Pair Element) - $channels++; - } - } - for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) { - $channels++; - if ($program_configs['back_element_is_cpe'][$i]) { - // each back element is channel pair (CPE = Channel Pair Element) - $channels++; - } - } - for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) { - $channels++; - } - return $channels; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.aac.php // +// module for analyzing AAC Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_aac extends getid3_handler +{ + public function Analyze() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + if (fread($this->getid3->fp, 4) == 'ADIF') { + $this->getAACADIFheaderFilepointer(); + } else { + $this->getAACADTSheaderFilepointer(); + } + return true; + } + + + + public function getAACADIFheaderFilepointer() { + $info = &$this->getid3->info; + $info['fileformat'] = 'aac'; + $info['audio']['dataformat'] = 'aac'; + $info['audio']['lossless'] = false; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $AACheader = fread($this->getid3->fp, 1024); + $offset = 0; + + if (substr($AACheader, 0, 4) == 'ADIF') { + + // http://faac.sourceforge.net/wiki/index.php?page=ADIF + + // http://libmpeg.org/mpeg4/doc/w2203tfs.pdf + // adif_header() { + // adif_id 32 + // copyright_id_present 1 + // if( copyright_id_present ) + // copyright_id 72 + // original_copy 1 + // home 1 + // bitstream_type 1 + // bitrate 23 + // num_program_config_elements 4 + // for (i = 0; i < num_program_config_elements + 1; i++ ) { + // if( bitstream_type == '0' ) + // adif_buffer_fullness 20 + // program_config_element() + // } + // } + + $AACheaderBitstream = getid3_lib::BigEndian2Bin($AACheader); + $bitoffset = 0; + + $info['aac']['header_type'] = 'ADIF'; + $bitoffset += 32; + $info['aac']['header']['mpeg_version'] = 4; + + $info['aac']['header']['copyright'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + if ($info['aac']['header']['copyright']) { + $info['aac']['header']['copyright_id'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 72)); + $bitoffset += 72; + } + $info['aac']['header']['original_copy'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + $info['aac']['header']['home'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + $info['aac']['header']['is_vbr'] = (bool) (substr($AACheaderBitstream, $bitoffset, 1) == '1'); + $bitoffset += 1; + if ($info['aac']['header']['is_vbr']) { + $info['audio']['bitrate_mode'] = 'vbr'; + $info['aac']['header']['bitrate_max'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); + $bitoffset += 23; + } else { + $info['audio']['bitrate_mode'] = 'cbr'; + $info['aac']['header']['bitrate'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 23)); + $bitoffset += 23; + $info['audio']['bitrate'] = $info['aac']['header']['bitrate']; + } + if ($info['audio']['bitrate'] == 0) { + $info['error'][] = 'Corrupt AAC file: bitrate_audio == zero'; + return false; + } + $info['aac']['header']['num_program_configs'] = 1 + getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + + for ($i = 0; $i < $info['aac']['header']['num_program_configs']; $i++) { + // http://www.audiocoding.com/wiki/index.php?page=program_config_element + + // buffer_fullness 20 + + // element_instance_tag 4 + // object_type 2 + // sampling_frequency_index 4 + // num_front_channel_elements 4 + // num_side_channel_elements 4 + // num_back_channel_elements 4 + // num_lfe_channel_elements 2 + // num_assoc_data_elements 3 + // num_valid_cc_elements 4 + // mono_mixdown_present 1 + // mono_mixdown_element_number 4 if mono_mixdown_present == 1 + // stereo_mixdown_present 1 + // stereo_mixdown_element_number 4 if stereo_mixdown_present == 1 + // matrix_mixdown_idx_present 1 + // matrix_mixdown_idx 2 if matrix_mixdown_idx_present == 1 + // pseudo_surround_enable 1 if matrix_mixdown_idx_present == 1 + // for (i = 0; i < num_front_channel_elements; i++) { + // front_element_is_cpe[i] 1 + // front_element_tag_select[i] 4 + // } + // for (i = 0; i < num_side_channel_elements; i++) { + // side_element_is_cpe[i] 1 + // side_element_tag_select[i] 4 + // } + // for (i = 0; i < num_back_channel_elements; i++) { + // back_element_is_cpe[i] 1 + // back_element_tag_select[i] 4 + // } + // for (i = 0; i < num_lfe_channel_elements; i++) { + // lfe_element_tag_select[i] 4 + // } + // for (i = 0; i < num_assoc_data_elements; i++) { + // assoc_data_element_tag_select[i] 4 + // } + // for (i = 0; i < num_valid_cc_elements; i++) { + // cc_element_is_ind_sw[i] 1 + // valid_cc_element_tag_select[i] 4 + // } + // byte_alignment() VAR + // comment_field_bytes 8 + // for (i = 0; i < comment_field_bytes; i++) { + // comment_field_data[i] 8 + // } + + if (!$info['aac']['header']['is_vbr']) { + $info['aac']['program_configs'][$i]['buffer_fullness'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 20)); + $bitoffset += 20; + } + $info['aac']['program_configs'][$i]['element_instance_tag'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['object_type'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $info['aac']['program_configs'][$i]['sampling_frequency_index'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['num_front_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['num_side_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['num_back_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['num_lfe_channel_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $info['aac']['program_configs'][$i]['num_assoc_data_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 3)); + $bitoffset += 3; + $info['aac']['program_configs'][$i]['num_valid_cc_elements'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + $info['aac']['program_configs'][$i]['mono_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($info['aac']['program_configs'][$i]['mono_mixdown_present']) { + $info['aac']['program_configs'][$i]['mono_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + $info['aac']['program_configs'][$i]['stereo_mixdown_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($info['aac']['program_configs'][$i]['stereo_mixdown_present']) { + $info['aac']['program_configs'][$i]['stereo_mixdown_element_number'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + $info['aac']['program_configs'][$i]['matrix_mixdown_idx_present'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + if ($info['aac']['program_configs'][$i]['matrix_mixdown_idx_present']) { + $info['aac']['program_configs'][$i]['matrix_mixdown_idx'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 2)); + $bitoffset += 2; + $info['aac']['program_configs'][$i]['pseudo_surround_enable'] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_front_channel_elements']; $j++) { + $info['aac']['program_configs'][$i]['front_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $info['aac']['program_configs'][$i]['front_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_side_channel_elements']; $j++) { + $info['aac']['program_configs'][$i]['side_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $info['aac']['program_configs'][$i]['side_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_back_channel_elements']; $j++) { + $info['aac']['program_configs'][$i]['back_element_is_cpe'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $info['aac']['program_configs'][$i]['back_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_lfe_channel_elements']; $j++) { + $info['aac']['program_configs'][$i]['lfe_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_assoc_data_elements']; $j++) { + $info['aac']['program_configs'][$i]['assoc_data_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + for ($j = 0; $j < $info['aac']['program_configs'][$i]['num_valid_cc_elements']; $j++) { + $info['aac']['program_configs'][$i]['cc_element_is_ind_sw'][$j] = (bool) getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 1)); + $bitoffset += 1; + $info['aac']['program_configs'][$i]['valid_cc_element_tag_select'][$j] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 4)); + $bitoffset += 4; + } + + $bitoffset = ceil($bitoffset / 8) * 8; + + $info['aac']['program_configs'][$i]['comment_field_bytes'] = getid3_lib::Bin2Dec(substr($AACheaderBitstream, $bitoffset, 8)); + $bitoffset += 8; + $info['aac']['program_configs'][$i]['comment_field'] = getid3_lib::Bin2String(substr($AACheaderBitstream, $bitoffset, 8 * $info['aac']['program_configs'][$i]['comment_field_bytes'])); + $bitoffset += 8 * $info['aac']['program_configs'][$i]['comment_field_bytes']; + + + $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['program_configs'][$i]['object_type'], $info['aac']['header']['mpeg_version']); + $info['aac']['program_configs'][$i]['sampling_frequency'] = self::AACsampleRateLookup($info['aac']['program_configs'][$i]['sampling_frequency_index']); + $info['audio']['sample_rate'] = $info['aac']['program_configs'][$i]['sampling_frequency']; + $info['audio']['channels'] = self::AACchannelCountCalculate($info['aac']['program_configs'][$i]); + if ($info['aac']['program_configs'][$i]['comment_field']) { + $info['aac']['comments'][] = $info['aac']['program_configs'][$i]['comment_field']; + } + } + $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']; + + $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile']; + + + + return true; + + } else { + + unset($info['fileformat']); + unset($info['aac']); + $info['error'][] = 'AAC-ADIF synch not found at offset '.$info['avdataoffset'].' (expected "ADIF", found "'.substr($AACheader, 0, 4).'" instead)'; + return false; + + } + + } + + + public function getAACADTSheaderFilepointer($MaxFramesToScan=1000000, $ReturnExtendedInfo=false) { + $info = &$this->getid3->info; + + // based loosely on code from AACfile by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + + // http://faac.sourceforge.net/wiki/index.php?page=ADTS // dead link + // http://wiki.multimedia.cx/index.php?title=ADTS + + // * ADTS Fixed Header: these don't change from frame to frame + // syncword 12 always: '111111111111' + // ID 1 0: MPEG-4, 1: MPEG-2 + // MPEG layer 2 If you send AAC in MPEG-TS, set to 0 + // protection_absent 1 0: CRC present; 1: no CRC + // profile 2 0: AAC Main; 1: AAC LC (Low Complexity); 2: AAC SSR (Scalable Sample Rate); 3: AAC LTP (Long Term Prediction) + // sampling_frequency_index 4 15 not allowed + // private_bit 1 usually 0 + // channel_configuration 3 + // original/copy 1 0: original; 1: copy + // home 1 usually 0 + // emphasis 2 only if ID == 0 (ie MPEG-4) // not present in some documentation? + + // * ADTS Variable Header: these can change from frame to frame + // copyright_identification_bit 1 + // copyright_identification_start 1 + // aac_frame_length 13 length of the frame including header (in bytes) + // adts_buffer_fullness 11 0x7FF indicates VBR + // no_raw_data_blocks_in_frame 2 + + // * ADTS Error check + // crc_check 16 only if protection_absent == 0 + + $byteoffset = $info['avdataoffset']; + $framenumber = 0; + + // Init bit pattern array + static $decbin = array(); + + // Populate $bindec + for ($i = 0; $i < 256; $i++) { + $decbin[chr($i)] = str_pad(decbin($i), 8, '0', STR_PAD_LEFT); + } + + // used to calculate bitrate below + $BitrateCache = array(); + + + while (true) { + // breaks out when end-of-file encountered, or invalid data found, + // or MaxFramesToScan frames have been scanned + + if (!getid3_lib::intValueSupported($byteoffset)) { + $info['warning'][] = 'Unable to parse AAC file beyond '.ftell($this->getid3->fp).' (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)'; + return false; + } + fseek($this->getid3->fp, $byteoffset, SEEK_SET); + + // First get substring + $substring = fread($this->getid3->fp, 9); // header is 7 bytes (or 9 if CRC is present) + $substringlength = strlen($substring); + if ($substringlength != 9) { + $info['error'][] = 'Failed to read 7 bytes at offset '.(ftell($this->getid3->fp) - $substringlength).' (only read '.$substringlength.' bytes)'; + return false; + } + // this would be easier with 64-bit math, but split it up to allow for 32-bit: + $header1 = getid3_lib::BigEndian2Int(substr($substring, 0, 2)); + $header2 = getid3_lib::BigEndian2Int(substr($substring, 2, 4)); + $header3 = getid3_lib::BigEndian2Int(substr($substring, 6, 1)); + + $info['aac']['header']['raw']['syncword'] = ($header1 & 0xFFF0) >> 4; + if ($info['aac']['header']['raw']['syncword'] != 0x0FFF) { + $info['error'][] = 'Synch pattern (0x0FFF) not found at offset '.(ftell($this->getid3->fp) - $substringlength).' (found 0x0'.strtoupper(dechex($info['aac']['header']['raw']['syncword'])).' instead)'; + //if ($info['fileformat'] == 'aac') { + // return true; + //} + unset($info['aac']); + return false; + } + + // Gather info for first frame only - this takes time to do 1000 times! + if ($framenumber == 0) { + $info['aac']['header_type'] = 'ADTS'; + $info['fileformat'] = 'aac'; + $info['audio']['dataformat'] = 'aac'; + + $info['aac']['header']['raw']['mpeg_version'] = ($header1 & 0x0008) >> 3; + $info['aac']['header']['raw']['mpeg_layer'] = ($header1 & 0x0006) >> 1; + $info['aac']['header']['raw']['protection_absent'] = ($header1 & 0x0001) >> 0; + + $info['aac']['header']['raw']['profile_code'] = ($header2 & 0xC0000000) >> 30; + $info['aac']['header']['raw']['sample_rate_code'] = ($header2 & 0x3C000000) >> 26; + $info['aac']['header']['raw']['private_stream'] = ($header2 & 0x02000000) >> 25; + $info['aac']['header']['raw']['channels_code'] = ($header2 & 0x01C00000) >> 22; + $info['aac']['header']['raw']['original'] = ($header2 & 0x00200000) >> 21; + $info['aac']['header']['raw']['home'] = ($header2 & 0x00100000) >> 20; + $info['aac']['header']['raw']['copyright_stream'] = ($header2 & 0x00080000) >> 19; + $info['aac']['header']['raw']['copyright_start'] = ($header2 & 0x00040000) >> 18; + $info['aac']['header']['raw']['frame_length'] = ($header2 & 0x0003FFE0) >> 5; + + $info['aac']['header']['mpeg_version'] = ($info['aac']['header']['raw']['mpeg_version'] ? 2 : 4); + $info['aac']['header']['crc_present'] = ($info['aac']['header']['raw']['protection_absent'] ? false: true); + $info['aac']['header']['profile'] = self::AACprofileLookup($info['aac']['header']['raw']['profile_code'], $info['aac']['header']['mpeg_version']); + $info['aac']['header']['sample_frequency'] = self::AACsampleRateLookup($info['aac']['header']['raw']['sample_rate_code']); + $info['aac']['header']['private'] = (bool) $info['aac']['header']['raw']['private_stream']; + $info['aac']['header']['original'] = (bool) $info['aac']['header']['raw']['original']; + $info['aac']['header']['home'] = (bool) $info['aac']['header']['raw']['home']; + $info['aac']['header']['channels'] = (($info['aac']['header']['raw']['channels_code'] == 7) ? 8 : $info['aac']['header']['raw']['channels_code']); + if ($ReturnExtendedInfo) { + $info['aac'][$framenumber]['copyright_id_bit'] = (bool) $info['aac']['header']['raw']['copyright_stream']; + $info['aac'][$framenumber]['copyright_id_start'] = (bool) $info['aac']['header']['raw']['copyright_start']; + } + + if ($info['aac']['header']['raw']['mpeg_layer'] != 0) { + $info['warning'][] = 'Layer error - expected "0", found "'.$info['aac']['header']['raw']['mpeg_layer'].'" instead'; + } + if ($info['aac']['header']['sample_frequency'] == 0) { + $info['error'][] = 'Corrupt AAC file: sample_frequency == zero'; + return false; + } + + $info['audio']['sample_rate'] = $info['aac']['header']['sample_frequency']; + $info['audio']['channels'] = $info['aac']['header']['channels']; + } + + $FrameLength = ($header2 & 0x0003FFE0) >> 5; + + if (!isset($BitrateCache[$FrameLength])) { + $BitrateCache[$FrameLength] = ($info['aac']['header']['sample_frequency'] / 1024) * $FrameLength * 8; + } + getid3_lib::safe_inc($info['aac']['bitrate_distribution'][$BitrateCache[$FrameLength]], 1); + + $info['aac'][$framenumber]['aac_frame_length'] = $FrameLength; + + $info['aac'][$framenumber]['adts_buffer_fullness'] = (($header2 & 0x0000001F) << 6) & (($header3 & 0xFC) >> 2); + if ($info['aac'][$framenumber]['adts_buffer_fullness'] == 0x07FF) { + $info['audio']['bitrate_mode'] = 'vbr'; + } else { + $info['audio']['bitrate_mode'] = 'cbr'; + } + $info['aac'][$framenumber]['num_raw_data_blocks'] = (($header3 & 0x03) >> 0); + + if ($info['aac']['header']['crc_present']) { + //$info['aac'][$framenumber]['crc'] = getid3_lib::BigEndian2Int(substr($substring, 7, 2); + } + + if (!$ReturnExtendedInfo) { + unset($info['aac'][$framenumber]); + } + + /* + $rounded_precision = 5000; + $info['aac']['bitrate_distribution_rounded'] = array(); + foreach ($info['aac']['bitrate_distribution'] as $bitrate => $count) { + $rounded_bitrate = round($bitrate / $rounded_precision) * $rounded_precision; + getid3_lib::safe_inc($info['aac']['bitrate_distribution_rounded'][$rounded_bitrate], $count); + } + ksort($info['aac']['bitrate_distribution_rounded']); + */ + + $byteoffset += $FrameLength; + if ((++$framenumber < $MaxFramesToScan) && (($byteoffset + 10) < $info['avdataend'])) { + + // keep scanning + + } else { + + $info['aac']['frames'] = $framenumber; + $info['playtime_seconds'] = ($info['avdataend'] / $byteoffset) * (($framenumber * 1024) / $info['aac']['header']['sample_frequency']); // (1 / % of file scanned) * (samples / (samples/sec)) = seconds + if ($info['playtime_seconds'] == 0) { + $info['error'][] = 'Corrupt AAC file: playtime_seconds == zero'; + return false; + } + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + ksort($info['aac']['bitrate_distribution']); + + $info['audio']['encoder_options'] = $info['aac']['header_type'].' '.$info['aac']['header']['profile']; + + return true; + + } + } + // should never get here. + } + + public static function AACsampleRateLookup($samplerateid) { + static $AACsampleRateLookup = array(); + if (empty($AACsampleRateLookup)) { + $AACsampleRateLookup[0] = 96000; + $AACsampleRateLookup[1] = 88200; + $AACsampleRateLookup[2] = 64000; + $AACsampleRateLookup[3] = 48000; + $AACsampleRateLookup[4] = 44100; + $AACsampleRateLookup[5] = 32000; + $AACsampleRateLookup[6] = 24000; + $AACsampleRateLookup[7] = 22050; + $AACsampleRateLookup[8] = 16000; + $AACsampleRateLookup[9] = 12000; + $AACsampleRateLookup[10] = 11025; + $AACsampleRateLookup[11] = 8000; + $AACsampleRateLookup[12] = 0; + $AACsampleRateLookup[13] = 0; + $AACsampleRateLookup[14] = 0; + $AACsampleRateLookup[15] = 0; + } + return (isset($AACsampleRateLookup[$samplerateid]) ? $AACsampleRateLookup[$samplerateid] : 'invalid'); + } + + public static function AACprofileLookup($profileid, $mpegversion) { + static $AACprofileLookup = array(); + if (empty($AACprofileLookup)) { + $AACprofileLookup[2][0] = 'Main profile'; + $AACprofileLookup[2][1] = 'Low Complexity profile (LC)'; + $AACprofileLookup[2][2] = 'Scalable Sample Rate profile (SSR)'; + $AACprofileLookup[2][3] = '(reserved)'; + $AACprofileLookup[4][0] = 'AAC_MAIN'; + $AACprofileLookup[4][1] = 'AAC_LC'; + $AACprofileLookup[4][2] = 'AAC_SSR'; + $AACprofileLookup[4][3] = 'AAC_LTP'; + } + return (isset($AACprofileLookup[$mpegversion][$profileid]) ? $AACprofileLookup[$mpegversion][$profileid] : 'invalid'); + } + + public static function AACchannelCountCalculate($program_configs) { + $channels = 0; + for ($i = 0; $i < $program_configs['num_front_channel_elements']; $i++) { + $channels++; + if ($program_configs['front_element_is_cpe'][$i]) { + // each front element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_side_channel_elements']; $i++) { + $channels++; + if ($program_configs['side_element_is_cpe'][$i]) { + // each side element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_back_channel_elements']; $i++) { + $channels++; + if ($program_configs['back_element_is_cpe'][$i]) { + // each back element is channel pair (CPE = Channel Pair Element) + $channels++; + } + } + for ($i = 0; $i < $program_configs['num_lfe_channel_elements']; $i++) { + $channels++; + } + return $channels; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.ac3.php b/app/libs/vendor/getid3/module.audio.ac3.php index c710698a..9834feb5 100644 --- a/app/libs/vendor/getid3/module.audio.ac3.php +++ b/app/libs/vendor/getid3/module.audio.ac3.php @@ -1,473 +1,473 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.ac3.php // -// module for analyzing AC-3 (aka Dolby Digital) audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_ac3 extends getid3_handler -{ - private $AC3header = array(); - private $BSIoffset = 0; - - const syncword = "\x0B\x77"; - - public function Analyze() { - $info = &$this->getid3->info; - - ///AH - $info['ac3']['raw']['bsi'] = array(); - $thisfile_ac3 = &$info['ac3']; - $thisfile_ac3_raw = &$thisfile_ac3['raw']; - $thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi']; - - - // http://www.atsc.org/standards/a_52a.pdf - - $info['fileformat'] = 'ac3'; - - // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames - // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256 - // new audio samples per channel. A synchronization information (SI) header at the beginning - // of each frame contains information needed to acquire and maintain synchronization. A - // bit stream information (BSI) header follows SI, and contains parameters describing the coded - // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the - // end of each frame is an error check field that includes a CRC word for error detection. An - // additional CRC word is located in the SI header, the use of which, by a decoder, is optional. - // - // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC - - // syncinfo() { - // syncword 16 - // crc1 16 - // fscod 2 - // frmsizecod 6 - // } /* end of syncinfo */ - - $this->fseek($info['avdataoffset']); - $this->AC3header['syncinfo'] = $this->fread(5); - - if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) { - $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword; - $offset = 2; - } else { - if (!$this->isDependencyFor('matroska')) { - unset($info['fileformat'], $info['ac3']); - return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"'); - } - $offset = 0; - $this->fseek(-2, SEEK_CUR); - } - - $info['audio']['dataformat'] = 'ac3'; - $info['audio']['bitrate_mode'] = 'cbr'; - $info['audio']['lossless'] = false; - - $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2)); - $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1)); - $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6; - $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F); - - $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']); - if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) { - $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; - } - - $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']); - $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']); - $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; - - $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15)); - $ac3_bsi_offset = 0; - - $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); - if ($thisfile_ac3_raw_bsi['bsid'] > 8) { - // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. - // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. - // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. - $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8'); - unset($info['ac3']); - return false; - } - - $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); - $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); - - $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); - $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']); - foreach($ac3_coding_mode as $key => $value) { - $thisfile_ac3[$key] = $value; - } - switch ($thisfile_ac3_raw_bsi['acmod']) { - case 0: - case 1: - $info['audio']['channelmode'] = 'mono'; - break; - case 3: - case 4: - $info['audio']['channelmode'] = 'stereo'; - break; - default: - $info['audio']['channelmode'] = 'surround'; - break; - } - $info['audio']['channels'] = $thisfile_ac3['num_channels']; - - if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) { - // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. - $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); - $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); - } - - if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { - // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. - $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); - $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); - } - - if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) { - // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. - $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); - $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); - } - - $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1); - $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon']; - if ($thisfile_ac3_raw_bsi['lfeon']) { - //$info['audio']['channels']++; - $info['audio']['channels'] .= '.1'; - } - - $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']); - - // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. - // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. - $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); - $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB'; - - $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['compre_flag']) { - $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); - $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']); - } - - $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['langcode_flag']) { - $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); - } - - $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['audprodie']) { - $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); - $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); - - $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB'; - $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']); - } - - if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) { - // If acmod is 0, then two completely independent program channels (dual mono) - // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case, - // a number of additional items are present in BSI or audblk to fully describe Ch2. - - // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. - // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. - $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); - $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; - - $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['compre_flag2']) { - $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); - $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']); - } - - $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['langcode_flag2']) { - $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); - } - - $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['audprodie2']) { - $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); - $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); - - $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB'; - $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']); - } - - } - - $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); - - $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); - - $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['timecode1_flag']) { - $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14); - } - - $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['timecode2_flag']) { - $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14); - } - - $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1); - if ($thisfile_ac3_raw_bsi['addbsi_flag']) { - $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6); - - $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length'])); - - $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8); - $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8; - } - - return true; - } - - private function readHeaderBSI($length) { - $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length); - $this->BSIoffset += $length; - - return bindec($data); - } - - public static function sampleRateCodeLookup($fscod) { - static $sampleRateCodeLookup = array( - 0 => 48000, - 1 => 44100, - 2 => 32000, - 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute. - ); - return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false); - } - - public static function serviceTypeLookup($bsmod, $acmod) { - static $serviceTypeLookup = array(); - if (empty($serviceTypeLookup)) { - for ($i = 0; $i <= 7; $i++) { - $serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)'; - $serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)'; - $serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)'; - $serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)'; - $serviceTypeLookup[4][$i] = 'associated service: dialogue (D)'; - $serviceTypeLookup[5][$i] = 'associated service: commentary (C)'; - $serviceTypeLookup[6][$i] = 'associated service: emergency (E)'; - } - - $serviceTypeLookup[7][1] = 'associated service: voice over (VO)'; - for ($i = 2; $i <= 7; $i++) { - $serviceTypeLookup[7][$i] = 'main audio service: karaoke'; - } - } - return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false); - } - - public static function audioCodingModeLookup($acmod) { - // array(channel configuration, # channels (not incl LFE), channel order) - static $audioCodingModeLookup = array ( - 0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'), - 1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'), - 2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'), - 3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'), - 4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'), - 5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'), - 6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'), - 7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'), - ); - return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false); - } - - public static function centerMixLevelLookup($cmixlev) { - static $centerMixLevelLookup; - if (empty($centerMixLevelLookup)) { - $centerMixLevelLookup = array( - 0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB) - 1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB) - 2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB) - 3 => 'reserved' - ); - } - return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false); - } - - public static function surroundMixLevelLookup($surmixlev) { - static $surroundMixLevelLookup; - if (empty($surroundMixLevelLookup)) { - $surroundMixLevelLookup = array( - 0 => pow(2, -3.0 / 6), - 1 => pow(2, -6.0 / 6), - 2 => 0, - 3 => 'reserved' - ); - } - return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false); - } - - public static function dolbySurroundModeLookup($dsurmod) { - static $dolbySurroundModeLookup = array( - 0 => 'not indicated', - 1 => 'Not Dolby Surround encoded', - 2 => 'Dolby Surround encoded', - 3 => 'reserved' - ); - return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false); - } - - public static function channelsEnabledLookup($acmod, $lfeon) { - $lookup = array( - 'ch1'=>(bool) ($acmod == 0), - 'ch2'=>(bool) ($acmod == 0), - 'left'=>(bool) ($acmod > 1), - 'right'=>(bool) ($acmod > 1), - 'center'=>(bool) ($acmod & 0x01), - 'surround_mono'=>false, - 'surround_left'=>false, - 'surround_right'=>false, - 'lfe'=>$lfeon); - switch ($acmod) { - case 4: - case 5: - $lookup['surround_mono'] = true; - break; - case 6: - case 7: - $lookup['surround_left'] = true; - $lookup['surround_right'] = true; - break; - } - return $lookup; - } - - public static function heavyCompression($compre) { - // The first four bits indicate gain changes in 6.02dB increments which can be - // implemented with an arithmetic shift operation. The following four bits - // indicate linear gain changes, and require a 5-bit multiply. - // We will represent the two 4-bit fields of compr as follows: - // X0 X1 X2 X3 . Y4 Y5 Y6 Y7 - // The meaning of the X values is most simply described by considering X to represent a 4-bit - // signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The - // following table shows this in detail. - - // Meaning of 4 msb of compr - // 7 +48.16 dB - // 6 +42.14 dB - // 5 +36.12 dB - // 4 +30.10 dB - // 3 +24.08 dB - // 2 +18.06 dB - // 1 +12.04 dB - // 0 +6.02 dB - // -1 0 dB - // -2 -6.02 dB - // -3 -12.04 dB - // -4 -18.06 dB - // -5 -24.08 dB - // -6 -30.10 dB - // -7 -36.12 dB - // -8 -42.14 dB - - $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT); - if ($fourbit{0} == '1') { - $log_gain = -8 + bindec(substr($fourbit, 1)); - } else { - $log_gain = bindec(substr($fourbit, 1)); - } - $log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2); - - // The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to - // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can - // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain - // changes from -0.28 dB to -6.02 dB. - - $lin_gain = (16 + ($compre & 0x0F)) / 32; - - // The combination of X and Y values allows compr to indicate gain changes from - // 48.16 - 0.28 = +47.89 dB, to - // -42.14 - 6.02 = -48.16 dB. - - return $log_gain - $lin_gain; - } - - public static function roomTypeLookup($roomtyp) { - static $roomTypeLookup = array( - 0 => 'not indicated', - 1 => 'large room, X curve monitor', - 2 => 'small room, flat monitor', - 3 => 'reserved' - ); - return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false); - } - - public static function frameSizeLookup($frmsizecod, $fscod) { - $padding = (bool) ($frmsizecod % 2); - $framesizeid = floor($frmsizecod / 2); - - static $frameSizeLookup = array(); - if (empty($frameSizeLookup)) { - $frameSizeLookup = array ( - 0 => array(128, 138, 192), - 1 => array(40, 160, 174, 240), - 2 => array(48, 192, 208, 288), - 3 => array(56, 224, 242, 336), - 4 => array(64, 256, 278, 384), - 5 => array(80, 320, 348, 480), - 6 => array(96, 384, 416, 576), - 7 => array(112, 448, 486, 672), - 8 => array(128, 512, 556, 768), - 9 => array(160, 640, 696, 960), - 10 => array(192, 768, 834, 1152), - 11 => array(224, 896, 974, 1344), - 12 => array(256, 1024, 1114, 1536), - 13 => array(320, 1280, 1392, 1920), - 14 => array(384, 1536, 1670, 2304), - 15 => array(448, 1792, 1950, 2688), - 16 => array(512, 2048, 2228, 3072), - 17 => array(576, 2304, 2506, 3456), - 18 => array(640, 2560, 2786, 3840) - ); - } - if (($fscod == 1) && $padding) { - // frame lengths are padded by 1 word (16 bits) at 44100 - $frameSizeLookup[$frmsizecod] += 2; - } - return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false); - } - - public static function bitrateLookup($frmsizecod) { - $framesizeid = floor($frmsizecod / 2); - - static $bitrateLookup = array( - 0 => 32000, - 1 => 40000, - 2 => 48000, - 3 => 56000, - 4 => 64000, - 5 => 80000, - 6 => 96000, - 7 => 112000, - 8 => 128000, - 9 => 160000, - 10 => 192000, - 11 => 224000, - 12 => 256000, - 13 => 320000, - 14 => 384000, - 15 => 448000, - 16 => 512000, - 17 => 576000, - 18 => 640000 - ); - return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false); - } - - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.ac3.php // +// module for analyzing AC-3 (aka Dolby Digital) audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_ac3 extends getid3_handler +{ + private $AC3header = array(); + private $BSIoffset = 0; + + const syncword = "\x0B\x77"; + + public function Analyze() { + $info = &$this->getid3->info; + + ///AH + $info['ac3']['raw']['bsi'] = array(); + $thisfile_ac3 = &$info['ac3']; + $thisfile_ac3_raw = &$thisfile_ac3['raw']; + $thisfile_ac3_raw_bsi = &$thisfile_ac3_raw['bsi']; + + + // http://www.atsc.org/standards/a_52a.pdf + + $info['fileformat'] = 'ac3'; + + // An AC-3 serial coded audio bit stream is made up of a sequence of synchronization frames + // Each synchronization frame contains 6 coded audio blocks (AB), each of which represent 256 + // new audio samples per channel. A synchronization information (SI) header at the beginning + // of each frame contains information needed to acquire and maintain synchronization. A + // bit stream information (BSI) header follows SI, and contains parameters describing the coded + // audio service. The coded audio blocks may be followed by an auxiliary data (Aux) field. At the + // end of each frame is an error check field that includes a CRC word for error detection. An + // additional CRC word is located in the SI header, the use of which, by a decoder, is optional. + // + // syncinfo() | bsi() | AB0 | AB1 | AB2 | AB3 | AB4 | AB5 | Aux | CRC + + // syncinfo() { + // syncword 16 + // crc1 16 + // fscod 2 + // frmsizecod 6 + // } /* end of syncinfo */ + + $this->fseek($info['avdataoffset']); + $this->AC3header['syncinfo'] = $this->fread(5); + + if (strpos($this->AC3header['syncinfo'], self::syncword) === 0) { + $thisfile_ac3_raw['synchinfo']['synchword'] = self::syncword; + $offset = 2; + } else { + if (!$this->isDependencyFor('matroska')) { + unset($info['fileformat'], $info['ac3']); + return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($this->AC3header['syncinfo'], 0, 2)).'"'); + } + $offset = 0; + $this->fseek(-2, SEEK_CUR); + } + + $info['audio']['dataformat'] = 'ac3'; + $info['audio']['bitrate_mode'] = 'cbr'; + $info['audio']['lossless'] = false; + + $thisfile_ac3_raw['synchinfo']['crc1'] = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], $offset, 2)); + $ac3_synchinfo_fscod_frmsizecod = getid3_lib::LittleEndian2Int(substr($this->AC3header['syncinfo'], ($offset + 2), 1)); + $thisfile_ac3_raw['synchinfo']['fscod'] = ($ac3_synchinfo_fscod_frmsizecod & 0xC0) >> 6; + $thisfile_ac3_raw['synchinfo']['frmsizecod'] = ($ac3_synchinfo_fscod_frmsizecod & 0x3F); + + $thisfile_ac3['sample_rate'] = self::sampleRateCodeLookup($thisfile_ac3_raw['synchinfo']['fscod']); + if ($thisfile_ac3_raw['synchinfo']['fscod'] <= 3) { + $info['audio']['sample_rate'] = $thisfile_ac3['sample_rate']; + } + + $thisfile_ac3['frame_length'] = self::frameSizeLookup($thisfile_ac3_raw['synchinfo']['frmsizecod'], $thisfile_ac3_raw['synchinfo']['fscod']); + $thisfile_ac3['bitrate'] = self::bitrateLookup($thisfile_ac3_raw['synchinfo']['frmsizecod']); + $info['audio']['bitrate'] = $thisfile_ac3['bitrate']; + + $this->AC3header['bsi'] = getid3_lib::BigEndian2Bin($this->fread(15)); + $ac3_bsi_offset = 0; + + $thisfile_ac3_raw_bsi['bsid'] = $this->readHeaderBSI(5); + if ($thisfile_ac3_raw_bsi['bsid'] > 8) { + // Decoders which can decode version 8 will thus be able to decode version numbers less than 8. + // If this standard is extended by the addition of additional elements or features, a value of bsid greater than 8 will be used. + // Decoders built to this version of the standard will not be able to decode versions with bsid greater than 8. + $this->error('Bit stream identification is version '.$thisfile_ac3_raw_bsi['bsid'].', but getID3() only understands up to version 8'); + unset($info['ac3']); + return false; + } + + $thisfile_ac3_raw_bsi['bsmod'] = $this->readHeaderBSI(3); + $thisfile_ac3_raw_bsi['acmod'] = $this->readHeaderBSI(3); + + $thisfile_ac3['service_type'] = self::serviceTypeLookup($thisfile_ac3_raw_bsi['bsmod'], $thisfile_ac3_raw_bsi['acmod']); + $ac3_coding_mode = self::audioCodingModeLookup($thisfile_ac3_raw_bsi['acmod']); + foreach($ac3_coding_mode as $key => $value) { + $thisfile_ac3[$key] = $value; + } + switch ($thisfile_ac3_raw_bsi['acmod']) { + case 0: + case 1: + $info['audio']['channelmode'] = 'mono'; + break; + case 3: + case 4: + $info['audio']['channelmode'] = 'stereo'; + break; + default: + $info['audio']['channelmode'] = 'surround'; + break; + } + $info['audio']['channels'] = $thisfile_ac3['num_channels']; + + if ($thisfile_ac3_raw_bsi['acmod'] & 0x01) { + // If the lsb of acmod is a 1, center channel is in use and cmixlev follows in the bit stream. + $thisfile_ac3_raw_bsi['cmixlev'] = $this->readHeaderBSI(2); + $thisfile_ac3['center_mix_level'] = self::centerMixLevelLookup($thisfile_ac3_raw_bsi['cmixlev']); + } + + if ($thisfile_ac3_raw_bsi['acmod'] & 0x04) { + // If the msb of acmod is a 1, surround channels are in use and surmixlev follows in the bit stream. + $thisfile_ac3_raw_bsi['surmixlev'] = $this->readHeaderBSI(2); + $thisfile_ac3['surround_mix_level'] = self::surroundMixLevelLookup($thisfile_ac3_raw_bsi['surmixlev']); + } + + if ($thisfile_ac3_raw_bsi['acmod'] == 0x02) { + // When operating in the two channel mode, this 2-bit code indicates whether or not the program has been encoded in Dolby Surround. + $thisfile_ac3_raw_bsi['dsurmod'] = $this->readHeaderBSI(2); + $thisfile_ac3['dolby_surround_mode'] = self::dolbySurroundModeLookup($thisfile_ac3_raw_bsi['dsurmod']); + } + + $thisfile_ac3_raw_bsi['lfeon'] = (bool) $this->readHeaderBSI(1); + $thisfile_ac3['lfe_enabled'] = $thisfile_ac3_raw_bsi['lfeon']; + if ($thisfile_ac3_raw_bsi['lfeon']) { + //$info['audio']['channels']++; + $info['audio']['channels'] .= '.1'; + } + + $thisfile_ac3['channels_enabled'] = self::channelsEnabledLookup($thisfile_ac3_raw_bsi['acmod'], $thisfile_ac3_raw_bsi['lfeon']); + + // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. + // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. + $thisfile_ac3_raw_bsi['dialnorm'] = $this->readHeaderBSI(5); + $thisfile_ac3['dialogue_normalization'] = '-'.$thisfile_ac3_raw_bsi['dialnorm'].'dB'; + + $thisfile_ac3_raw_bsi['compre_flag'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['compre_flag']) { + $thisfile_ac3_raw_bsi['compr'] = $this->readHeaderBSI(8); + $thisfile_ac3['heavy_compression'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr']); + } + + $thisfile_ac3_raw_bsi['langcode_flag'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['langcode_flag']) { + $thisfile_ac3_raw_bsi['langcod'] = $this->readHeaderBSI(8); + } + + $thisfile_ac3_raw_bsi['audprodie'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['audprodie']) { + $thisfile_ac3_raw_bsi['mixlevel'] = $this->readHeaderBSI(5); + $thisfile_ac3_raw_bsi['roomtyp'] = $this->readHeaderBSI(2); + + $thisfile_ac3['mixing_level'] = (80 + $thisfile_ac3_raw_bsi['mixlevel']).'dB'; + $thisfile_ac3['room_type'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp']); + } + + if ($thisfile_ac3_raw_bsi['acmod'] == 0x00) { + // If acmod is 0, then two completely independent program channels (dual mono) + // are encoded into the bit stream, and are referenced as Ch1, Ch2. In this case, + // a number of additional items are present in BSI or audblk to fully describe Ch2. + + // This indicates how far the average dialogue level is below digital 100 percent. Valid values are 1-31. + // The value of 0 is reserved. The values of 1 to 31 are interpreted as -1 dB to -31 dB with respect to digital 100 percent. + $thisfile_ac3_raw_bsi['dialnorm2'] = $this->readHeaderBSI(5); + $thisfile_ac3['dialogue_normalization2'] = '-'.$thisfile_ac3_raw_bsi['dialnorm2'].'dB'; + + $thisfile_ac3_raw_bsi['compre_flag2'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['compre_flag2']) { + $thisfile_ac3_raw_bsi['compr2'] = $this->readHeaderBSI(8); + $thisfile_ac3['heavy_compression2'] = self::heavyCompression($thisfile_ac3_raw_bsi['compr2']); + } + + $thisfile_ac3_raw_bsi['langcode_flag2'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['langcode_flag2']) { + $thisfile_ac3_raw_bsi['langcod2'] = $this->readHeaderBSI(8); + } + + $thisfile_ac3_raw_bsi['audprodie2'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['audprodie2']) { + $thisfile_ac3_raw_bsi['mixlevel2'] = $this->readHeaderBSI(5); + $thisfile_ac3_raw_bsi['roomtyp2'] = $this->readHeaderBSI(2); + + $thisfile_ac3['mixing_level2'] = (80 + $thisfile_ac3_raw_bsi['mixlevel2']).'dB'; + $thisfile_ac3['room_type2'] = self::roomTypeLookup($thisfile_ac3_raw_bsi['roomtyp2']); + } + + } + + $thisfile_ac3_raw_bsi['copyright'] = (bool) $this->readHeaderBSI(1); + + $thisfile_ac3_raw_bsi['original'] = (bool) $this->readHeaderBSI(1); + + $thisfile_ac3_raw_bsi['timecode1_flag'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['timecode1_flag']) { + $thisfile_ac3_raw_bsi['timecode1'] = $this->readHeaderBSI(14); + } + + $thisfile_ac3_raw_bsi['timecode2_flag'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['timecode2_flag']) { + $thisfile_ac3_raw_bsi['timecode2'] = $this->readHeaderBSI(14); + } + + $thisfile_ac3_raw_bsi['addbsi_flag'] = (bool) $this->readHeaderBSI(1); + if ($thisfile_ac3_raw_bsi['addbsi_flag']) { + $thisfile_ac3_raw_bsi['addbsi_length'] = $this->readHeaderBSI(6); + + $this->AC3header['bsi'] .= getid3_lib::BigEndian2Bin($this->fread($thisfile_ac3_raw_bsi['addbsi_length'])); + + $thisfile_ac3_raw_bsi['addbsi_data'] = substr($this->AC3header['bsi'], $this->BSIoffset, $thisfile_ac3_raw_bsi['addbsi_length'] * 8); + $this->BSIoffset += $thisfile_ac3_raw_bsi['addbsi_length'] * 8; + } + + return true; + } + + private function readHeaderBSI($length) { + $data = substr($this->AC3header['bsi'], $this->BSIoffset, $length); + $this->BSIoffset += $length; + + return bindec($data); + } + + public static function sampleRateCodeLookup($fscod) { + static $sampleRateCodeLookup = array( + 0 => 48000, + 1 => 44100, + 2 => 32000, + 3 => 'reserved' // If the reserved code is indicated, the decoder should not attempt to decode audio and should mute. + ); + return (isset($sampleRateCodeLookup[$fscod]) ? $sampleRateCodeLookup[$fscod] : false); + } + + public static function serviceTypeLookup($bsmod, $acmod) { + static $serviceTypeLookup = array(); + if (empty($serviceTypeLookup)) { + for ($i = 0; $i <= 7; $i++) { + $serviceTypeLookup[0][$i] = 'main audio service: complete main (CM)'; + $serviceTypeLookup[1][$i] = 'main audio service: music and effects (ME)'; + $serviceTypeLookup[2][$i] = 'associated service: visually impaired (VI)'; + $serviceTypeLookup[3][$i] = 'associated service: hearing impaired (HI)'; + $serviceTypeLookup[4][$i] = 'associated service: dialogue (D)'; + $serviceTypeLookup[5][$i] = 'associated service: commentary (C)'; + $serviceTypeLookup[6][$i] = 'associated service: emergency (E)'; + } + + $serviceTypeLookup[7][1] = 'associated service: voice over (VO)'; + for ($i = 2; $i <= 7; $i++) { + $serviceTypeLookup[7][$i] = 'main audio service: karaoke'; + } + } + return (isset($serviceTypeLookup[$bsmod][$acmod]) ? $serviceTypeLookup[$bsmod][$acmod] : false); + } + + public static function audioCodingModeLookup($acmod) { + // array(channel configuration, # channels (not incl LFE), channel order) + static $audioCodingModeLookup = array ( + 0 => array('channel_config'=>'1+1', 'num_channels'=>2, 'channel_order'=>'Ch1,Ch2'), + 1 => array('channel_config'=>'1/0', 'num_channels'=>1, 'channel_order'=>'C'), + 2 => array('channel_config'=>'2/0', 'num_channels'=>2, 'channel_order'=>'L,R'), + 3 => array('channel_config'=>'3/0', 'num_channels'=>3, 'channel_order'=>'L,C,R'), + 4 => array('channel_config'=>'2/1', 'num_channels'=>3, 'channel_order'=>'L,R,S'), + 5 => array('channel_config'=>'3/1', 'num_channels'=>4, 'channel_order'=>'L,C,R,S'), + 6 => array('channel_config'=>'2/2', 'num_channels'=>4, 'channel_order'=>'L,R,SL,SR'), + 7 => array('channel_config'=>'3/2', 'num_channels'=>5, 'channel_order'=>'L,C,R,SL,SR'), + ); + return (isset($audioCodingModeLookup[$acmod]) ? $audioCodingModeLookup[$acmod] : false); + } + + public static function centerMixLevelLookup($cmixlev) { + static $centerMixLevelLookup; + if (empty($centerMixLevelLookup)) { + $centerMixLevelLookup = array( + 0 => pow(2, -3.0 / 6), // 0.707 (-3.0 dB) + 1 => pow(2, -4.5 / 6), // 0.595 (-4.5 dB) + 2 => pow(2, -6.0 / 6), // 0.500 (-6.0 dB) + 3 => 'reserved' + ); + } + return (isset($centerMixLevelLookup[$cmixlev]) ? $centerMixLevelLookup[$cmixlev] : false); + } + + public static function surroundMixLevelLookup($surmixlev) { + static $surroundMixLevelLookup; + if (empty($surroundMixLevelLookup)) { + $surroundMixLevelLookup = array( + 0 => pow(2, -3.0 / 6), + 1 => pow(2, -6.0 / 6), + 2 => 0, + 3 => 'reserved' + ); + } + return (isset($surroundMixLevelLookup[$surmixlev]) ? $surroundMixLevelLookup[$surmixlev] : false); + } + + public static function dolbySurroundModeLookup($dsurmod) { + static $dolbySurroundModeLookup = array( + 0 => 'not indicated', + 1 => 'Not Dolby Surround encoded', + 2 => 'Dolby Surround encoded', + 3 => 'reserved' + ); + return (isset($dolbySurroundModeLookup[$dsurmod]) ? $dolbySurroundModeLookup[$dsurmod] : false); + } + + public static function channelsEnabledLookup($acmod, $lfeon) { + $lookup = array( + 'ch1'=>(bool) ($acmod == 0), + 'ch2'=>(bool) ($acmod == 0), + 'left'=>(bool) ($acmod > 1), + 'right'=>(bool) ($acmod > 1), + 'center'=>(bool) ($acmod & 0x01), + 'surround_mono'=>false, + 'surround_left'=>false, + 'surround_right'=>false, + 'lfe'=>$lfeon); + switch ($acmod) { + case 4: + case 5: + $lookup['surround_mono'] = true; + break; + case 6: + case 7: + $lookup['surround_left'] = true; + $lookup['surround_right'] = true; + break; + } + return $lookup; + } + + public static function heavyCompression($compre) { + // The first four bits indicate gain changes in 6.02dB increments which can be + // implemented with an arithmetic shift operation. The following four bits + // indicate linear gain changes, and require a 5-bit multiply. + // We will represent the two 4-bit fields of compr as follows: + // X0 X1 X2 X3 . Y4 Y5 Y6 Y7 + // The meaning of the X values is most simply described by considering X to represent a 4-bit + // signed integer with values from -8 to +7. The gain indicated by X is then (X + 1) * 6.02 dB. The + // following table shows this in detail. + + // Meaning of 4 msb of compr + // 7 +48.16 dB + // 6 +42.14 dB + // 5 +36.12 dB + // 4 +30.10 dB + // 3 +24.08 dB + // 2 +18.06 dB + // 1 +12.04 dB + // 0 +6.02 dB + // -1 0 dB + // -2 -6.02 dB + // -3 -12.04 dB + // -4 -18.06 dB + // -5 -24.08 dB + // -6 -30.10 dB + // -7 -36.12 dB + // -8 -42.14 dB + + $fourbit = str_pad(decbin(($compre & 0xF0) >> 4), 4, '0', STR_PAD_LEFT); + if ($fourbit{0} == '1') { + $log_gain = -8 + bindec(substr($fourbit, 1)); + } else { + $log_gain = bindec(substr($fourbit, 1)); + } + $log_gain = ($log_gain + 1) * getid3_lib::RGADamplitude2dB(2); + + // The value of Y is a linear representation of a gain change of up to -6 dB. Y is considered to + // be an unsigned fractional integer, with a leading value of 1, or: 0.1 Y4 Y5 Y6 Y7 (base 2). Y can + // represent values between 0.111112 (or 31/32) and 0.100002 (or 1/2). Thus, Y can represent gain + // changes from -0.28 dB to -6.02 dB. + + $lin_gain = (16 + ($compre & 0x0F)) / 32; + + // The combination of X and Y values allows compr to indicate gain changes from + // 48.16 - 0.28 = +47.89 dB, to + // -42.14 - 6.02 = -48.16 dB. + + return $log_gain - $lin_gain; + } + + public static function roomTypeLookup($roomtyp) { + static $roomTypeLookup = array( + 0 => 'not indicated', + 1 => 'large room, X curve monitor', + 2 => 'small room, flat monitor', + 3 => 'reserved' + ); + return (isset($roomTypeLookup[$roomtyp]) ? $roomTypeLookup[$roomtyp] : false); + } + + public static function frameSizeLookup($frmsizecod, $fscod) { + $padding = (bool) ($frmsizecod % 2); + $framesizeid = floor($frmsizecod / 2); + + static $frameSizeLookup = array(); + if (empty($frameSizeLookup)) { + $frameSizeLookup = array ( + 0 => array(128, 138, 192), + 1 => array(40, 160, 174, 240), + 2 => array(48, 192, 208, 288), + 3 => array(56, 224, 242, 336), + 4 => array(64, 256, 278, 384), + 5 => array(80, 320, 348, 480), + 6 => array(96, 384, 416, 576), + 7 => array(112, 448, 486, 672), + 8 => array(128, 512, 556, 768), + 9 => array(160, 640, 696, 960), + 10 => array(192, 768, 834, 1152), + 11 => array(224, 896, 974, 1344), + 12 => array(256, 1024, 1114, 1536), + 13 => array(320, 1280, 1392, 1920), + 14 => array(384, 1536, 1670, 2304), + 15 => array(448, 1792, 1950, 2688), + 16 => array(512, 2048, 2228, 3072), + 17 => array(576, 2304, 2506, 3456), + 18 => array(640, 2560, 2786, 3840) + ); + } + if (($fscod == 1) && $padding) { + // frame lengths are padded by 1 word (16 bits) at 44100 + $frameSizeLookup[$frmsizecod] += 2; + } + return (isset($frameSizeLookup[$framesizeid][$fscod]) ? $frameSizeLookup[$framesizeid][$fscod] : false); + } + + public static function bitrateLookup($frmsizecod) { + $framesizeid = floor($frmsizecod / 2); + + static $bitrateLookup = array( + 0 => 32000, + 1 => 40000, + 2 => 48000, + 3 => 56000, + 4 => 64000, + 5 => 80000, + 6 => 96000, + 7 => 112000, + 8 => 128000, + 9 => 160000, + 10 => 192000, + 11 => 224000, + 12 => 256000, + 13 => 320000, + 14 => 384000, + 15 => 448000, + 16 => 512000, + 17 => 576000, + 18 => 640000 + ); + return (isset($bitrateLookup[$framesizeid]) ? $bitrateLookup[$framesizeid] : false); + } + + +} diff --git a/app/libs/vendor/getid3/module.audio.au.php b/app/libs/vendor/getid3/module.audio.au.php index 82055bbb..5951684a 100644 --- a/app/libs/vendor/getid3/module.audio.au.php +++ b/app/libs/vendor/getid3/module.audio.au.php @@ -1,162 +1,162 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.au.php // -// module for analyzing AU files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_au extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $AUheader = fread($this->getid3->fp, 8); - - $magic = '.snd'; - if (substr($AUheader, 0, 4) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"'; - return false; - } - - // shortcut - $info['au'] = array(); - $thisfile_au = &$info['au']; - - $info['fileformat'] = 'au'; - $info['audio']['dataformat'] = 'au'; - $info['audio']['bitrate_mode'] = 'cbr'; - $thisfile_au['encoding'] = 'ISO-8859-1'; - - $thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4)); - $AUheader .= fread($this->getid3->fp, $thisfile_au['header_length'] - 8); - $info['avdataoffset'] += $thisfile_au['header_length']; - - $thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4)); - $thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4)); - $thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4)); - $thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4)); - $thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24)); - - $thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']); - $thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']); - if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) { - $info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample']; - } else { - unset($thisfile_au['bits_per_sample']); - } - - $info['audio']['sample_rate'] = $thisfile_au['sample_rate']; - $info['audio']['channels'] = $thisfile_au['channels']; - - if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) { - $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'; - } - - $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds']; - - return true; - } - - public function AUdataFormatNameLookup($id) { - static $AUdataFormatNameLookup = array( - 0 => 'unspecified format', - 1 => '8-bit mu-law', - 2 => '8-bit linear', - 3 => '16-bit linear', - 4 => '24-bit linear', - 5 => '32-bit linear', - 6 => 'floating-point', - 7 => 'double-precision float', - 8 => 'fragmented sampled data', - 9 => 'SUN_FORMAT_NESTED', - 10 => 'DSP program', - 11 => '8-bit fixed-point', - 12 => '16-bit fixed-point', - 13 => '24-bit fixed-point', - 14 => '32-bit fixed-point', - - 16 => 'non-audio display data', - 17 => 'SND_FORMAT_MULAW_SQUELCH', - 18 => '16-bit linear with emphasis', - 19 => '16-bit linear with compression', - 20 => '16-bit linear with emphasis + compression', - 21 => 'Music Kit DSP commands', - 22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES', - 23 => 'CCITT g.721 4-bit ADPCM', - 24 => 'CCITT g.722 ADPCM', - 25 => 'CCITT g.723 3-bit ADPCM', - 26 => 'CCITT g.723 5-bit ADPCM', - 27 => 'A-Law 8-bit' - ); - return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false); - } - - public function AUdataFormatBitsPerSampleLookup($id) { - static $AUdataFormatBitsPerSampleLookup = array( - 1 => 8, - 2 => 8, - 3 => 16, - 4 => 24, - 5 => 32, - 6 => 32, - 7 => 64, - - 11 => 8, - 12 => 16, - 13 => 24, - 14 => 32, - - 18 => 16, - 19 => 16, - 20 => 16, - - 23 => 16, - - 25 => 16, - 26 => 16, - 27 => 8 - ); - return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false); - } - - public function AUdataFormatUsedBitsPerSampleLookup($id) { - static $AUdataFormatUsedBitsPerSampleLookup = array( - 1 => 8, - 2 => 8, - 3 => 16, - 4 => 24, - 5 => 32, - 6 => 32, - 7 => 64, - - 11 => 8, - 12 => 16, - 13 => 24, - 14 => 32, - - 18 => 16, - 19 => 16, - 20 => 16, - - 23 => 4, - - 25 => 3, - 26 => 5, - 27 => 8, - ); - return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.au.php // +// module for analyzing AU files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_au extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $AUheader = fread($this->getid3->fp, 8); + + $magic = '.snd'; + if (substr($AUheader, 0, 4) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" (".snd") at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($AUheader, 0, 4)).'"'; + return false; + } + + // shortcut + $info['au'] = array(); + $thisfile_au = &$info['au']; + + $info['fileformat'] = 'au'; + $info['audio']['dataformat'] = 'au'; + $info['audio']['bitrate_mode'] = 'cbr'; + $thisfile_au['encoding'] = 'ISO-8859-1'; + + $thisfile_au['header_length'] = getid3_lib::BigEndian2Int(substr($AUheader, 4, 4)); + $AUheader .= fread($this->getid3->fp, $thisfile_au['header_length'] - 8); + $info['avdataoffset'] += $thisfile_au['header_length']; + + $thisfile_au['data_size'] = getid3_lib::BigEndian2Int(substr($AUheader, 8, 4)); + $thisfile_au['data_format_id'] = getid3_lib::BigEndian2Int(substr($AUheader, 12, 4)); + $thisfile_au['sample_rate'] = getid3_lib::BigEndian2Int(substr($AUheader, 16, 4)); + $thisfile_au['channels'] = getid3_lib::BigEndian2Int(substr($AUheader, 20, 4)); + $thisfile_au['comments']['comment'][] = trim(substr($AUheader, 24)); + + $thisfile_au['data_format'] = $this->AUdataFormatNameLookup($thisfile_au['data_format_id']); + $thisfile_au['used_bits_per_sample'] = $this->AUdataFormatUsedBitsPerSampleLookup($thisfile_au['data_format_id']); + if ($thisfile_au['bits_per_sample'] = $this->AUdataFormatBitsPerSampleLookup($thisfile_au['data_format_id'])) { + $info['audio']['bits_per_sample'] = $thisfile_au['bits_per_sample']; + } else { + unset($thisfile_au['bits_per_sample']); + } + + $info['audio']['sample_rate'] = $thisfile_au['sample_rate']; + $info['audio']['channels'] = $thisfile_au['channels']; + + if (($info['avdataoffset'] + $thisfile_au['data_size']) > $info['avdataend']) { + $info['warning'][] = 'Possible truncated file - expecting "'.$thisfile_au['data_size'].'" bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' bytes"'; + } + + $info['playtime_seconds'] = $thisfile_au['data_size'] / ($thisfile_au['sample_rate'] * $thisfile_au['channels'] * ($thisfile_au['used_bits_per_sample'] / 8)); + $info['audio']['bitrate'] = ($thisfile_au['data_size'] * 8) / $info['playtime_seconds']; + + return true; + } + + public function AUdataFormatNameLookup($id) { + static $AUdataFormatNameLookup = array( + 0 => 'unspecified format', + 1 => '8-bit mu-law', + 2 => '8-bit linear', + 3 => '16-bit linear', + 4 => '24-bit linear', + 5 => '32-bit linear', + 6 => 'floating-point', + 7 => 'double-precision float', + 8 => 'fragmented sampled data', + 9 => 'SUN_FORMAT_NESTED', + 10 => 'DSP program', + 11 => '8-bit fixed-point', + 12 => '16-bit fixed-point', + 13 => '24-bit fixed-point', + 14 => '32-bit fixed-point', + + 16 => 'non-audio display data', + 17 => 'SND_FORMAT_MULAW_SQUELCH', + 18 => '16-bit linear with emphasis', + 19 => '16-bit linear with compression', + 20 => '16-bit linear with emphasis + compression', + 21 => 'Music Kit DSP commands', + 22 => 'SND_FORMAT_DSP_COMMANDS_SAMPLES', + 23 => 'CCITT g.721 4-bit ADPCM', + 24 => 'CCITT g.722 ADPCM', + 25 => 'CCITT g.723 3-bit ADPCM', + 26 => 'CCITT g.723 5-bit ADPCM', + 27 => 'A-Law 8-bit' + ); + return (isset($AUdataFormatNameLookup[$id]) ? $AUdataFormatNameLookup[$id] : false); + } + + public function AUdataFormatBitsPerSampleLookup($id) { + static $AUdataFormatBitsPerSampleLookup = array( + 1 => 8, + 2 => 8, + 3 => 16, + 4 => 24, + 5 => 32, + 6 => 32, + 7 => 64, + + 11 => 8, + 12 => 16, + 13 => 24, + 14 => 32, + + 18 => 16, + 19 => 16, + 20 => 16, + + 23 => 16, + + 25 => 16, + 26 => 16, + 27 => 8 + ); + return (isset($AUdataFormatBitsPerSampleLookup[$id]) ? $AUdataFormatBitsPerSampleLookup[$id] : false); + } + + public function AUdataFormatUsedBitsPerSampleLookup($id) { + static $AUdataFormatUsedBitsPerSampleLookup = array( + 1 => 8, + 2 => 8, + 3 => 16, + 4 => 24, + 5 => 32, + 6 => 32, + 7 => 64, + + 11 => 8, + 12 => 16, + 13 => 24, + 14 => 32, + + 18 => 16, + 19 => 16, + 20 => 16, + + 23 => 4, + + 25 => 3, + 26 => 5, + 27 => 8, + ); + return (isset($AUdataFormatUsedBitsPerSampleLookup[$id]) ? $AUdataFormatUsedBitsPerSampleLookup[$id] : false); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.avr.php b/app/libs/vendor/getid3/module.audio.avr.php index 0f19357f..77107eae 100644 --- a/app/libs/vendor/getid3/module.audio.avr.php +++ b/app/libs/vendor/getid3/module.audio.avr.php @@ -1,124 +1,124 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.avr.php // -// module for analyzing AVR Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_avr extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html - // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html - // offset type length name comments - // --------------------------------------------------------------------- - // 0 char 4 ID format ID == "2BIT" - // 4 char 8 name sample name (unused space filled with 0) - // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo - // With stereo, samples are alternated, - // the first voice is the left : - // (LRLRLRLRLRLRLRLRLR...) - // 14 short 1 resolution 8, 12 or 16 (bits) - // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed - // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on - // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127 - // 0xFFFF means "no MIDI note defined" - // 22 byte 1 Replay speed Frequence in the Replay software - // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz, - // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz - // 6=43.885 Khz, 7=47.261 Khz - // -1 (0xFF)=no defined Frequence - // 23 byte 3 sample rate in Hertz - // 26 long 1 size in bytes (2 * bytes in stereo) - // 30 long 1 loop begin 0 for no loop - // 34 long 1 loop size equal to 'size' for no loop - // 38 short 2 Reserved, MIDI keyboard split */ - // 40 short 2 Reserved, sample compression */ - // 42 short 2 Reserved */ - // 44 char 20; Additional filename space, used if (name[7] != 0) - // 64 byte 64 user data - // 128 bytes ? sample data (12 bits samples are coded on 16 bits: - // 0000 xxxx xxxx xxxx) - // --------------------------------------------------------------------- - - // Note that all values are in motorola (big-endian) format, and that long is - // assumed to be 4 bytes, and short 2 bytes. - // When reading the samples, you should handle both signed and unsigned data, - // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert - // 8-bit data between signed/unsigned just add 127 to the sample values. - // Simularly for 16-bit data you should add 32769 - - $info['fileformat'] = 'avr'; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $AVRheader = fread($this->getid3->fp, 128); - - $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4); - $magic = '2BIT'; - if ($info['avr']['raw']['magic'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"'; - unset($info['fileformat']); - unset($info['avr']); - return false; - } - $info['avdataoffset'] += 128; - - $info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8)); - $info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2)); - $info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2)); - $info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2)); - $info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2)); - $info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2)); - $info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1)); - $info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3)); - $info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4)); - $info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4)); - $info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4)); - $info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2)); - $info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2)); - $info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2)); - $info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20)); - $info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64)); - - $info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true); - $info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true); - $info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true); - - $info['avr']['midi_notes'] = array(); - if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) { - $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8; - } - if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) { - $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF); - } - - if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) { - $info['warning'][] = 'Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']); - } - - $info['audio']['dataformat'] = 'avr'; - $info['audio']['lossless'] = true; - $info['audio']['bitrate_mode'] = 'cbr'; - $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; - $info['audio']['sample_rate'] = $info['avr']['sample_rate']; - $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1); - $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate']; - $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds']; - - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.avr.php // +// module for analyzing AVR Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_avr extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + // http://cui.unige.ch/OSG/info/AudioFormats/ap11.html + // http://www.btinternet.com/~AnthonyJ/Atari/programming/avr_format.html + // offset type length name comments + // --------------------------------------------------------------------- + // 0 char 4 ID format ID == "2BIT" + // 4 char 8 name sample name (unused space filled with 0) + // 12 short 1 mono/stereo 0=mono, -1 (0xFFFF)=stereo + // With stereo, samples are alternated, + // the first voice is the left : + // (LRLRLRLRLRLRLRLRLR...) + // 14 short 1 resolution 8, 12 or 16 (bits) + // 16 short 1 signed or not 0=unsigned, -1 (0xFFFF)=signed + // 18 short 1 loop or not 0=no loop, -1 (0xFFFF)=loop on + // 20 short 1 MIDI note 0xFFnn, where 0 <= nn <= 127 + // 0xFFFF means "no MIDI note defined" + // 22 byte 1 Replay speed Frequence in the Replay software + // 0=5.485 Khz, 1=8.084 Khz, 2=10.971 Khz, + // 3=16.168 Khz, 4=21.942 Khz, 5=32.336 Khz + // 6=43.885 Khz, 7=47.261 Khz + // -1 (0xFF)=no defined Frequence + // 23 byte 3 sample rate in Hertz + // 26 long 1 size in bytes (2 * bytes in stereo) + // 30 long 1 loop begin 0 for no loop + // 34 long 1 loop size equal to 'size' for no loop + // 38 short 2 Reserved, MIDI keyboard split */ + // 40 short 2 Reserved, sample compression */ + // 42 short 2 Reserved */ + // 44 char 20; Additional filename space, used if (name[7] != 0) + // 64 byte 64 user data + // 128 bytes ? sample data (12 bits samples are coded on 16 bits: + // 0000 xxxx xxxx xxxx) + // --------------------------------------------------------------------- + + // Note that all values are in motorola (big-endian) format, and that long is + // assumed to be 4 bytes, and short 2 bytes. + // When reading the samples, you should handle both signed and unsigned data, + // and be prepared to convert 16->8 bit, or mono->stereo if needed. To convert + // 8-bit data between signed/unsigned just add 127 to the sample values. + // Simularly for 16-bit data you should add 32769 + + $info['fileformat'] = 'avr'; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $AVRheader = fread($this->getid3->fp, 128); + + $info['avr']['raw']['magic'] = substr($AVRheader, 0, 4); + $magic = '2BIT'; + if ($info['avr']['raw']['magic'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['avr']['raw']['magic']).'"'; + unset($info['fileformat']); + unset($info['avr']); + return false; + } + $info['avdataoffset'] += 128; + + $info['avr']['sample_name'] = rtrim(substr($AVRheader, 4, 8)); + $info['avr']['raw']['mono'] = getid3_lib::BigEndian2Int(substr($AVRheader, 12, 2)); + $info['avr']['bits_per_sample'] = getid3_lib::BigEndian2Int(substr($AVRheader, 14, 2)); + $info['avr']['raw']['signed'] = getid3_lib::BigEndian2Int(substr($AVRheader, 16, 2)); + $info['avr']['raw']['loop'] = getid3_lib::BigEndian2Int(substr($AVRheader, 18, 2)); + $info['avr']['raw']['midi'] = getid3_lib::BigEndian2Int(substr($AVRheader, 20, 2)); + $info['avr']['raw']['replay_freq'] = getid3_lib::BigEndian2Int(substr($AVRheader, 22, 1)); + $info['avr']['sample_rate'] = getid3_lib::BigEndian2Int(substr($AVRheader, 23, 3)); + $info['avr']['sample_length'] = getid3_lib::BigEndian2Int(substr($AVRheader, 26, 4)); + $info['avr']['loop_start'] = getid3_lib::BigEndian2Int(substr($AVRheader, 30, 4)); + $info['avr']['loop_end'] = getid3_lib::BigEndian2Int(substr($AVRheader, 34, 4)); + $info['avr']['midi_split'] = getid3_lib::BigEndian2Int(substr($AVRheader, 38, 2)); + $info['avr']['sample_compression'] = getid3_lib::BigEndian2Int(substr($AVRheader, 40, 2)); + $info['avr']['reserved'] = getid3_lib::BigEndian2Int(substr($AVRheader, 42, 2)); + $info['avr']['sample_name_extra'] = rtrim(substr($AVRheader, 44, 20)); + $info['avr']['comment'] = rtrim(substr($AVRheader, 64, 64)); + + $info['avr']['flags']['stereo'] = (($info['avr']['raw']['mono'] == 0) ? false : true); + $info['avr']['flags']['signed'] = (($info['avr']['raw']['signed'] == 0) ? false : true); + $info['avr']['flags']['loop'] = (($info['avr']['raw']['loop'] == 0) ? false : true); + + $info['avr']['midi_notes'] = array(); + if (($info['avr']['raw']['midi'] & 0xFF00) != 0xFF00) { + $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0xFF00) >> 8; + } + if (($info['avr']['raw']['midi'] & 0x00FF) != 0x00FF) { + $info['avr']['midi_notes'][] = ($info['avr']['raw']['midi'] & 0x00FF); + } + + if (($info['avdataend'] - $info['avdataoffset']) != ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2))) { + $info['warning'][] = 'Probable truncated file: expecting '.($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 1 : 2)).' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']); + } + + $info['audio']['dataformat'] = 'avr'; + $info['audio']['lossless'] = true; + $info['audio']['bitrate_mode'] = 'cbr'; + $info['audio']['bits_per_sample'] = $info['avr']['bits_per_sample']; + $info['audio']['sample_rate'] = $info['avr']['sample_rate']; + $info['audio']['channels'] = ($info['avr']['flags']['stereo'] ? 2 : 1); + $info['playtime_seconds'] = ($info['avr']['sample_length'] / $info['audio']['channels']) / $info['avr']['sample_rate']; + $info['audio']['bitrate'] = ($info['avr']['sample_length'] * (($info['avr']['bits_per_sample'] == 8) ? 8 : 16)) / $info['playtime_seconds']; + + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.bonk.php b/app/libs/vendor/getid3/module.audio.bonk.php index a57065a1..e96be5b1 100644 --- a/app/libs/vendor/getid3/module.audio.bonk.php +++ b/app/libs/vendor/getid3/module.audio.bonk.php @@ -1,227 +1,227 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.la.php // -// module for analyzing BONK audio files // -// dependencies: module.tag.id3v2.php (optional) // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_bonk extends getid3_handler -{ - public function Analyze() { - $info = &$this->getid3->info; - - // shortcut - $info['bonk'] = array(); - $thisfile_bonk = &$info['bonk']; - - $thisfile_bonk['dataoffset'] = $info['avdataoffset']; - $thisfile_bonk['dataend'] = $info['avdataend']; - - if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) { - - $info['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB'; - - } else { - - // scan-from-end method, for v0.6 and higher - fseek($this->getid3->fp, $thisfile_bonk['dataend'] - 8, SEEK_SET); - $PossibleBonkTag = fread($this->getid3->fp, 8); - while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) { - $BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4)); - fseek($this->getid3->fp, 0 - $BonkTagSize, SEEK_CUR); - $BonkTagOffset = ftell($this->getid3->fp); - $TagHeaderTest = fread($this->getid3->fp, 5); - if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"'; - return false; - } - $BonkTagName = substr($TagHeaderTest, 1, 4); - - $thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize; - $thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset; - $this->HandleBonkTags($BonkTagName); - $NextTagEndOffset = $BonkTagOffset - 8; - if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) { - if (empty($info['audio']['encoder'])) { - $info['audio']['encoder'] = 'Extended BONK v0.9+'; - } - return true; - } - fseek($this->getid3->fp, $NextTagEndOffset, SEEK_SET); - $PossibleBonkTag = fread($this->getid3->fp, 8); - } - - } - - // seek-from-beginning method for v0.4 and v0.5 - if (empty($thisfile_bonk['BONK'])) { - fseek($this->getid3->fp, $thisfile_bonk['dataoffset'], SEEK_SET); - do { - $TagHeaderTest = fread($this->getid3->fp, 5); - switch ($TagHeaderTest) { - case "\x00".'BONK': - if (empty($info['audio']['encoder'])) { - $info['audio']['encoder'] = 'BONK v0.4'; - } - break; - - case "\x00".'INFO': - $info['audio']['encoder'] = 'Extended BONK v0.5'; - break; - - default: - break 2; - } - $BonkTagName = substr($TagHeaderTest, 1, 4); - $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset']; - $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset']; - $this->HandleBonkTags($BonkTagName); - - } while (true); - } - - // parse META block for v0.6 - v0.8 - if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) { - fseek($this->getid3->fp, $thisfile_bonk['META']['tags']['info'], SEEK_SET); - $TagHeaderTest = fread($this->getid3->fp, 5); - if ($TagHeaderTest == "\x00".'INFO') { - $info['audio']['encoder'] = 'Extended BONK v0.6 - v0.8'; - - $BonkTagName = substr($TagHeaderTest, 1, 4); - $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset']; - $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset']; - $this->HandleBonkTags($BonkTagName); - } - } - - if (empty($info['audio']['encoder'])) { - $info['audio']['encoder'] = 'Extended BONK v0.9+'; - } - if (empty($thisfile_bonk['BONK'])) { - unset($info['bonk']); - } - return true; - - } - - public function HandleBonkTags($BonkTagName) { - $info = &$this->getid3->info; - switch ($BonkTagName) { - case 'BONK': - // shortcut - $thisfile_bonk_BONK = &$info['bonk']['BONK']; - - $BonkData = "\x00".'BONK'.fread($this->getid3->fp, 17); - $thisfile_bonk_BONK['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1)); - $thisfile_bonk_BONK['number_samples'] = getid3_lib::LittleEndian2Int(substr($BonkData, 6, 4)); - $thisfile_bonk_BONK['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BonkData, 10, 4)); - - $thisfile_bonk_BONK['channels'] = getid3_lib::LittleEndian2Int(substr($BonkData, 14, 1)); - $thisfile_bonk_BONK['lossless'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 15, 1)); - $thisfile_bonk_BONK['joint_stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 16, 1)); - $thisfile_bonk_BONK['number_taps'] = getid3_lib::LittleEndian2Int(substr($BonkData, 17, 2)); - $thisfile_bonk_BONK['downsampling_ratio'] = getid3_lib::LittleEndian2Int(substr($BonkData, 19, 1)); - $thisfile_bonk_BONK['samples_per_packet'] = getid3_lib::LittleEndian2Int(substr($BonkData, 20, 2)); - - $info['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17; - $info['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size']; - - $info['fileformat'] = 'bonk'; - $info['audio']['dataformat'] = 'bonk'; - $info['audio']['bitrate_mode'] = 'vbr'; // assumed - $info['audio']['channels'] = $thisfile_bonk_BONK['channels']; - $info['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate']; - $info['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo'); - $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless']; - $info['audio']['codec'] = 'bonk'; - - $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); - if ($info['playtime_seconds'] > 0) { - $info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds']; - } - break; - - case 'INFO': - // shortcut - $thisfile_bonk_INFO = &$info['bonk']['INFO']; - - $thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); - $thisfile_bonk_INFO['entries_count'] = 0; - $NextInfoDataPair = fread($this->getid3->fp, 5); - if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { - while (!feof($this->getid3->fp)) { - //$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4)); - //$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1)); - //$thisfile_bonk_INFO[] = $CurrentSeekInfo; - - $NextInfoDataPair = fread($this->getid3->fp, 5); - if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { - fseek($this->getid3->fp, -5, SEEK_CUR); - break; - } - $thisfile_bonk_INFO['entries_count']++; - } - } - break; - - case 'META': - $BonkData = "\x00".'META'.fread($this->getid3->fp, $info['bonk']['META']['size'] - 5); - $info['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1)); - - $MetaTagEntries = floor(((strlen($BonkData) - 8) - 6) / 8); // BonkData - xxxxmeta - ØMETA - $offset = 6; - for ($i = 0; $i < $MetaTagEntries; $i++) { - $MetaEntryTagName = substr($BonkData, $offset, 4); - $offset += 4; - $MetaEntryTagOffset = getid3_lib::LittleEndian2Int(substr($BonkData, $offset, 4)); - $offset += 4; - $info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset; - } - break; - - case ' ID3': - $info['audio']['encoder'] = 'Extended BONK v0.9+'; - - // ID3v2 checking is optional - if (class_exists('getid3_id3v2')) { - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_id3v2 = new getid3_id3v2($getid3_temp); - $getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2; - $info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze(); - if ($info['bonk'][' ID3']['valid']) { - $info['id3v2'] = $getid3_temp->info['id3v2']; - } - unset($getid3_temp, $getid3_id3v2); - } - break; - - default: - $info['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset']; - break; - - } - } - - public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) { - static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META'); - foreach ($BonkIsValidTagName as $validtagname) { - if ($validtagname == $PossibleBonkTag) { - return true; - } elseif ($ignorecase && (strtolower($validtagname) == strtolower($PossibleBonkTag))) { - return true; - } - } - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.la.php // +// module for analyzing BONK audio files // +// dependencies: module.tag.id3v2.php (optional) // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_bonk extends getid3_handler +{ + public function Analyze() { + $info = &$this->getid3->info; + + // shortcut + $info['bonk'] = array(); + $thisfile_bonk = &$info['bonk']; + + $thisfile_bonk['dataoffset'] = $info['avdataoffset']; + $thisfile_bonk['dataend'] = $info['avdataend']; + + if (!getid3_lib::intValueSupported($thisfile_bonk['dataend'])) { + + $info['warning'][] = 'Unable to parse BONK file from end (v0.6+ preferred method) because PHP filesystem functions only support up to '.round(PHP_INT_MAX / 1073741824).'GB'; + + } else { + + // scan-from-end method, for v0.6 and higher + fseek($this->getid3->fp, $thisfile_bonk['dataend'] - 8, SEEK_SET); + $PossibleBonkTag = fread($this->getid3->fp, 8); + while ($this->BonkIsValidTagName(substr($PossibleBonkTag, 4, 4), true)) { + $BonkTagSize = getid3_lib::LittleEndian2Int(substr($PossibleBonkTag, 0, 4)); + fseek($this->getid3->fp, 0 - $BonkTagSize, SEEK_CUR); + $BonkTagOffset = ftell($this->getid3->fp); + $TagHeaderTest = fread($this->getid3->fp, 5); + if (($TagHeaderTest{0} != "\x00") || (substr($PossibleBonkTag, 4, 4) != strtolower(substr($PossibleBonkTag, 4, 4)))) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes("\x00".strtoupper(substr($PossibleBonkTag, 4, 4))).'" at offset '.$BonkTagOffset.', found "'.getid3_lib::PrintHexBytes($TagHeaderTest).'"'; + return false; + } + $BonkTagName = substr($TagHeaderTest, 1, 4); + + $thisfile_bonk[$BonkTagName]['size'] = $BonkTagSize; + $thisfile_bonk[$BonkTagName]['offset'] = $BonkTagOffset; + $this->HandleBonkTags($BonkTagName); + $NextTagEndOffset = $BonkTagOffset - 8; + if ($NextTagEndOffset < $thisfile_bonk['dataoffset']) { + if (empty($info['audio']['encoder'])) { + $info['audio']['encoder'] = 'Extended BONK v0.9+'; + } + return true; + } + fseek($this->getid3->fp, $NextTagEndOffset, SEEK_SET); + $PossibleBonkTag = fread($this->getid3->fp, 8); + } + + } + + // seek-from-beginning method for v0.4 and v0.5 + if (empty($thisfile_bonk['BONK'])) { + fseek($this->getid3->fp, $thisfile_bonk['dataoffset'], SEEK_SET); + do { + $TagHeaderTest = fread($this->getid3->fp, 5); + switch ($TagHeaderTest) { + case "\x00".'BONK': + if (empty($info['audio']['encoder'])) { + $info['audio']['encoder'] = 'BONK v0.4'; + } + break; + + case "\x00".'INFO': + $info['audio']['encoder'] = 'Extended BONK v0.5'; + break; + + default: + break 2; + } + $BonkTagName = substr($TagHeaderTest, 1, 4); + $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset']; + $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset']; + $this->HandleBonkTags($BonkTagName); + + } while (true); + } + + // parse META block for v0.6 - v0.8 + if (empty($thisfile_bonk['INFO']) && isset($thisfile_bonk['META']['tags']['info'])) { + fseek($this->getid3->fp, $thisfile_bonk['META']['tags']['info'], SEEK_SET); + $TagHeaderTest = fread($this->getid3->fp, 5); + if ($TagHeaderTest == "\x00".'INFO') { + $info['audio']['encoder'] = 'Extended BONK v0.6 - v0.8'; + + $BonkTagName = substr($TagHeaderTest, 1, 4); + $thisfile_bonk[$BonkTagName]['size'] = $thisfile_bonk['dataend'] - $thisfile_bonk['dataoffset']; + $thisfile_bonk[$BonkTagName]['offset'] = $thisfile_bonk['dataoffset']; + $this->HandleBonkTags($BonkTagName); + } + } + + if (empty($info['audio']['encoder'])) { + $info['audio']['encoder'] = 'Extended BONK v0.9+'; + } + if (empty($thisfile_bonk['BONK'])) { + unset($info['bonk']); + } + return true; + + } + + public function HandleBonkTags($BonkTagName) { + $info = &$this->getid3->info; + switch ($BonkTagName) { + case 'BONK': + // shortcut + $thisfile_bonk_BONK = &$info['bonk']['BONK']; + + $BonkData = "\x00".'BONK'.fread($this->getid3->fp, 17); + $thisfile_bonk_BONK['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1)); + $thisfile_bonk_BONK['number_samples'] = getid3_lib::LittleEndian2Int(substr($BonkData, 6, 4)); + $thisfile_bonk_BONK['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BonkData, 10, 4)); + + $thisfile_bonk_BONK['channels'] = getid3_lib::LittleEndian2Int(substr($BonkData, 14, 1)); + $thisfile_bonk_BONK['lossless'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 15, 1)); + $thisfile_bonk_BONK['joint_stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BonkData, 16, 1)); + $thisfile_bonk_BONK['number_taps'] = getid3_lib::LittleEndian2Int(substr($BonkData, 17, 2)); + $thisfile_bonk_BONK['downsampling_ratio'] = getid3_lib::LittleEndian2Int(substr($BonkData, 19, 1)); + $thisfile_bonk_BONK['samples_per_packet'] = getid3_lib::LittleEndian2Int(substr($BonkData, 20, 2)); + + $info['avdataoffset'] = $thisfile_bonk_BONK['offset'] + 5 + 17; + $info['avdataend'] = $thisfile_bonk_BONK['offset'] + $thisfile_bonk_BONK['size']; + + $info['fileformat'] = 'bonk'; + $info['audio']['dataformat'] = 'bonk'; + $info['audio']['bitrate_mode'] = 'vbr'; // assumed + $info['audio']['channels'] = $thisfile_bonk_BONK['channels']; + $info['audio']['sample_rate'] = $thisfile_bonk_BONK['sample_rate']; + $info['audio']['channelmode'] = ($thisfile_bonk_BONK['joint_stereo'] ? 'joint stereo' : 'stereo'); + $info['audio']['lossless'] = $thisfile_bonk_BONK['lossless']; + $info['audio']['codec'] = 'bonk'; + + $info['playtime_seconds'] = $thisfile_bonk_BONK['number_samples'] / ($thisfile_bonk_BONK['sample_rate'] * $thisfile_bonk_BONK['channels']); + if ($info['playtime_seconds'] > 0) { + $info['audio']['bitrate'] = (($info['bonk']['dataend'] - $info['bonk']['dataoffset']) * 8) / $info['playtime_seconds']; + } + break; + + case 'INFO': + // shortcut + $thisfile_bonk_INFO = &$info['bonk']['INFO']; + + $thisfile_bonk_INFO['version'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); + $thisfile_bonk_INFO['entries_count'] = 0; + $NextInfoDataPair = fread($this->getid3->fp, 5); + if (!$this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { + while (!feof($this->getid3->fp)) { + //$CurrentSeekInfo['offset'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 0, 4)); + //$CurrentSeekInfo['nextbit'] = getid3_lib::LittleEndian2Int(substr($NextInfoDataPair, 4, 1)); + //$thisfile_bonk_INFO[] = $CurrentSeekInfo; + + $NextInfoDataPair = fread($this->getid3->fp, 5); + if ($this->BonkIsValidTagName(substr($NextInfoDataPair, 1, 4))) { + fseek($this->getid3->fp, -5, SEEK_CUR); + break; + } + $thisfile_bonk_INFO['entries_count']++; + } + } + break; + + case 'META': + $BonkData = "\x00".'META'.fread($this->getid3->fp, $info['bonk']['META']['size'] - 5); + $info['bonk']['META']['version'] = getid3_lib::LittleEndian2Int(substr($BonkData, 5, 1)); + + $MetaTagEntries = floor(((strlen($BonkData) - 8) - 6) / 8); // BonkData - xxxxmeta - ØMETA + $offset = 6; + for ($i = 0; $i < $MetaTagEntries; $i++) { + $MetaEntryTagName = substr($BonkData, $offset, 4); + $offset += 4; + $MetaEntryTagOffset = getid3_lib::LittleEndian2Int(substr($BonkData, $offset, 4)); + $offset += 4; + $info['bonk']['META']['tags'][$MetaEntryTagName] = $MetaEntryTagOffset; + } + break; + + case ' ID3': + $info['audio']['encoder'] = 'Extended BONK v0.9+'; + + // ID3v2 checking is optional + if (class_exists('getid3_id3v2')) { + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_id3v2 = new getid3_id3v2($getid3_temp); + $getid3_id3v2->StartingOffset = $info['bonk'][' ID3']['offset'] + 2; + $info['bonk'][' ID3']['valid'] = $getid3_id3v2->Analyze(); + if ($info['bonk'][' ID3']['valid']) { + $info['id3v2'] = $getid3_temp->info['id3v2']; + } + unset($getid3_temp, $getid3_id3v2); + } + break; + + default: + $info['warning'][] = 'Unexpected Bonk tag "'.$BonkTagName.'" at offset '.$info['bonk'][$BonkTagName]['offset']; + break; + + } + } + + public static function BonkIsValidTagName($PossibleBonkTag, $ignorecase=false) { + static $BonkIsValidTagName = array('BONK', 'INFO', ' ID3', 'META'); + foreach ($BonkIsValidTagName as $validtagname) { + if ($validtagname == $PossibleBonkTag) { + return true; + } elseif ($ignorecase && (strtolower($validtagname) == strtolower($PossibleBonkTag))) { + return true; + } + } + return false; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.dss.php b/app/libs/vendor/getid3/module.audio.dss.php index ac208b61..4719d53b 100644 --- a/app/libs/vendor/getid3/module.audio.dss.php +++ b/app/libs/vendor/getid3/module.audio.dss.php @@ -1,77 +1,77 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.dss.php // -// module for analyzing Digital Speech Standard (DSS) files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_dss extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $DSSheader = fread($this->getid3->fp, 1256); - - if (!preg_match('#^(\x02|\x03)ds[s2]#', $DSSheader)) { - $info['error'][] = 'Expecting "[02-03] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"'; - return false; - } - - // some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm - $info['encoding'] = 'ISO-8859-1'; // not certain, but assumed - $info['dss'] = array(); - - $info['fileformat'] = 'dss'; - $info['mime_type'] = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2" - $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2" - $info['audio']['bitrate_mode'] = 'cbr'; - - $info['dss']['version'] = ord(substr($DSSheader, 0, 1)); - $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400" - $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4)); - // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen - $info['dss']['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12)); - $info['dss']['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12)); - $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS - $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512 - $info['dss']['priority'] = ord(substr($DSSheader, 793, 1)); - $info['dss']['comments'] = trim(substr($DSSheader, 798, 100)); - - //$info['audio']['bits_per_sample'] = ?; - //$info['audio']['sample_rate'] = ?; - $info['audio']['channels'] = 1; - - $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000; - if (floor($info['dss']['playtime_ms'] / 1000) != $info['dss']['playtime_sec']) { - // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check - $info['playtime_seconds'] = $info['dss']['playtime_sec']; - $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value'); - } - $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds']; - - return true; - } - - public function DSSdateStringToUnixDate($datestring) { - $y = substr($datestring, 0, 2); - $m = substr($datestring, 2, 2); - $d = substr($datestring, 4, 2); - $h = substr($datestring, 6, 2); - $i = substr($datestring, 8, 2); - $s = substr($datestring, 10, 2); - $y += (($y < 95) ? 2000 : 1900); - return mktime($h, $i, $s, $m, $d, $y); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.dss.php // +// module for analyzing Digital Speech Standard (DSS) files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_dss extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $DSSheader = fread($this->getid3->fp, 1256); + + if (!preg_match('#^(\x02|\x03)ds[s2]#', $DSSheader)) { + $info['error'][] = 'Expecting "[02-03] 64 73 [73|32]" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($DSSheader, 0, 4)).'"'; + return false; + } + + // some structure information taken from http://cpansearch.perl.org/src/RGIBSON/Audio-DSS-0.02/lib/Audio/DSS.pm + $info['encoding'] = 'ISO-8859-1'; // not certain, but assumed + $info['dss'] = array(); + + $info['fileformat'] = 'dss'; + $info['mime_type'] = 'audio/x-'.substr($DSSheader, 1, 3); // "audio/x-dss" or "audio/x-ds2" + $info['audio']['dataformat'] = substr($DSSheader, 1, 3); // "dss" or "ds2" + $info['audio']['bitrate_mode'] = 'cbr'; + + $info['dss']['version'] = ord(substr($DSSheader, 0, 1)); + $info['dss']['hardware'] = trim(substr($DSSheader, 12, 16)); // identification string for hardware used to create the file, e.g. "DPM 9600", "DS2400" + $info['dss']['unknown1'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 28, 4)); + // 32-37 = "FE FF FE FF F7 FF" in all the sample files I've seen + $info['dss']['date_create'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 38, 12)); + $info['dss']['date_complete'] = $this->DSSdateStringToUnixDate(substr($DSSheader, 50, 12)); + $info['dss']['playtime_sec'] = intval((substr($DSSheader, 62, 2) * 3600) + (substr($DSSheader, 64, 2) * 60) + substr($DSSheader, 66, 2)); // approximate file playtime in HHMMSS + $info['dss']['playtime_ms'] = getid3_lib::LittleEndian2Int(substr($DSSheader, 512, 4)); // exact file playtime in milliseconds. Has also been observed at offset 530 in one sample file, with something else (unknown) at offset 512 + $info['dss']['priority'] = ord(substr($DSSheader, 793, 1)); + $info['dss']['comments'] = trim(substr($DSSheader, 798, 100)); + + //$info['audio']['bits_per_sample'] = ?; + //$info['audio']['sample_rate'] = ?; + $info['audio']['channels'] = 1; + + $info['playtime_seconds'] = $info['dss']['playtime_ms'] / 1000; + if (floor($info['dss']['playtime_ms'] / 1000) != $info['dss']['playtime_sec']) { + // *should* just be playtime_ms / 1000 but at least one sample file has playtime_ms at offset 530 instead of offset 512, so safety check + $info['playtime_seconds'] = $info['dss']['playtime_sec']; + $this->getid3->warning('playtime_ms ('.number_format($info['dss']['playtime_ms'] / 1000, 3).') does not match playtime_sec ('.number_format($info['dss']['playtime_sec']).') - using playtime_sec value'); + } + $info['audio']['bitrate'] = ($info['filesize'] * 8) / $info['playtime_seconds']; + + return true; + } + + public function DSSdateStringToUnixDate($datestring) { + $y = substr($datestring, 0, 2); + $m = substr($datestring, 2, 2); + $d = substr($datestring, 4, 2); + $h = substr($datestring, 6, 2); + $i = substr($datestring, 8, 2); + $s = substr($datestring, 10, 2); + $y += (($y < 95) ? 2000 : 1900); + return mktime($h, $i, $s, $m, $d, $y); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.dts.php b/app/libs/vendor/getid3/module.audio.dts.php index 5aeddee7..79982ccc 100644 --- a/app/libs/vendor/getid3/module.audio.dts.php +++ b/app/libs/vendor/getid3/module.audio.dts.php @@ -1,290 +1,290 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.dts.php // -// module for analyzing DTS Audio files // -// dependencies: NONE // -// // -///////////////////////////////////////////////////////////////// - - -/** -* @tutorial http://wiki.multimedia.cx/index.php?title=DTS -*/ -class getid3_dts extends getid3_handler -{ - /** - * Default DTS syncword used in native .cpt or .dts formats - */ - const syncword = "\x7F\xFE\x80\x01"; - - private $readBinDataOffset = 0; - - /** - * Possible syncwords indicating bitstream encoding - */ - public static $syncwords = array( - 0 => "\x7F\xFE\x80\x01", // raw big-endian - 1 => "\xFE\x7F\x01\x80", // raw little-endian - 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian - 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian - - public function Analyze() { - $info = &$this->getid3->info; - $info['fileformat'] = 'dts'; - - $this->fseek($info['avdataoffset']); - $DTSheader = $this->fread(20); // we only need 2 words magic + 6 words frame header, but these words may be normal 16-bit words OR 14-bit words with 2 highest bits set to zero, so 8 words can be either 8*16/8 = 16 bytes OR 8*16*(16/14)/8 = 18.3 bytes - - // check syncword - $sync = substr($DTSheader, 0, 4); - if (($encoding = array_search($sync, self::$syncwords)) !== false) { - - $info['dts']['raw']['magic'] = $sync; - $this->readBinDataOffset = 32; - - } elseif ($this->isDependencyFor('matroska')) { - - // Matroska contains DTS without syncword encoded as raw big-endian format - $encoding = 0; - $this->readBinDataOffset = 0; - - } else { - - unset($info['fileformat']); - return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"'); - - } - - // decode header - $fhBS = ''; - for ($word_offset = 0; $word_offset <= strlen($DTSheader); $word_offset += 2) { - switch ($encoding) { - case 0: // raw big-endian - $fhBS .= getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ); - break; - case 1: // raw little-endian - $fhBS .= getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))); - break; - case 2: // 14-bit big-endian - $fhBS .= substr(getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ), 2, 14); - break; - case 3: // 14-bit little-endian - $fhBS .= substr(getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))), 2, 14); - break; - } - } - - $info['dts']['raw']['frame_type'] = $this->readBinData($fhBS, 1); - $info['dts']['raw']['deficit_samples'] = $this->readBinData($fhBS, 5); - $info['dts']['flags']['crc_present'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['raw']['pcm_sample_blocks'] = $this->readBinData($fhBS, 7); - $info['dts']['raw']['frame_byte_size'] = $this->readBinData($fhBS, 14); - $info['dts']['raw']['channel_arrangement'] = $this->readBinData($fhBS, 6); - $info['dts']['raw']['sample_frequency'] = $this->readBinData($fhBS, 4); - $info['dts']['raw']['bitrate'] = $this->readBinData($fhBS, 5); - $info['dts']['flags']['embedded_downmix'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['dynamicrange'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['timestamp'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['auxdata'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['hdcd'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['raw']['extension_audio'] = $this->readBinData($fhBS, 3); - $info['dts']['flags']['extended_coding'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['raw']['lfe_effects'] = $this->readBinData($fhBS, 2); - $info['dts']['flags']['predictor_history'] = (bool) $this->readBinData($fhBS, 1); - if ($info['dts']['flags']['crc_present']) { - $info['dts']['raw']['crc16'] = $this->readBinData($fhBS, 16); - } - $info['dts']['flags']['mri_perfect_reconst'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['raw']['encoder_soft_version'] = $this->readBinData($fhBS, 4); - $info['dts']['raw']['copy_history'] = $this->readBinData($fhBS, 2); - $info['dts']['raw']['bits_per_sample'] = $this->readBinData($fhBS, 2); - $info['dts']['flags']['surround_es'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['front_sum_diff'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['flags']['surround_sum_diff'] = (bool) $this->readBinData($fhBS, 1); - $info['dts']['raw']['dialog_normalization'] = $this->readBinData($fhBS, 4); - - - $info['dts']['bitrate'] = self::bitrateLookup($info['dts']['raw']['bitrate']); - $info['dts']['bits_per_sample'] = self::bitPerSampleLookup($info['dts']['raw']['bits_per_sample']); - $info['dts']['sample_rate'] = self::sampleRateLookup($info['dts']['raw']['sample_frequency']); - $info['dts']['dialog_normalization'] = self::dialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']); - $info['dts']['flags']['lossless'] = (($info['dts']['raw']['bitrate'] == 31) ? true : false); - $info['dts']['bitrate_mode'] = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr'); - $info['dts']['channels'] = self::numChannelsLookup($info['dts']['raw']['channel_arrangement']); - $info['dts']['channel_arrangement'] = self::channelArrangementLookup($info['dts']['raw']['channel_arrangement']); - - $info['audio']['dataformat'] = 'dts'; - $info['audio']['lossless'] = $info['dts']['flags']['lossless']; - $info['audio']['bitrate_mode'] = $info['dts']['bitrate_mode']; - $info['audio']['bits_per_sample'] = $info['dts']['bits_per_sample']; - $info['audio']['sample_rate'] = $info['dts']['sample_rate']; - $info['audio']['channels'] = $info['dts']['channels']; - $info['audio']['bitrate'] = $info['dts']['bitrate']; - if (isset($info['avdataend']) && !empty($info['dts']['bitrate']) && is_numeric($info['dts']['bitrate'])) { - $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8); - if (($encoding == 2) || ($encoding == 3)) { - // 14-bit data packed into 16-bit words, so the playtime is wrong because only (14/16) of the bytes in the data portion of the file are used at the specified bitrate - $info['playtime_seconds'] *= (14 / 16); - } - } - return true; - } - - private function readBinData($bin, $length) { - $data = substr($bin, $this->readBinDataOffset, $length); - $this->readBinDataOffset += $length; - - return bindec($data); - } - - public static function bitrateLookup($index) { - static $lookup = array( - 0 => 32000, - 1 => 56000, - 2 => 64000, - 3 => 96000, - 4 => 112000, - 5 => 128000, - 6 => 192000, - 7 => 224000, - 8 => 256000, - 9 => 320000, - 10 => 384000, - 11 => 448000, - 12 => 512000, - 13 => 576000, - 14 => 640000, - 15 => 768000, - 16 => 960000, - 17 => 1024000, - 18 => 1152000, - 19 => 1280000, - 20 => 1344000, - 21 => 1408000, - 22 => 1411200, - 23 => 1472000, - 24 => 1536000, - 25 => 1920000, - 26 => 2048000, - 27 => 3072000, - 28 => 3840000, - 29 => 'open', - 30 => 'variable', - 31 => 'lossless', - ); - return (isset($lookup[$index]) ? $lookup[$index] : false); - } - - public static function sampleRateLookup($index) { - static $lookup = array( - 0 => 'invalid', - 1 => 8000, - 2 => 16000, - 3 => 32000, - 4 => 'invalid', - 5 => 'invalid', - 6 => 11025, - 7 => 22050, - 8 => 44100, - 9 => 'invalid', - 10 => 'invalid', - 11 => 12000, - 12 => 24000, - 13 => 48000, - 14 => 'invalid', - 15 => 'invalid', - ); - return (isset($lookup[$index]) ? $lookup[$index] : false); - } - - public static function bitPerSampleLookup($index) { - static $lookup = array( - 0 => 16, - 1 => 20, - 2 => 24, - 3 => 24, - ); - return (isset($lookup[$index]) ? $lookup[$index] : false); - } - - public static function numChannelsLookup($index) { - switch ($index) { - case 0: - return 1; - break; - case 1: - case 2: - case 3: - case 4: - return 2; - break; - case 5: - case 6: - return 3; - break; - case 7: - case 8: - return 4; - break; - case 9: - return 5; - break; - case 10: - case 11: - case 12: - return 6; - break; - case 13: - return 7; - break; - case 14: - case 15: - return 8; - break; - } - return false; - } - - public static function channelArrangementLookup($index) { - static $lookup = array( - 0 => 'A', - 1 => 'A + B (dual mono)', - 2 => 'L + R (stereo)', - 3 => '(L+R) + (L-R) (sum-difference)', - 4 => 'LT + RT (left and right total)', - 5 => 'C + L + R', - 6 => 'L + R + S', - 7 => 'C + L + R + S', - 8 => 'L + R + SL + SR', - 9 => 'C + L + R + SL + SR', - 10 => 'CL + CR + L + R + SL + SR', - 11 => 'C + L + R+ LR + RR + OV', - 12 => 'CF + CR + LF + RF + LR + RR', - 13 => 'CL + C + CR + L + R + SL + SR', - 14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2', - 15 => 'CL + C+ CR + L + R + SL + S + SR', - ); - return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined'); - } - - public static function dialogNormalization($index, $version) { - switch ($version) { - case 7: - return 0 - $index; - break; - case 6: - return 0 - 16 - $index; - break; - } - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.dts.php // +// module for analyzing DTS Audio files // +// dependencies: NONE // +// // +///////////////////////////////////////////////////////////////// + + +/** +* @tutorial http://wiki.multimedia.cx/index.php?title=DTS +*/ +class getid3_dts extends getid3_handler +{ + /** + * Default DTS syncword used in native .cpt or .dts formats + */ + const syncword = "\x7F\xFE\x80\x01"; + + private $readBinDataOffset = 0; + + /** + * Possible syncwords indicating bitstream encoding + */ + public static $syncwords = array( + 0 => "\x7F\xFE\x80\x01", // raw big-endian + 1 => "\xFE\x7F\x01\x80", // raw little-endian + 2 => "\x1F\xFF\xE8\x00", // 14-bit big-endian + 3 => "\xFF\x1F\x00\xE8"); // 14-bit little-endian + + public function Analyze() { + $info = &$this->getid3->info; + $info['fileformat'] = 'dts'; + + $this->fseek($info['avdataoffset']); + $DTSheader = $this->fread(20); // we only need 2 words magic + 6 words frame header, but these words may be normal 16-bit words OR 14-bit words with 2 highest bits set to zero, so 8 words can be either 8*16/8 = 16 bytes OR 8*16*(16/14)/8 = 18.3 bytes + + // check syncword + $sync = substr($DTSheader, 0, 4); + if (($encoding = array_search($sync, self::$syncwords)) !== false) { + + $info['dts']['raw']['magic'] = $sync; + $this->readBinDataOffset = 32; + + } elseif ($this->isDependencyFor('matroska')) { + + // Matroska contains DTS without syncword encoded as raw big-endian format + $encoding = 0; + $this->readBinDataOffset = 0; + + } else { + + unset($info['fileformat']); + return $this->error('Expecting "'.implode('| ', array_map('getid3_lib::PrintHexBytes', self::$syncwords)).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($sync).'"'); + + } + + // decode header + $fhBS = ''; + for ($word_offset = 0; $word_offset <= strlen($DTSheader); $word_offset += 2) { + switch ($encoding) { + case 0: // raw big-endian + $fhBS .= getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ); + break; + case 1: // raw little-endian + $fhBS .= getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))); + break; + case 2: // 14-bit big-endian + $fhBS .= substr(getid3_lib::BigEndian2Bin( substr($DTSheader, $word_offset, 2) ), 2, 14); + break; + case 3: // 14-bit little-endian + $fhBS .= substr(getid3_lib::BigEndian2Bin(strrev(substr($DTSheader, $word_offset, 2))), 2, 14); + break; + } + } + + $info['dts']['raw']['frame_type'] = $this->readBinData($fhBS, 1); + $info['dts']['raw']['deficit_samples'] = $this->readBinData($fhBS, 5); + $info['dts']['flags']['crc_present'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['raw']['pcm_sample_blocks'] = $this->readBinData($fhBS, 7); + $info['dts']['raw']['frame_byte_size'] = $this->readBinData($fhBS, 14); + $info['dts']['raw']['channel_arrangement'] = $this->readBinData($fhBS, 6); + $info['dts']['raw']['sample_frequency'] = $this->readBinData($fhBS, 4); + $info['dts']['raw']['bitrate'] = $this->readBinData($fhBS, 5); + $info['dts']['flags']['embedded_downmix'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['dynamicrange'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['timestamp'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['auxdata'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['hdcd'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['raw']['extension_audio'] = $this->readBinData($fhBS, 3); + $info['dts']['flags']['extended_coding'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['audio_sync_insertion'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['raw']['lfe_effects'] = $this->readBinData($fhBS, 2); + $info['dts']['flags']['predictor_history'] = (bool) $this->readBinData($fhBS, 1); + if ($info['dts']['flags']['crc_present']) { + $info['dts']['raw']['crc16'] = $this->readBinData($fhBS, 16); + } + $info['dts']['flags']['mri_perfect_reconst'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['raw']['encoder_soft_version'] = $this->readBinData($fhBS, 4); + $info['dts']['raw']['copy_history'] = $this->readBinData($fhBS, 2); + $info['dts']['raw']['bits_per_sample'] = $this->readBinData($fhBS, 2); + $info['dts']['flags']['surround_es'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['front_sum_diff'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['flags']['surround_sum_diff'] = (bool) $this->readBinData($fhBS, 1); + $info['dts']['raw']['dialog_normalization'] = $this->readBinData($fhBS, 4); + + + $info['dts']['bitrate'] = self::bitrateLookup($info['dts']['raw']['bitrate']); + $info['dts']['bits_per_sample'] = self::bitPerSampleLookup($info['dts']['raw']['bits_per_sample']); + $info['dts']['sample_rate'] = self::sampleRateLookup($info['dts']['raw']['sample_frequency']); + $info['dts']['dialog_normalization'] = self::dialogNormalization($info['dts']['raw']['dialog_normalization'], $info['dts']['raw']['encoder_soft_version']); + $info['dts']['flags']['lossless'] = (($info['dts']['raw']['bitrate'] == 31) ? true : false); + $info['dts']['bitrate_mode'] = (($info['dts']['raw']['bitrate'] == 30) ? 'vbr' : 'cbr'); + $info['dts']['channels'] = self::numChannelsLookup($info['dts']['raw']['channel_arrangement']); + $info['dts']['channel_arrangement'] = self::channelArrangementLookup($info['dts']['raw']['channel_arrangement']); + + $info['audio']['dataformat'] = 'dts'; + $info['audio']['lossless'] = $info['dts']['flags']['lossless']; + $info['audio']['bitrate_mode'] = $info['dts']['bitrate_mode']; + $info['audio']['bits_per_sample'] = $info['dts']['bits_per_sample']; + $info['audio']['sample_rate'] = $info['dts']['sample_rate']; + $info['audio']['channels'] = $info['dts']['channels']; + $info['audio']['bitrate'] = $info['dts']['bitrate']; + if (isset($info['avdataend']) && !empty($info['dts']['bitrate']) && is_numeric($info['dts']['bitrate'])) { + $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) / ($info['dts']['bitrate'] / 8); + if (($encoding == 2) || ($encoding == 3)) { + // 14-bit data packed into 16-bit words, so the playtime is wrong because only (14/16) of the bytes in the data portion of the file are used at the specified bitrate + $info['playtime_seconds'] *= (14 / 16); + } + } + return true; + } + + private function readBinData($bin, $length) { + $data = substr($bin, $this->readBinDataOffset, $length); + $this->readBinDataOffset += $length; + + return bindec($data); + } + + public static function bitrateLookup($index) { + static $lookup = array( + 0 => 32000, + 1 => 56000, + 2 => 64000, + 3 => 96000, + 4 => 112000, + 5 => 128000, + 6 => 192000, + 7 => 224000, + 8 => 256000, + 9 => 320000, + 10 => 384000, + 11 => 448000, + 12 => 512000, + 13 => 576000, + 14 => 640000, + 15 => 768000, + 16 => 960000, + 17 => 1024000, + 18 => 1152000, + 19 => 1280000, + 20 => 1344000, + 21 => 1408000, + 22 => 1411200, + 23 => 1472000, + 24 => 1536000, + 25 => 1920000, + 26 => 2048000, + 27 => 3072000, + 28 => 3840000, + 29 => 'open', + 30 => 'variable', + 31 => 'lossless', + ); + return (isset($lookup[$index]) ? $lookup[$index] : false); + } + + public static function sampleRateLookup($index) { + static $lookup = array( + 0 => 'invalid', + 1 => 8000, + 2 => 16000, + 3 => 32000, + 4 => 'invalid', + 5 => 'invalid', + 6 => 11025, + 7 => 22050, + 8 => 44100, + 9 => 'invalid', + 10 => 'invalid', + 11 => 12000, + 12 => 24000, + 13 => 48000, + 14 => 'invalid', + 15 => 'invalid', + ); + return (isset($lookup[$index]) ? $lookup[$index] : false); + } + + public static function bitPerSampleLookup($index) { + static $lookup = array( + 0 => 16, + 1 => 20, + 2 => 24, + 3 => 24, + ); + return (isset($lookup[$index]) ? $lookup[$index] : false); + } + + public static function numChannelsLookup($index) { + switch ($index) { + case 0: + return 1; + break; + case 1: + case 2: + case 3: + case 4: + return 2; + break; + case 5: + case 6: + return 3; + break; + case 7: + case 8: + return 4; + break; + case 9: + return 5; + break; + case 10: + case 11: + case 12: + return 6; + break; + case 13: + return 7; + break; + case 14: + case 15: + return 8; + break; + } + return false; + } + + public static function channelArrangementLookup($index) { + static $lookup = array( + 0 => 'A', + 1 => 'A + B (dual mono)', + 2 => 'L + R (stereo)', + 3 => '(L+R) + (L-R) (sum-difference)', + 4 => 'LT + RT (left and right total)', + 5 => 'C + L + R', + 6 => 'L + R + S', + 7 => 'C + L + R + S', + 8 => 'L + R + SL + SR', + 9 => 'C + L + R + SL + SR', + 10 => 'CL + CR + L + R + SL + SR', + 11 => 'C + L + R+ LR + RR + OV', + 12 => 'CF + CR + LF + RF + LR + RR', + 13 => 'CL + C + CR + L + R + SL + SR', + 14 => 'CL + CR + L + R + SL1 + SL2 + SR1 + SR2', + 15 => 'CL + C+ CR + L + R + SL + S + SR', + ); + return (isset($lookup[$index]) ? $lookup[$index] : 'user-defined'); + } + + public static function dialogNormalization($index, $version) { + switch ($version) { + case 7: + return 0 - $index; + break; + case 6: + return 0 - 16 - $index; + break; + } + return false; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.flac.php b/app/libs/vendor/getid3/module.audio.flac.php index de8bb558..6b9598c7 100644 --- a/app/libs/vendor/getid3/module.audio.flac.php +++ b/app/libs/vendor/getid3/module.audio.flac.php @@ -1,442 +1,442 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.flac.php // -// module for analyzing FLAC and OggFLAC audio files // -// dependencies: module.audio.ogg.php // -// /// -///////////////////////////////////////////////////////////////// - - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true); - -/** -* @tutorial http://flac.sourceforge.net/format.html -*/ -class getid3_flac extends getid3_handler -{ - const syncword = 'fLaC'; - - public function Analyze() { - $info = &$this->getid3->info; - - $this->fseek($info['avdataoffset']); - $StreamMarker = $this->fread(4); - if ($StreamMarker != self::syncword) { - return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"'); - } - $info['fileformat'] = 'flac'; - $info['audio']['dataformat'] = 'flac'; - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['lossless'] = true; - - // parse flac container - return $this->parseMETAdata(); - } - - public function parseMETAdata() { - $info = &$this->getid3->info; - do { - $BlockOffset = $this->ftell(); - $BlockHeader = $this->fread(4); - $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); - $LastBlockFlag = (bool) ($LBFBT & 0x80); - $BlockType = ($LBFBT & 0x7F); - $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3)); - $BlockTypeText = self::metaBlockTypeLookup($BlockType); - - if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) { - $this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file'); - break; - } - if ($BlockLength < 1) { - $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid'); - break; - } - - $info['flac'][$BlockTypeText]['raw'] = array(); - $BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw']; - - $BlockTypeText_raw['offset'] = $BlockOffset; - $BlockTypeText_raw['last_meta_block'] = $LastBlockFlag; - $BlockTypeText_raw['block_type'] = $BlockType; - $BlockTypeText_raw['block_type_text'] = $BlockTypeText; - $BlockTypeText_raw['block_length'] = $BlockLength; - if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically - $BlockTypeText_raw['block_data'] = $this->fread($BlockLength); - } - - switch ($BlockTypeText) { - case 'STREAMINFO': // 0x00 - if (!$this->parseSTREAMINFO($BlockTypeText_raw['block_data'])) { - return false; - } - break; - - case 'PADDING': // 0x01 - unset($info['flac']['PADDING']); // ignore - break; - - case 'APPLICATION': // 0x02 - if (!$this->parseAPPLICATION($BlockTypeText_raw['block_data'])) { - return false; - } - break; - - case 'SEEKTABLE': // 0x03 - if (!$this->parseSEEKTABLE($BlockTypeText_raw['block_data'])) { - return false; - } - break; - - case 'VORBIS_COMMENT': // 0x04 - if (!$this->parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) { - return false; - } - break; - - case 'CUESHEET': // 0x05 - if (!$this->parseCUESHEET($BlockTypeText_raw['block_data'])) { - return false; - } - break; - - case 'PICTURE': // 0x06 - if (!$this->parsePICTURE()) { - return false; - } - break; - - default: - $this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset); - } - - unset($info['flac'][$BlockTypeText]['raw']); - $info['avdataoffset'] = $this->ftell(); - } - while ($LastBlockFlag === false); - - // handle tags - if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) { - $info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments']; - } - if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) { - $info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']); - } - - // copy attachments to 'comments' array if nesesary - if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) { - foreach ($info['flac']['PICTURE'] as $entry) { - if (!empty($entry['data'])) { - $info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']); - } - } - } - - if (isset($info['flac']['STREAMINFO'])) { - if (!$this->isDependencyFor('matroska')) { - $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset']; - } - $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8); - if ($info['flac']['uncompressed_audio_bytes'] == 0) { - return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero'); - } - if (!empty($info['flac']['compressed_audio_bytes'])) { - $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes']; - } - } - - // set md5_data_source - built into flac 0.5+ - if (isset($info['flac']['STREAMINFO']['audio_signature'])) { - - if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { - $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'); - } - else { - $info['md5_data_source'] = ''; - $md5 = $info['flac']['STREAMINFO']['audio_signature']; - for ($i = 0; $i < strlen($md5); $i++) { - $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT); - } - if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) { - unset($info['md5_data_source']); - } - } - } - - if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) { - $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; - if ($info['audio']['bits_per_sample'] == 8) { - // special case - // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value - // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed - $this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file'); - } - } - - return true; - } - - private function parseSTREAMINFO($BlockData) { - $info = &$this->getid3->info; - - $info['flac']['STREAMINFO'] = array(); - $streaminfo = &$info['flac']['STREAMINFO']; - - $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2)); - $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2)); - $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3)); - $streaminfo['max_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3)); - - $SRCSBSS = getid3_lib::BigEndian2Bin(substr($BlockData, 10, 8)); - $streaminfo['sample_rate'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 0, 20)); - $streaminfo['channels'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1; - $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1; - $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36)); - - $streaminfo['audio_signature'] = substr($BlockData, 18, 16); - - if (!empty($streaminfo['sample_rate'])) { - - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['sample_rate'] = $streaminfo['sample_rate']; - $info['audio']['channels'] = $streaminfo['channels']; - $info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample']; - $info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate']; - if ($info['playtime_seconds'] > 0) { - if (!$this->isDependencyFor('matroska')) { - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - else { - $this->warning('Cannot determine audio bitrate because total stream size is unknown'); - } - } - - } else { - return $this->error('Corrupt METAdata block: STREAMINFO'); - } - - return true; - } - - private function parseAPPLICATION($BlockData) { - $info = &$this->getid3->info; - - $ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4)); - $info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID); - $info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4); - - return true; - } - - private function parseSEEKTABLE($BlockData) { - $info = &$this->getid3->info; - - $offset = 0; - $BlockLength = strlen($BlockData); - $placeholderpattern = str_repeat("\xFF", 8); - while ($offset < $BlockLength) { - $SampleNumberString = substr($BlockData, $offset, 8); - $offset += 8; - if ($SampleNumberString == $placeholderpattern) { - - // placeholder point - getid3_lib::safe_inc($info['flac']['SEEKTABLE']['placeholders'], 1); - $offset += 10; - - } else { - - $SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString); - $info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); - $offset += 8; - $info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2)); - $offset += 2; - - } - } - - return true; - } - - private function parseVORBIS_COMMENT($BlockData) { - $info = &$this->getid3->info; - - $getid3_ogg = new getid3_ogg($this->getid3); - if ($this->isDependencyFor('matroska')) { - $getid3_ogg->setStringMode($this->data_string); - } - $getid3_ogg->ParseVorbisComments(); - if (isset($info['ogg'])) { - unset($info['ogg']['comments_raw']); - $info['flac']['VORBIS_COMMENT'] = $info['ogg']; - unset($info['ogg']); - } - - unset($getid3_ogg); - - return true; - } - - private function parseCUESHEET($BlockData) { - $info = &$this->getid3->info; - $offset = 0; - $info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0"); - $offset += 128; - $info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); - $offset += 8; - $info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)) & 0x80); - $offset += 1; - - $offset += 258; // reserved - - $info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); - $offset += 1; - - for ($track = 0; $track < $info['flac']['CUESHEET']['number_tracks']; $track++) { - $TrackSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); - $offset += 8; - $TrackNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); - $offset += 1; - - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset; - - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($BlockData, $offset, 12); - $offset += 12; - - $TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); - $offset += 1; - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80); - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40); - - $offset += 13; // reserved - - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); - $offset += 1; - - for ($index = 0; $index < $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) { - $IndexSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); - $offset += 8; - $IndexNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); - $offset += 1; - - $offset += 3; // reserved - - $info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset; - } - } - - return true; - } - - /** - * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment - * External usage: audio.ogg - */ - public function parsePICTURE() { - $info = &$this->getid3->info; - - $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4)); - $picture['type'] = self::pictureTypeLookup($picture['typeid']); - $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4))); - $descr_length = getid3_lib::BigEndian2Int($this->fread(4)); - if ($descr_length) { - $picture['description'] = $this->fread($descr_length); - } - $picture['width'] = getid3_lib::BigEndian2Int($this->fread(4)); - $picture['height'] = getid3_lib::BigEndian2Int($this->fread(4)); - $picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4)); - $picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4)); - $data_length = getid3_lib::BigEndian2Int($this->fread(4)); - - if ($picture['image_mime'] == '-->') { - $picture['data'] = $this->fread($data_length); - } else { - $picture['data'] = $this->saveAttachment( - str_replace('/', '_', $picture['type']).'_'.$this->ftell(), - $this->ftell(), - $data_length, - $picture['image_mime']); - } - - $info['flac']['PICTURE'][] = $picture; - - return true; - } - - public static function metaBlockTypeLookup($blocktype) { - static $lookup = array( - 0 => 'STREAMINFO', - 1 => 'PADDING', - 2 => 'APPLICATION', - 3 => 'SEEKTABLE', - 4 => 'VORBIS_COMMENT', - 5 => 'CUESHEET', - 6 => 'PICTURE', - ); - return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved'); - } - - public static function applicationIDLookup($applicationid) { - // http://flac.sourceforge.net/id.html - static $lookup = array( - 0x41544348 => 'FlacFile', // "ATCH" - 0x42534F4C => 'beSolo', // "BSOL" - 0x42554753 => 'Bugs Player', // "BUGS" - 0x43756573 => 'GoldWave cue points (specification)', // "Cues" - 0x46696361 => 'CUE Splitter', // "Fica" - 0x46746F6C => 'flac-tools', // "Ftol" - 0x4D4F5442 => 'MOTB MetaCzar', // "MOTB" - 0x4D505345 => 'MP3 Stream Editor', // "MPSE" - 0x4D754D4C => 'MusicML: Music Metadata Language', // "MuML" - 0x52494646 => 'Sound Devices RIFF chunk storage', // "RIFF" - 0x5346464C => 'Sound Font FLAC', // "SFFL" - 0x534F4E59 => 'Sony Creative Software', // "SONY" - 0x5351455A => 'flacsqueeze', // "SQEZ" - 0x54745776 => 'TwistedWave', // "TtWv" - 0x55495453 => 'UITS Embedding tools', // "UITS" - 0x61696666 => 'FLAC AIFF chunk storage', // "aiff" - 0x696D6167 => 'flac-image application for storing arbitrary files in APPLICATION metadata blocks', // "imag" - 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // "peem" - 0x71667374 => 'QFLAC Studio', // "qfst" - 0x72696666 => 'FLAC RIFF chunk storage', // "riff" - 0x74756E65 => 'TagTuner', // "tune" - 0x78626174 => 'XBAT', // "xbat" - 0x786D6364 => 'xmcd', // "xmcd" - ); - return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved'); - } - - public static function pictureTypeLookup($type_id) { - static $lookup = array ( - 0 => 'Other', - 1 => '32x32 pixels \'file icon\' (PNG only)', - 2 => 'Other file icon', - 3 => 'Cover (front)', - 4 => 'Cover (back)', - 5 => 'Leaflet page', - 6 => 'Media (e.g. label side of CD)', - 7 => 'Lead artist/lead performer/soloist', - 8 => 'Artist/performer', - 9 => 'Conductor', - 10 => 'Band/Orchestra', - 11 => 'Composer', - 12 => 'Lyricist/text writer', - 13 => 'Recording Location', - 14 => 'During recording', - 15 => 'During performance', - 16 => 'Movie/video screen capture', - 17 => 'A bright coloured fish', - 18 => 'Illustration', - 19 => 'Band/artist logotype', - 20 => 'Publisher/Studio logotype', - ); - return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved'); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.flac.php // +// module for analyzing FLAC and OggFLAC audio files // +// dependencies: module.audio.ogg.php // +// /// +///////////////////////////////////////////////////////////////// + + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ogg.php', __FILE__, true); + +/** +* @tutorial http://flac.sourceforge.net/format.html +*/ +class getid3_flac extends getid3_handler +{ + const syncword = 'fLaC'; + + public function Analyze() { + $info = &$this->getid3->info; + + $this->fseek($info['avdataoffset']); + $StreamMarker = $this->fread(4); + if ($StreamMarker != self::syncword) { + return $this->error('Expecting "'.getid3_lib::PrintHexBytes(self::syncword).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($StreamMarker).'"'); + } + $info['fileformat'] = 'flac'; + $info['audio']['dataformat'] = 'flac'; + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['lossless'] = true; + + // parse flac container + return $this->parseMETAdata(); + } + + public function parseMETAdata() { + $info = &$this->getid3->info; + do { + $BlockOffset = $this->ftell(); + $BlockHeader = $this->fread(4); + $LBFBT = getid3_lib::BigEndian2Int(substr($BlockHeader, 0, 1)); + $LastBlockFlag = (bool) ($LBFBT & 0x80); + $BlockType = ($LBFBT & 0x7F); + $BlockLength = getid3_lib::BigEndian2Int(substr($BlockHeader, 1, 3)); + $BlockTypeText = self::metaBlockTypeLookup($BlockType); + + if (($BlockOffset + 4 + $BlockLength) > $info['avdataend']) { + $this->error('METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockTypeText.') at offset '.$BlockOffset.' extends beyond end of file'); + break; + } + if ($BlockLength < 1) { + $this->error('METADATA_BLOCK_HEADER.BLOCK_LENGTH ('.$BlockLength.') at offset '.$BlockOffset.' is invalid'); + break; + } + + $info['flac'][$BlockTypeText]['raw'] = array(); + $BlockTypeText_raw = &$info['flac'][$BlockTypeText]['raw']; + + $BlockTypeText_raw['offset'] = $BlockOffset; + $BlockTypeText_raw['last_meta_block'] = $LastBlockFlag; + $BlockTypeText_raw['block_type'] = $BlockType; + $BlockTypeText_raw['block_type_text'] = $BlockTypeText; + $BlockTypeText_raw['block_length'] = $BlockLength; + if ($BlockTypeText_raw['block_type'] != 0x06) { // do not read attachment data automatically + $BlockTypeText_raw['block_data'] = $this->fread($BlockLength); + } + + switch ($BlockTypeText) { + case 'STREAMINFO': // 0x00 + if (!$this->parseSTREAMINFO($BlockTypeText_raw['block_data'])) { + return false; + } + break; + + case 'PADDING': // 0x01 + unset($info['flac']['PADDING']); // ignore + break; + + case 'APPLICATION': // 0x02 + if (!$this->parseAPPLICATION($BlockTypeText_raw['block_data'])) { + return false; + } + break; + + case 'SEEKTABLE': // 0x03 + if (!$this->parseSEEKTABLE($BlockTypeText_raw['block_data'])) { + return false; + } + break; + + case 'VORBIS_COMMENT': // 0x04 + if (!$this->parseVORBIS_COMMENT($BlockTypeText_raw['block_data'])) { + return false; + } + break; + + case 'CUESHEET': // 0x05 + if (!$this->parseCUESHEET($BlockTypeText_raw['block_data'])) { + return false; + } + break; + + case 'PICTURE': // 0x06 + if (!$this->parsePICTURE()) { + return false; + } + break; + + default: + $this->warning('Unhandled METADATA_BLOCK_HEADER.BLOCK_TYPE ('.$BlockType.') at offset '.$BlockOffset); + } + + unset($info['flac'][$BlockTypeText]['raw']); + $info['avdataoffset'] = $this->ftell(); + } + while ($LastBlockFlag === false); + + // handle tags + if (!empty($info['flac']['VORBIS_COMMENT']['comments'])) { + $info['flac']['comments'] = $info['flac']['VORBIS_COMMENT']['comments']; + } + if (!empty($info['flac']['VORBIS_COMMENT']['vendor'])) { + $info['audio']['encoder'] = str_replace('reference ', '', $info['flac']['VORBIS_COMMENT']['vendor']); + } + + // copy attachments to 'comments' array if nesesary + if (isset($info['flac']['PICTURE']) && ($this->getid3->option_save_attachments !== getID3::ATTACHMENTS_NONE)) { + foreach ($info['flac']['PICTURE'] as $entry) { + if (!empty($entry['data'])) { + $info['flac']['comments']['picture'][] = array('image_mime'=>$entry['image_mime'], 'data'=>$entry['data']); + } + } + } + + if (isset($info['flac']['STREAMINFO'])) { + if (!$this->isDependencyFor('matroska')) { + $info['flac']['compressed_audio_bytes'] = $info['avdataend'] - $info['avdataoffset']; + } + $info['flac']['uncompressed_audio_bytes'] = $info['flac']['STREAMINFO']['samples_stream'] * $info['flac']['STREAMINFO']['channels'] * ($info['flac']['STREAMINFO']['bits_per_sample'] / 8); + if ($info['flac']['uncompressed_audio_bytes'] == 0) { + return $this->error('Corrupt FLAC file: uncompressed_audio_bytes == zero'); + } + if (!empty($info['flac']['compressed_audio_bytes'])) { + $info['flac']['compression_ratio'] = $info['flac']['compressed_audio_bytes'] / $info['flac']['uncompressed_audio_bytes']; + } + } + + // set md5_data_source - built into flac 0.5+ + if (isset($info['flac']['STREAMINFO']['audio_signature'])) { + + if ($info['flac']['STREAMINFO']['audio_signature'] === str_repeat("\x00", 16)) { + $this->warning('FLAC STREAMINFO.audio_signature is null (known issue with libOggFLAC)'); + } + else { + $info['md5_data_source'] = ''; + $md5 = $info['flac']['STREAMINFO']['audio_signature']; + for ($i = 0; $i < strlen($md5); $i++) { + $info['md5_data_source'] .= str_pad(dechex(ord($md5[$i])), 2, '00', STR_PAD_LEFT); + } + if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) { + unset($info['md5_data_source']); + } + } + } + + if (isset($info['flac']['STREAMINFO']['bits_per_sample'])) { + $info['audio']['bits_per_sample'] = $info['flac']['STREAMINFO']['bits_per_sample']; + if ($info['audio']['bits_per_sample'] == 8) { + // special case + // must invert sign bit on all data bytes before MD5'ing to match FLAC's calculated value + // MD5sum calculates on unsigned bytes, but FLAC calculated MD5 on 8-bit audio data as signed + $this->warning('FLAC calculates MD5 data strangely on 8-bit audio, so the stored md5_data_source value will not match the decoded WAV file'); + } + } + + return true; + } + + private function parseSTREAMINFO($BlockData) { + $info = &$this->getid3->info; + + $info['flac']['STREAMINFO'] = array(); + $streaminfo = &$info['flac']['STREAMINFO']; + + $streaminfo['min_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 0, 2)); + $streaminfo['max_block_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 2, 2)); + $streaminfo['min_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 4, 3)); + $streaminfo['max_frame_size'] = getid3_lib::BigEndian2Int(substr($BlockData, 7, 3)); + + $SRCSBSS = getid3_lib::BigEndian2Bin(substr($BlockData, 10, 8)); + $streaminfo['sample_rate'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 0, 20)); + $streaminfo['channels'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 20, 3)) + 1; + $streaminfo['bits_per_sample'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 23, 5)) + 1; + $streaminfo['samples_stream'] = getid3_lib::Bin2Dec(substr($SRCSBSS, 28, 36)); + + $streaminfo['audio_signature'] = substr($BlockData, 18, 16); + + if (!empty($streaminfo['sample_rate'])) { + + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['sample_rate'] = $streaminfo['sample_rate']; + $info['audio']['channels'] = $streaminfo['channels']; + $info['audio']['bits_per_sample'] = $streaminfo['bits_per_sample']; + $info['playtime_seconds'] = $streaminfo['samples_stream'] / $streaminfo['sample_rate']; + if ($info['playtime_seconds'] > 0) { + if (!$this->isDependencyFor('matroska')) { + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + else { + $this->warning('Cannot determine audio bitrate because total stream size is unknown'); + } + } + + } else { + return $this->error('Corrupt METAdata block: STREAMINFO'); + } + + return true; + } + + private function parseAPPLICATION($BlockData) { + $info = &$this->getid3->info; + + $ApplicationID = getid3_lib::BigEndian2Int(substr($BlockData, 0, 4)); + $info['flac']['APPLICATION'][$ApplicationID]['name'] = self::applicationIDLookup($ApplicationID); + $info['flac']['APPLICATION'][$ApplicationID]['data'] = substr($BlockData, 4); + + return true; + } + + private function parseSEEKTABLE($BlockData) { + $info = &$this->getid3->info; + + $offset = 0; + $BlockLength = strlen($BlockData); + $placeholderpattern = str_repeat("\xFF", 8); + while ($offset < $BlockLength) { + $SampleNumberString = substr($BlockData, $offset, 8); + $offset += 8; + if ($SampleNumberString == $placeholderpattern) { + + // placeholder point + getid3_lib::safe_inc($info['flac']['SEEKTABLE']['placeholders'], 1); + $offset += 10; + + } else { + + $SampleNumber = getid3_lib::BigEndian2Int($SampleNumberString); + $info['flac']['SEEKTABLE'][$SampleNumber]['offset'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); + $offset += 8; + $info['flac']['SEEKTABLE'][$SampleNumber]['samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 2)); + $offset += 2; + + } + } + + return true; + } + + private function parseVORBIS_COMMENT($BlockData) { + $info = &$this->getid3->info; + + $getid3_ogg = new getid3_ogg($this->getid3); + if ($this->isDependencyFor('matroska')) { + $getid3_ogg->setStringMode($this->data_string); + } + $getid3_ogg->ParseVorbisComments(); + if (isset($info['ogg'])) { + unset($info['ogg']['comments_raw']); + $info['flac']['VORBIS_COMMENT'] = $info['ogg']; + unset($info['ogg']); + } + + unset($getid3_ogg); + + return true; + } + + private function parseCUESHEET($BlockData) { + $info = &$this->getid3->info; + $offset = 0; + $info['flac']['CUESHEET']['media_catalog_number'] = trim(substr($BlockData, $offset, 128), "\0"); + $offset += 128; + $info['flac']['CUESHEET']['lead_in_samples'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); + $offset += 8; + $info['flac']['CUESHEET']['flags']['is_cd'] = (bool) (getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)) & 0x80); + $offset += 1; + + $offset += 258; // reserved + + $info['flac']['CUESHEET']['number_tracks'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); + $offset += 1; + + for ($track = 0; $track < $info['flac']['CUESHEET']['number_tracks']; $track++) { + $TrackSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); + $offset += 8; + $TrackNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); + $offset += 1; + + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['sample_offset'] = $TrackSampleOffset; + + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['isrc'] = substr($BlockData, $offset, 12); + $offset += 12; + + $TrackFlagsRaw = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); + $offset += 1; + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['is_audio'] = (bool) ($TrackFlagsRaw & 0x80); + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['flags']['pre_emphasis'] = (bool) ($TrackFlagsRaw & 0x40); + + $offset += 13; // reserved + + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points'] = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); + $offset += 1; + + for ($index = 0; $index < $info['flac']['CUESHEET']['tracks'][$TrackNumber]['index_points']; $index++) { + $IndexSampleOffset = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 8)); + $offset += 8; + $IndexNumber = getid3_lib::BigEndian2Int(substr($BlockData, $offset, 1)); + $offset += 1; + + $offset += 3; // reserved + + $info['flac']['CUESHEET']['tracks'][$TrackNumber]['indexes'][$IndexNumber] = $IndexSampleOffset; + } + } + + return true; + } + + /** + * Parse METADATA_BLOCK_PICTURE flac structure and extract attachment + * External usage: audio.ogg + */ + public function parsePICTURE() { + $info = &$this->getid3->info; + + $picture['typeid'] = getid3_lib::BigEndian2Int($this->fread(4)); + $picture['type'] = self::pictureTypeLookup($picture['typeid']); + $picture['image_mime'] = $this->fread(getid3_lib::BigEndian2Int($this->fread(4))); + $descr_length = getid3_lib::BigEndian2Int($this->fread(4)); + if ($descr_length) { + $picture['description'] = $this->fread($descr_length); + } + $picture['width'] = getid3_lib::BigEndian2Int($this->fread(4)); + $picture['height'] = getid3_lib::BigEndian2Int($this->fread(4)); + $picture['color_depth'] = getid3_lib::BigEndian2Int($this->fread(4)); + $picture['colors_indexed'] = getid3_lib::BigEndian2Int($this->fread(4)); + $data_length = getid3_lib::BigEndian2Int($this->fread(4)); + + if ($picture['image_mime'] == '-->') { + $picture['data'] = $this->fread($data_length); + } else { + $picture['data'] = $this->saveAttachment( + str_replace('/', '_', $picture['type']).'_'.$this->ftell(), + $this->ftell(), + $data_length, + $picture['image_mime']); + } + + $info['flac']['PICTURE'][] = $picture; + + return true; + } + + public static function metaBlockTypeLookup($blocktype) { + static $lookup = array( + 0 => 'STREAMINFO', + 1 => 'PADDING', + 2 => 'APPLICATION', + 3 => 'SEEKTABLE', + 4 => 'VORBIS_COMMENT', + 5 => 'CUESHEET', + 6 => 'PICTURE', + ); + return (isset($lookup[$blocktype]) ? $lookup[$blocktype] : 'reserved'); + } + + public static function applicationIDLookup($applicationid) { + // http://flac.sourceforge.net/id.html + static $lookup = array( + 0x41544348 => 'FlacFile', // "ATCH" + 0x42534F4C => 'beSolo', // "BSOL" + 0x42554753 => 'Bugs Player', // "BUGS" + 0x43756573 => 'GoldWave cue points (specification)', // "Cues" + 0x46696361 => 'CUE Splitter', // "Fica" + 0x46746F6C => 'flac-tools', // "Ftol" + 0x4D4F5442 => 'MOTB MetaCzar', // "MOTB" + 0x4D505345 => 'MP3 Stream Editor', // "MPSE" + 0x4D754D4C => 'MusicML: Music Metadata Language', // "MuML" + 0x52494646 => 'Sound Devices RIFF chunk storage', // "RIFF" + 0x5346464C => 'Sound Font FLAC', // "SFFL" + 0x534F4E59 => 'Sony Creative Software', // "SONY" + 0x5351455A => 'flacsqueeze', // "SQEZ" + 0x54745776 => 'TwistedWave', // "TtWv" + 0x55495453 => 'UITS Embedding tools', // "UITS" + 0x61696666 => 'FLAC AIFF chunk storage', // "aiff" + 0x696D6167 => 'flac-image application for storing arbitrary files in APPLICATION metadata blocks', // "imag" + 0x7065656D => 'Parseable Embedded Extensible Metadata (specification)', // "peem" + 0x71667374 => 'QFLAC Studio', // "qfst" + 0x72696666 => 'FLAC RIFF chunk storage', // "riff" + 0x74756E65 => 'TagTuner', // "tune" + 0x78626174 => 'XBAT', // "xbat" + 0x786D6364 => 'xmcd', // "xmcd" + ); + return (isset($lookup[$applicationid]) ? $lookup[$applicationid] : 'reserved'); + } + + public static function pictureTypeLookup($type_id) { + static $lookup = array ( + 0 => 'Other', + 1 => '32x32 pixels \'file icon\' (PNG only)', + 2 => 'Other file icon', + 3 => 'Cover (front)', + 4 => 'Cover (back)', + 5 => 'Leaflet page', + 6 => 'Media (e.g. label side of CD)', + 7 => 'Lead artist/lead performer/soloist', + 8 => 'Artist/performer', + 9 => 'Conductor', + 10 => 'Band/Orchestra', + 11 => 'Composer', + 12 => 'Lyricist/text writer', + 13 => 'Recording Location', + 14 => 'During recording', + 15 => 'During performance', + 16 => 'Movie/video screen capture', + 17 => 'A bright coloured fish', + 18 => 'Illustration', + 19 => 'Band/artist logotype', + 20 => 'Publisher/Studio logotype', + ); + return (isset($lookup[$type_id]) ? $lookup[$type_id] : 'reserved'); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.la.php b/app/libs/vendor/getid3/module.audio.la.php index 81cbda04..4e4cf53c 100644 --- a/app/libs/vendor/getid3/module.audio.la.php +++ b/app/libs/vendor/getid3/module.audio.la.php @@ -1,225 +1,225 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.la.php // -// module for analyzing LA (LosslessAudio) audio files // -// dependencies: module.audio.riff.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - -class getid3_la extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $offset = 0; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $rawdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); - - switch (substr($rawdata, $offset, 4)) { - case 'LA02': - case 'LA03': - case 'LA04': - $info['fileformat'] = 'la'; - $info['audio']['dataformat'] = 'la'; - $info['audio']['lossless'] = true; - - $info['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1); - $info['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1); - $info['la']['version'] = (float) $info['la']['version_major'] + ($info['la']['version_minor'] / 10); - $offset += 4; - - $info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - if ($info['la']['uncompressed_size'] == 0) { - $info['error'][] = 'Corrupt LA file: uncompressed_size == zero'; - return false; - } - - $WAVEchunk = substr($rawdata, $offset, 4); - if ($WAVEchunk !== 'WAVE') { - $info['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.'; - return false; - } - $offset += 4; - - $info['la']['fmt_size'] = 24; - if ($info['la']['version'] >= 0.3) { - - $info['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $info['la']['header_size'] = 49 + $info['la']['fmt_size'] - 24; - $offset += 4; - - } else { - - // version 0.2 didn't support additional data blocks - $info['la']['header_size'] = 41; - - } - - $fmt_chunk = substr($rawdata, $offset, 4); - if ($fmt_chunk !== 'fmt ') { - $info['error'][] = 'Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.'; - return false; - } - $offset += 4; - $fmt_size = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - - $info['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); - $offset += 2; - - $info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); - $offset += 2; - if ($info['la']['channels'] == 0) { - $info['error'][] = 'Corrupt LA file: channels == zero'; - return false; - } - - $info['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - if ($info['la']['sample_rate'] == 0) { - $info['error'][] = 'Corrupt LA file: sample_rate == zero'; - return false; - } - - $info['la']['bytes_per_second'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - $info['la']['bytes_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); - $offset += 2; - $info['la']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); - $offset += 2; - - $info['la']['samples'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - - $info['la']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 1)); - $offset += 1; - $info['la']['flags']['seekable'] = (bool) ($info['la']['raw']['flags'] & 0x01); - if ($info['la']['version'] >= 0.4) { - $info['la']['flags']['high_compression'] = (bool) ($info['la']['raw']['flags'] & 0x02); - } - - $info['la']['original_crc'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - - // mikeØbevin*de - // Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16 - // in earlier versions. A seekpoint is added every blocksize * seekevery - // samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should - // give the number of bytes used for the seekpoints. Of course, if seeking - // is disabled, there are no seekpoints stored. - if ($info['la']['version'] >= 0.4) { - $info['la']['blocksize'] = 61440; - $info['la']['seekevery'] = 19; - } else { - $info['la']['blocksize'] = 73728; - $info['la']['seekevery'] = 16; - } - - $info['la']['seekpoint_count'] = 0; - if ($info['la']['flags']['seekable']) { - $info['la']['seekpoint_count'] = floor($info['la']['samples'] / ($info['la']['blocksize'] * $info['la']['seekevery'])); - - for ($i = 0; $i < $info['la']['seekpoint_count']; $i++) { - $info['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - } - } - - if ($info['la']['version'] >= 0.3) { - - // Following the main header information, the program outputs all of the - // seekpoints. Following these is what I called the 'footer start', - // i.e. the position immediately after the La audio data is finished. - $info['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); - $offset += 4; - - if ($info['la']['footerstart'] > $info['filesize']) { - $info['warning'][] = 'FooterStart value points to offset '.$info['la']['footerstart'].' which is beyond end-of-file ('.$info['filesize'].')'; - $info['la']['footerstart'] = $info['filesize']; - } - - } else { - - // La v0.2 didn't have FooterStart value - $info['la']['footerstart'] = $info['avdataend']; - - } - - if ($info['la']['footerstart'] < $info['avdataend']) { - if ($RIFFtempfilename = tempnam(GETID3_TEMP_DIR, 'id3')) { - if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) { - $RIFFdata = 'WAVE'; - if ($info['la']['version'] == 0.2) { - $RIFFdata .= substr($rawdata, 12, 24); - } else { - $RIFFdata .= substr($rawdata, 16, 24); - } - if ($info['la']['footerstart'] < $info['avdataend']) { - fseek($this->getid3->fp, $info['la']['footerstart'], SEEK_SET); - $RIFFdata .= fread($this->getid3->fp, $info['avdataend'] - $info['la']['footerstart']); - } - $RIFFdata = 'RIFF'.getid3_lib::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata; - fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata)); - fclose($RIFF_fp); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($RIFFtempfilename); - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->Analyze(); - - if (empty($getid3_temp->info['error'])) { - $info['riff'] = $getid3_temp->info['riff']; - } else { - $info['warning'][] = 'Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']); - } - unset($getid3_temp, $getid3_riff); - } - unlink($RIFFtempfilename); - } - } - - // $info['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway - $info['avdataend'] = $info['avdataoffset'] + $info['la']['footerstart']; - $info['avdataoffset'] = $info['avdataoffset'] + $offset; - - $info['la']['compression_ratio'] = (float) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']); - $info['playtime_seconds'] = (float) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels']; - if ($info['playtime_seconds'] == 0) { - $info['error'][] = 'Corrupt LA file: playtime_seconds == zero'; - return false; - } - - $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds']; - //$info['audio']['codec'] = $info['la']['codec']; - $info['audio']['bits_per_sample'] = $info['la']['bits_per_sample']; - break; - - default: - if (substr($rawdata, $offset, 2) == 'LA') { - $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] does not support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.'; - } else { - $info['error'][] = 'Not a LA (Lossless-Audio) file'; - } - return false; - break; - } - - $info['audio']['channels'] = $info['la']['channels']; - $info['audio']['sample_rate'] = (int) $info['la']['sample_rate']; - $info['audio']['encoder'] = 'LA v'.$info['la']['version']; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.la.php // +// module for analyzing LA (LosslessAudio) audio files // +// dependencies: module.audio.riff.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + +class getid3_la extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $offset = 0; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $rawdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); + + switch (substr($rawdata, $offset, 4)) { + case 'LA02': + case 'LA03': + case 'LA04': + $info['fileformat'] = 'la'; + $info['audio']['dataformat'] = 'la'; + $info['audio']['lossless'] = true; + + $info['la']['version_major'] = (int) substr($rawdata, $offset + 2, 1); + $info['la']['version_minor'] = (int) substr($rawdata, $offset + 3, 1); + $info['la']['version'] = (float) $info['la']['version_major'] + ($info['la']['version_minor'] / 10); + $offset += 4; + + $info['la']['uncompressed_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + if ($info['la']['uncompressed_size'] == 0) { + $info['error'][] = 'Corrupt LA file: uncompressed_size == zero'; + return false; + } + + $WAVEchunk = substr($rawdata, $offset, 4); + if ($WAVEchunk !== 'WAVE') { + $info['error'][] = 'Expected "WAVE" ('.getid3_lib::PrintHexBytes('WAVE').') at offset '.$offset.', found "'.$WAVEchunk.'" ('.getid3_lib::PrintHexBytes($WAVEchunk).') instead.'; + return false; + } + $offset += 4; + + $info['la']['fmt_size'] = 24; + if ($info['la']['version'] >= 0.3) { + + $info['la']['fmt_size'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $info['la']['header_size'] = 49 + $info['la']['fmt_size'] - 24; + $offset += 4; + + } else { + + // version 0.2 didn't support additional data blocks + $info['la']['header_size'] = 41; + + } + + $fmt_chunk = substr($rawdata, $offset, 4); + if ($fmt_chunk !== 'fmt ') { + $info['error'][] = 'Expected "fmt " ('.getid3_lib::PrintHexBytes('fmt ').') at offset '.$offset.', found "'.$fmt_chunk.'" ('.getid3_lib::PrintHexBytes($fmt_chunk).') instead.'; + return false; + } + $offset += 4; + $fmt_size = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + $info['la']['raw']['format'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + + $info['la']['channels'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + if ($info['la']['channels'] == 0) { + $info['error'][] = 'Corrupt LA file: channels == zero'; + return false; + } + + $info['la']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + if ($info['la']['sample_rate'] == 0) { + $info['error'][] = 'Corrupt LA file: sample_rate == zero'; + return false; + } + + $info['la']['bytes_per_second'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + $info['la']['bytes_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + $info['la']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 2)); + $offset += 2; + + $info['la']['samples'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + $info['la']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 1)); + $offset += 1; + $info['la']['flags']['seekable'] = (bool) ($info['la']['raw']['flags'] & 0x01); + if ($info['la']['version'] >= 0.4) { + $info['la']['flags']['high_compression'] = (bool) ($info['la']['raw']['flags'] & 0x02); + } + + $info['la']['original_crc'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + // mikeØbevin*de + // Basically, the blocksize/seekevery are 61440/19 in La0.4 and 73728/16 + // in earlier versions. A seekpoint is added every blocksize * seekevery + // samples, so 4 * int(totalSamples / (blockSize * seekEvery)) should + // give the number of bytes used for the seekpoints. Of course, if seeking + // is disabled, there are no seekpoints stored. + if ($info['la']['version'] >= 0.4) { + $info['la']['blocksize'] = 61440; + $info['la']['seekevery'] = 19; + } else { + $info['la']['blocksize'] = 73728; + $info['la']['seekevery'] = 16; + } + + $info['la']['seekpoint_count'] = 0; + if ($info['la']['flags']['seekable']) { + $info['la']['seekpoint_count'] = floor($info['la']['samples'] / ($info['la']['blocksize'] * $info['la']['seekevery'])); + + for ($i = 0; $i < $info['la']['seekpoint_count']; $i++) { + $info['la']['seekpoints'][] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + } + } + + if ($info['la']['version'] >= 0.3) { + + // Following the main header information, the program outputs all of the + // seekpoints. Following these is what I called the 'footer start', + // i.e. the position immediately after the La audio data is finished. + $info['la']['footerstart'] = getid3_lib::LittleEndian2Int(substr($rawdata, $offset, 4)); + $offset += 4; + + if ($info['la']['footerstart'] > $info['filesize']) { + $info['warning'][] = 'FooterStart value points to offset '.$info['la']['footerstart'].' which is beyond end-of-file ('.$info['filesize'].')'; + $info['la']['footerstart'] = $info['filesize']; + } + + } else { + + // La v0.2 didn't have FooterStart value + $info['la']['footerstart'] = $info['avdataend']; + + } + + if ($info['la']['footerstart'] < $info['avdataend']) { + if ($RIFFtempfilename = tempnam(GETID3_TEMP_DIR, 'id3')) { + if ($RIFF_fp = fopen($RIFFtempfilename, 'w+b')) { + $RIFFdata = 'WAVE'; + if ($info['la']['version'] == 0.2) { + $RIFFdata .= substr($rawdata, 12, 24); + } else { + $RIFFdata .= substr($rawdata, 16, 24); + } + if ($info['la']['footerstart'] < $info['avdataend']) { + fseek($this->getid3->fp, $info['la']['footerstart'], SEEK_SET); + $RIFFdata .= fread($this->getid3->fp, $info['avdataend'] - $info['la']['footerstart']); + } + $RIFFdata = 'RIFF'.getid3_lib::LittleEndian2String(strlen($RIFFdata), 4, false).$RIFFdata; + fwrite($RIFF_fp, $RIFFdata, strlen($RIFFdata)); + fclose($RIFF_fp); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($RIFFtempfilename); + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->Analyze(); + + if (empty($getid3_temp->info['error'])) { + $info['riff'] = $getid3_temp->info['riff']; + } else { + $info['warning'][] = 'Error parsing RIFF portion of La file: '.implode($getid3_temp->info['error']); + } + unset($getid3_temp, $getid3_riff); + } + unlink($RIFFtempfilename); + } + } + + // $info['avdataoffset'] should be zero to begin with, but just in case it's not, include the addition anyway + $info['avdataend'] = $info['avdataoffset'] + $info['la']['footerstart']; + $info['avdataoffset'] = $info['avdataoffset'] + $offset; + + $info['la']['compression_ratio'] = (float) (($info['avdataend'] - $info['avdataoffset']) / $info['la']['uncompressed_size']); + $info['playtime_seconds'] = (float) ($info['la']['samples'] / $info['la']['sample_rate']) / $info['la']['channels']; + if ($info['playtime_seconds'] == 0) { + $info['error'][] = 'Corrupt LA file: playtime_seconds == zero'; + return false; + } + + $info['audio']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['playtime_seconds']; + //$info['audio']['codec'] = $info['la']['codec']; + $info['audio']['bits_per_sample'] = $info['la']['bits_per_sample']; + break; + + default: + if (substr($rawdata, $offset, 2) == 'LA') { + $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] does not support LA version '.substr($rawdata, $offset + 2, 1).'.'.substr($rawdata, $offset + 3, 1).' which this appears to be - check http://getid3.sourceforge.net for updates.'; + } else { + $info['error'][] = 'Not a LA (Lossless-Audio) file'; + } + return false; + break; + } + + $info['audio']['channels'] = $info['la']['channels']; + $info['audio']['sample_rate'] = (int) $info['la']['sample_rate']; + $info['audio']['encoder'] = 'LA v'.$info['la']['version']; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.lpac.php b/app/libs/vendor/getid3/module.audio.lpac.php index 16b33a96..3d45e000 100644 --- a/app/libs/vendor/getid3/module.audio.lpac.php +++ b/app/libs/vendor/getid3/module.audio.lpac.php @@ -1,127 +1,127 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.lpac.php // -// module for analyzing LPAC Audio files // -// dependencies: module.audio-video.riff.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - -class getid3_lpac extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $LPACheader = fread($this->getid3->fp, 14); - if (substr($LPACheader, 0, 4) != 'LPAC') { - $info['error'][] = 'Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"'; - return false; - } - $info['avdataoffset'] += 14; - - $info['fileformat'] = 'lpac'; - $info['audio']['dataformat'] = 'lpac'; - $info['audio']['lossless'] = true; - $info['audio']['bitrate_mode'] = 'vbr'; - - $info['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1)); - $flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1)); - $info['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4)); - $flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4)); - - $info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40); - $info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04); - $info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02); - $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01); - - if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) { - $info['warning'][] = '24-bit and 16-bit flags cannot both be set'; - } - - $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000); - $info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000); - $info['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256; - $info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000); - $info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000); - $info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000); - $info['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8; - $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F); - - if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) { - $info['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"'; - } - switch ($info['lpac']['file_version']) { - case 6: - if ($info['lpac']['flags']['adaptive_quantization']) { - $info['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true'; - } - if ($info['lpac']['quantization'] != 20) { - $info['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q']; - } - break; - - default: - //$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org'; - break; - } - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info = $info; - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->Analyze(); - $info['avdataoffset'] = $getid3_temp->info['avdataoffset']; - $info['riff'] = $getid3_temp->info['riff']; - $info['error'] = $getid3_temp->info['error']; - $info['warning'] = $getid3_temp->info['warning']; - $info['lpac']['comments']['comment'] = $getid3_temp->info['comments']; - $info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate']; - unset($getid3_temp, $getid3_riff); - - $info['audio']['channels'] = ($info['lpac']['flags']['stereo'] ? 2 : 1); - - if ($info['lpac']['flags']['24_bit']) { - $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample']; - } elseif ($info['lpac']['flags']['16_bit']) { - $info['audio']['bits_per_sample'] = 16; - } else { - $info['audio']['bits_per_sample'] = 8; - } - - if ($info['lpac']['flags']['fast_compress']) { - // fast - $info['audio']['encoder_options'] = '-1'; - } else { - switch ($info['lpac']['max_prediction_order']) { - case 20: // simple - $info['audio']['encoder_options'] = '-2'; - break; - case 30: // medium - $info['audio']['encoder_options'] = '-3'; - break; - case 40: // high - $info['audio']['encoder_options'] = '-4'; - break; - case 60: // extrahigh - $info['audio']['encoder_options'] = '-5'; - break; - } - } - - $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.lpac.php // +// module for analyzing LPAC Audio files // +// dependencies: module.audio-video.riff.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + +class getid3_lpac extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $LPACheader = fread($this->getid3->fp, 14); + if (substr($LPACheader, 0, 4) != 'LPAC') { + $info['error'][] = 'Expected "LPAC" at offset '.$info['avdataoffset'].', found "'.$StreamMarker.'"'; + return false; + } + $info['avdataoffset'] += 14; + + $info['fileformat'] = 'lpac'; + $info['audio']['dataformat'] = 'lpac'; + $info['audio']['lossless'] = true; + $info['audio']['bitrate_mode'] = 'vbr'; + + $info['lpac']['file_version'] = getid3_lib::BigEndian2Int(substr($LPACheader, 4, 1)); + $flags['audio_type'] = getid3_lib::BigEndian2Int(substr($LPACheader, 5, 1)); + $info['lpac']['total_samples']= getid3_lib::BigEndian2Int(substr($LPACheader, 6, 4)); + $flags['parameters'] = getid3_lib::BigEndian2Int(substr($LPACheader, 10, 4)); + + $info['lpac']['flags']['is_wave'] = (bool) ($flags['audio_type'] & 0x40); + $info['lpac']['flags']['stereo'] = (bool) ($flags['audio_type'] & 0x04); + $info['lpac']['flags']['24_bit'] = (bool) ($flags['audio_type'] & 0x02); + $info['lpac']['flags']['16_bit'] = (bool) ($flags['audio_type'] & 0x01); + + if ($info['lpac']['flags']['24_bit'] && $info['lpac']['flags']['16_bit']) { + $info['warning'][] = '24-bit and 16-bit flags cannot both be set'; + } + + $info['lpac']['flags']['fast_compress'] = (bool) ($flags['parameters'] & 0x40000000); + $info['lpac']['flags']['random_access'] = (bool) ($flags['parameters'] & 0x08000000); + $info['lpac']['block_length'] = pow(2, (($flags['parameters'] & 0x07000000) >> 24)) * 256; + $info['lpac']['flags']['adaptive_prediction_order'] = (bool) ($flags['parameters'] & 0x00800000); + $info['lpac']['flags']['adaptive_quantization'] = (bool) ($flags['parameters'] & 0x00400000); + $info['lpac']['flags']['joint_stereo'] = (bool) ($flags['parameters'] & 0x00040000); + $info['lpac']['quantization'] = ($flags['parameters'] & 0x00001F00) >> 8; + $info['lpac']['max_prediction_order'] = ($flags['parameters'] & 0x0000003F); + + if ($info['lpac']['flags']['fast_compress'] && ($info['lpac']['max_prediction_order'] != 3)) { + $info['warning'][] = 'max_prediction_order expected to be "3" if fast_compress is true, actual value is "'.$info['lpac']['max_prediction_order'].'"'; + } + switch ($info['lpac']['file_version']) { + case 6: + if ($info['lpac']['flags']['adaptive_quantization']) { + $info['warning'][] = 'adaptive_quantization expected to be false in LPAC file stucture v6, actually true'; + } + if ($info['lpac']['quantization'] != 20) { + $info['warning'][] = 'Quantization expected to be 20 in LPAC file stucture v6, actually '.$info['lpac']['flags']['Q']; + } + break; + + default: + //$info['warning'][] = 'This version of getID3() ['.$this->getid3->version().'] only supports LPAC file format version 6, this file is version '.$info['lpac']['file_version'].' - please report to info@getid3.org'; + break; + } + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info = $info; + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->Analyze(); + $info['avdataoffset'] = $getid3_temp->info['avdataoffset']; + $info['riff'] = $getid3_temp->info['riff']; + $info['error'] = $getid3_temp->info['error']; + $info['warning'] = $getid3_temp->info['warning']; + $info['lpac']['comments']['comment'] = $getid3_temp->info['comments']; + $info['audio']['sample_rate'] = $getid3_temp->info['audio']['sample_rate']; + unset($getid3_temp, $getid3_riff); + + $info['audio']['channels'] = ($info['lpac']['flags']['stereo'] ? 2 : 1); + + if ($info['lpac']['flags']['24_bit']) { + $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample']; + } elseif ($info['lpac']['flags']['16_bit']) { + $info['audio']['bits_per_sample'] = 16; + } else { + $info['audio']['bits_per_sample'] = 8; + } + + if ($info['lpac']['flags']['fast_compress']) { + // fast + $info['audio']['encoder_options'] = '-1'; + } else { + switch ($info['lpac']['max_prediction_order']) { + case 20: // simple + $info['audio']['encoder_options'] = '-2'; + break; + case 30: // medium + $info['audio']['encoder_options'] = '-3'; + break; + case 40: // high + $info['audio']['encoder_options'] = '-4'; + break; + case 60: // extrahigh + $info['audio']['encoder_options'] = '-5'; + break; + } + } + + $info['playtime_seconds'] = $info['lpac']['total_samples'] / $info['audio']['sample_rate']; + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.midi.php b/app/libs/vendor/getid3/module.audio.midi.php index 35e17d9a..2ca258e7 100644 --- a/app/libs/vendor/getid3/module.audio.midi.php +++ b/app/libs/vendor/getid3/module.audio.midi.php @@ -1,529 +1,529 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.midi.php // -// module for Midi Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - -define('GETID3_MIDI_MAGIC_MTHD', 'MThd'); // MIDI file header magic -define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic - -class getid3_midi extends getid3_handler -{ - public $scanwholefile = true; - - public function Analyze() { - $info = &$this->getid3->info; - - // shortcut - $info['midi']['raw'] = array(); - $thisfile_midi = &$info['midi']; - $thisfile_midi_raw = &$thisfile_midi['raw']; - - $info['fileformat'] = 'midi'; - $info['audio']['dataformat'] = 'midi'; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $MIDIdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); - $offset = 0; - $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd' - if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"'; - unset($info['fileformat']); - return false; - } - $offset += 4; - $thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4)); - $offset += 4; - $thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); - $offset += 2; - $thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); - $offset += 2; - $thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); - $offset += 2; - - for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) { - while ((strlen($MIDIdata) - $offset) < 8) { - if ($buffer = fread($this->getid3->fp, $this->getid3->fread_buffer_size())) { - $MIDIdata .= $buffer; - } else { - $info['warning'][] = 'only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks'; - $info['error'][] = 'Unabled to read more file data at '.ftell($this->getid3->fp).' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes'; - return false; - } - } - $trackID = substr($MIDIdata, $offset, 4); - $offset += 4; - if ($trackID == GETID3_MIDI_MAGIC_MTRK) { - $tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4)); - $offset += 4; - //$thisfile_midi['tracks'][$i]['size'] = $tracksize; - $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize); - $offset += $tracksize; - } else { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead'; - return false; - } - } - - if (!isset($trackdataarray) || !is_array($trackdataarray)) { - $info['error'][] = 'Cannot find MIDI track information'; - unset($thisfile_midi); - unset($info['fileformat']); - return false; - } - - if ($this->scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important - $thisfile_midi['totalticks'] = 0; - $info['playtime_seconds'] = 0; - $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat - $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat - $MicroSecondsPerQuarterNoteAfter = array (); - - foreach ($trackdataarray as $tracknumber => $trackdata) { - - $eventsoffset = 0; - $LastIssuedMIDIcommand = 0; - $LastIssuedMIDIchannel = 0; - $CumulativeDeltaTime = 0; - $TicksAtCurrentBPM = 0; - while ($eventsoffset < strlen($trackdata)) { - $eventid = 0; - if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) { - $eventid = count($MIDIevents[$tracknumber]); - } - $deltatime = 0; - for ($i = 0; $i < 4; $i++) { - $deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1)); - $deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F); - if ($deltatimebyte & 0x80) { - // another byte follows - } else { - break; - } - } - $CumulativeDeltaTime += $deltatime; - $TicksAtCurrentBPM += $deltatime; - $MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime; - $MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1)); - if ($MIDI_event_channel & 0x80) { - // OK, normal event - MIDI command has MSB set - $LastIssuedMIDIcommand = $MIDI_event_channel >> 4; - $LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F; - } else { - // running event - assume last command - $eventsoffset--; - } - $MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand; - $MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel; - if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released) - - $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); - $velocity = ord(substr($trackdata, $eventsoffset++, 1)); - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed) - - $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); - $velocity = ord(substr($trackdata, $eventsoffset++, 1)); - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch - - $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); - $velocity = ord(substr($trackdata, $eventsoffset++, 1)); - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change - - $controllernum = ord(substr($trackdata, $eventsoffset++, 1)); - $newvalue = ord(substr($trackdata, $eventsoffset++, 1)); - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change - - $newprogramnum = ord(substr($trackdata, $eventsoffset++, 1)); - - $thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum; - if ($tracknumber == 10) { - $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum); - } else { - $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum); - } - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { // Channel after-touch - - $channelnumber = ord(substr($trackdata, $eventsoffset++, 1)); - - } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change) - - $changeLSB = ord(substr($trackdata, $eventsoffset++, 1)); - $changeMSB = ord(substr($trackdata, $eventsoffset++, 1)); - $pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F); - - } elseif (($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) { - - $METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1)); - $METAeventLength = ord(substr($trackdata, $eventsoffset++, 1)); - $METAeventData = substr($trackdata, $eventsoffset, $METAeventLength); - $eventsoffset += $METAeventLength; - switch ($METAeventCommand) { - case 0x00: // Set track sequence number - $track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength)); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number; - break; - - case 0x01: // Text: generic - $text_generic = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic; - $thisfile_midi['comments']['comment'][] = $text_generic; - break; - - case 0x02: // Text: copyright - $text_copyright = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright; - $thisfile_midi['comments']['copyright'][] = $text_copyright; - break; - - case 0x03: // Text: track name - $text_trackname = substr($METAeventData, 0, $METAeventLength); - $thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname; - break; - - case 0x04: // Text: track instrument name - $text_instrument = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument; - break; - - case 0x05: // Text: lyrics - $text_lyrics = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics; - if (!isset($thisfile_midi['lyrics'])) { - $thisfile_midi['lyrics'] = ''; - } - $thisfile_midi['lyrics'] .= $text_lyrics."\n"; - break; - - case 0x06: // Text: marker - $text_marker = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker; - break; - - case 0x07: // Text: cue point - $text_cuepoint = substr($METAeventData, 0, $METAeventLength); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint; - break; - - case 0x2F: // End Of Track - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime; - break; - - case 0x51: // Tempo: microseconds / quarter note - $CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength)); - if ($CurrentMicroSecondsPerBeat == 0) { - $info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero'; - return false; - } - $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat; - $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60; - $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat; - $TicksAtCurrentBPM = 0; - break; - - case 0x58: // Time signature - $timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0}); - $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc - $timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote; - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator; - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator; - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator; - $thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator; - break; - - case 0x59: // Keysignature - $keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0}); - if ($keysig_sharpsflats & 0x80) { - // (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps) - $keysig_sharpsflats -= 256; - } - - $keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor - $keysigs = array(-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#'); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0); - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] = (bool) $keysig_majorminor; - //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major'); - - // $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect) - $thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major'); - break; - - case 0x7F: // Sequencer specific information - $custom_data = substr($METAeventData, 0, $METAeventLength); - break; - - default: - $info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand; - break; - } - - } else { - - $info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel']; - - } - } - if (($tracknumber > 0) || (count($trackdataarray) == 1)) { - $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime); - } - } - $previoustickoffset = null; - - ksort($MicroSecondsPerQuarterNoteAfter); - foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) { - if (is_null($previoustickoffset)) { - $prevmicrosecondsperbeat = $microsecondsperbeat; - $previoustickoffset = $tickoffset; - continue; - } - if ($thisfile_midi['totalticks'] > $tickoffset) { - - if ($thisfile_midi_raw['ticksperqnote'] == 0) { - $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero'; - return false; - } - - $info['playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000); - - $prevmicrosecondsperbeat = $microsecondsperbeat; - $previoustickoffset = $tickoffset; - } - } - if ($thisfile_midi['totalticks'] > $previoustickoffset) { - - if ($thisfile_midi_raw['ticksperqnote'] == 0) { - $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero'; - return false; - } - - $info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000); - - } - } - - - if (!empty($info['playtime_seconds'])) { - $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - - if (!empty($thisfile_midi['lyrics'])) { - $thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics']; - } - - return true; - } - - public function GeneralMIDIinstrumentLookup($instrumentid) { - - $begin = __LINE__; - - /** This is not a comment! - - 0 Acoustic Grand - 1 Bright Acoustic - 2 Electric Grand - 3 Honky-Tonk - 4 Electric Piano 1 - 5 Electric Piano 2 - 6 Harpsichord - 7 Clavier - 8 Celesta - 9 Glockenspiel - 10 Music Box - 11 Vibraphone - 12 Marimba - 13 Xylophone - 14 Tubular Bells - 15 Dulcimer - 16 Drawbar Organ - 17 Percussive Organ - 18 Rock Organ - 19 Church Organ - 20 Reed Organ - 21 Accordian - 22 Harmonica - 23 Tango Accordian - 24 Acoustic Guitar (nylon) - 25 Acoustic Guitar (steel) - 26 Electric Guitar (jazz) - 27 Electric Guitar (clean) - 28 Electric Guitar (muted) - 29 Overdriven Guitar - 30 Distortion Guitar - 31 Guitar Harmonics - 32 Acoustic Bass - 33 Electric Bass (finger) - 34 Electric Bass (pick) - 35 Fretless Bass - 36 Slap Bass 1 - 37 Slap Bass 2 - 38 Synth Bass 1 - 39 Synth Bass 2 - 40 Violin - 41 Viola - 42 Cello - 43 Contrabass - 44 Tremolo Strings - 45 Pizzicato Strings - 46 Orchestral Strings - 47 Timpani - 48 String Ensemble 1 - 49 String Ensemble 2 - 50 SynthStrings 1 - 51 SynthStrings 2 - 52 Choir Aahs - 53 Voice Oohs - 54 Synth Voice - 55 Orchestra Hit - 56 Trumpet - 57 Trombone - 58 Tuba - 59 Muted Trumpet - 60 French Horn - 61 Brass Section - 62 SynthBrass 1 - 63 SynthBrass 2 - 64 Soprano Sax - 65 Alto Sax - 66 Tenor Sax - 67 Baritone Sax - 68 Oboe - 69 English Horn - 70 Bassoon - 71 Clarinet - 72 Piccolo - 73 Flute - 74 Recorder - 75 Pan Flute - 76 Blown Bottle - 77 Shakuhachi - 78 Whistle - 79 Ocarina - 80 Lead 1 (square) - 81 Lead 2 (sawtooth) - 82 Lead 3 (calliope) - 83 Lead 4 (chiff) - 84 Lead 5 (charang) - 85 Lead 6 (voice) - 86 Lead 7 (fifths) - 87 Lead 8 (bass + lead) - 88 Pad 1 (new age) - 89 Pad 2 (warm) - 90 Pad 3 (polysynth) - 91 Pad 4 (choir) - 92 Pad 5 (bowed) - 93 Pad 6 (metallic) - 94 Pad 7 (halo) - 95 Pad 8 (sweep) - 96 FX 1 (rain) - 97 FX 2 (soundtrack) - 98 FX 3 (crystal) - 99 FX 4 (atmosphere) - 100 FX 5 (brightness) - 101 FX 6 (goblins) - 102 FX 7 (echoes) - 103 FX 8 (sci-fi) - 104 Sitar - 105 Banjo - 106 Shamisen - 107 Koto - 108 Kalimba - 109 Bagpipe - 110 Fiddle - 111 Shanai - 112 Tinkle Bell - 113 Agogo - 114 Steel Drums - 115 Woodblock - 116 Taiko Drum - 117 Melodic Tom - 118 Synth Drum - 119 Reverse Cymbal - 120 Guitar Fret Noise - 121 Breath Noise - 122 Seashore - 123 Bird Tweet - 124 Telephone Ring - 125 Helicopter - 126 Applause - 127 Gunshot - - */ - - return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument'); - } - - public function GeneralMIDIpercussionLookup($instrumentid) { - - $begin = __LINE__; - - /** This is not a comment! - - 35 Acoustic Bass Drum - 36 Bass Drum 1 - 37 Side Stick - 38 Acoustic Snare - 39 Hand Clap - 40 Electric Snare - 41 Low Floor Tom - 42 Closed Hi-Hat - 43 High Floor Tom - 44 Pedal Hi-Hat - 45 Low Tom - 46 Open Hi-Hat - 47 Low-Mid Tom - 48 Hi-Mid Tom - 49 Crash Cymbal 1 - 50 High Tom - 51 Ride Cymbal 1 - 52 Chinese Cymbal - 53 Ride Bell - 54 Tambourine - 55 Splash Cymbal - 56 Cowbell - 57 Crash Cymbal 2 - 59 Ride Cymbal 2 - 60 Hi Bongo - 61 Low Bongo - 62 Mute Hi Conga - 63 Open Hi Conga - 64 Low Conga - 65 High Timbale - 66 Low Timbale - 67 High Agogo - 68 Low Agogo - 69 Cabasa - 70 Maracas - 71 Short Whistle - 72 Long Whistle - 73 Short Guiro - 74 Long Guiro - 75 Claves - 76 Hi Wood Block - 77 Low Wood Block - 78 Mute Cuica - 79 Open Cuica - 80 Mute Triangle - 81 Open Triangle - - */ - - return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion'); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.midi.php // +// module for Midi Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +define('GETID3_MIDI_MAGIC_MTHD', 'MThd'); // MIDI file header magic +define('GETID3_MIDI_MAGIC_MTRK', 'MTrk'); // MIDI track header magic + +class getid3_midi extends getid3_handler +{ + public $scanwholefile = true; + + public function Analyze() { + $info = &$this->getid3->info; + + // shortcut + $info['midi']['raw'] = array(); + $thisfile_midi = &$info['midi']; + $thisfile_midi_raw = &$thisfile_midi['raw']; + + $info['fileformat'] = 'midi'; + $info['audio']['dataformat'] = 'midi'; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $MIDIdata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); + $offset = 0; + $MIDIheaderID = substr($MIDIdata, $offset, 4); // 'MThd' + if ($MIDIheaderID != GETID3_MIDI_MAGIC_MTHD) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTHD).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($MIDIheaderID).'"'; + unset($info['fileformat']); + return false; + } + $offset += 4; + $thisfile_midi_raw['headersize'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4)); + $offset += 4; + $thisfile_midi_raw['fileformat'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); + $offset += 2; + $thisfile_midi_raw['tracks'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); + $offset += 2; + $thisfile_midi_raw['ticksperqnote'] = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 2)); + $offset += 2; + + for ($i = 0; $i < $thisfile_midi_raw['tracks']; $i++) { + while ((strlen($MIDIdata) - $offset) < 8) { + if ($buffer = fread($this->getid3->fp, $this->getid3->fread_buffer_size())) { + $MIDIdata .= $buffer; + } else { + $info['warning'][] = 'only processed '.($i - 1).' of '.$thisfile_midi_raw['tracks'].' tracks'; + $info['error'][] = 'Unabled to read more file data at '.ftell($this->getid3->fp).' (trying to seek to : '.$offset.'), was expecting at least 8 more bytes'; + return false; + } + } + $trackID = substr($MIDIdata, $offset, 4); + $offset += 4; + if ($trackID == GETID3_MIDI_MAGIC_MTRK) { + $tracksize = getid3_lib::BigEndian2Int(substr($MIDIdata, $offset, 4)); + $offset += 4; + //$thisfile_midi['tracks'][$i]['size'] = $tracksize; + $trackdataarray[$i] = substr($MIDIdata, $offset, $tracksize); + $offset += $tracksize; + } else { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes(GETID3_MIDI_MAGIC_MTRK).'" at '.($offset - 4).', found "'.getid3_lib::PrintHexBytes($trackID).'" instead'; + return false; + } + } + + if (!isset($trackdataarray) || !is_array($trackdataarray)) { + $info['error'][] = 'Cannot find MIDI track information'; + unset($thisfile_midi); + unset($info['fileformat']); + return false; + } + + if ($this->scanwholefile) { // this can take quite a long time, so have the option to bypass it if speed is very important + $thisfile_midi['totalticks'] = 0; + $info['playtime_seconds'] = 0; + $CurrentMicroSecondsPerBeat = 500000; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat + $CurrentBeatsPerMinute = 120; // 120 beats per minute; 60,000,000 microseconds per minute -> 500,000 microseconds per beat + $MicroSecondsPerQuarterNoteAfter = array (); + + foreach ($trackdataarray as $tracknumber => $trackdata) { + + $eventsoffset = 0; + $LastIssuedMIDIcommand = 0; + $LastIssuedMIDIchannel = 0; + $CumulativeDeltaTime = 0; + $TicksAtCurrentBPM = 0; + while ($eventsoffset < strlen($trackdata)) { + $eventid = 0; + if (isset($MIDIevents[$tracknumber]) && is_array($MIDIevents[$tracknumber])) { + $eventid = count($MIDIevents[$tracknumber]); + } + $deltatime = 0; + for ($i = 0; $i < 4; $i++) { + $deltatimebyte = ord(substr($trackdata, $eventsoffset++, 1)); + $deltatime = ($deltatime << 7) + ($deltatimebyte & 0x7F); + if ($deltatimebyte & 0x80) { + // another byte follows + } else { + break; + } + } + $CumulativeDeltaTime += $deltatime; + $TicksAtCurrentBPM += $deltatime; + $MIDIevents[$tracknumber][$eventid]['deltatime'] = $deltatime; + $MIDI_event_channel = ord(substr($trackdata, $eventsoffset++, 1)); + if ($MIDI_event_channel & 0x80) { + // OK, normal event - MIDI command has MSB set + $LastIssuedMIDIcommand = $MIDI_event_channel >> 4; + $LastIssuedMIDIchannel = $MIDI_event_channel & 0x0F; + } else { + // running event - assume last command + $eventsoffset--; + } + $MIDIevents[$tracknumber][$eventid]['eventid'] = $LastIssuedMIDIcommand; + $MIDIevents[$tracknumber][$eventid]['channel'] = $LastIssuedMIDIchannel; + if ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x08) { // Note off (key is released) + + $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); + $velocity = ord(substr($trackdata, $eventsoffset++, 1)); + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x09) { // Note on (key is pressed) + + $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); + $velocity = ord(substr($trackdata, $eventsoffset++, 1)); + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0A) { // Key after-touch + + $notenumber = ord(substr($trackdata, $eventsoffset++, 1)); + $velocity = ord(substr($trackdata, $eventsoffset++, 1)); + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0B) { // Control Change + + $controllernum = ord(substr($trackdata, $eventsoffset++, 1)); + $newvalue = ord(substr($trackdata, $eventsoffset++, 1)); + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0C) { // Program (patch) change + + $newprogramnum = ord(substr($trackdata, $eventsoffset++, 1)); + + $thisfile_midi_raw['track'][$tracknumber]['instrumentid'] = $newprogramnum; + if ($tracknumber == 10) { + $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIpercussionLookup($newprogramnum); + } else { + $thisfile_midi_raw['track'][$tracknumber]['instrument'] = $this->GeneralMIDIinstrumentLookup($newprogramnum); + } + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0D) { // Channel after-touch + + $channelnumber = ord(substr($trackdata, $eventsoffset++, 1)); + + } elseif ($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0E) { // Pitch wheel change (2000H is normal or no change) + + $changeLSB = ord(substr($trackdata, $eventsoffset++, 1)); + $changeMSB = ord(substr($trackdata, $eventsoffset++, 1)); + $pitchwheelchange = (($changeMSB & 0x7F) << 7) & ($changeLSB & 0x7F); + + } elseif (($MIDIevents[$tracknumber][$eventid]['eventid'] == 0x0F) && ($MIDIevents[$tracknumber][$eventid]['channel'] == 0x0F)) { + + $METAeventCommand = ord(substr($trackdata, $eventsoffset++, 1)); + $METAeventLength = ord(substr($trackdata, $eventsoffset++, 1)); + $METAeventData = substr($trackdata, $eventsoffset, $METAeventLength); + $eventsoffset += $METAeventLength; + switch ($METAeventCommand) { + case 0x00: // Set track sequence number + $track_sequence_number = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength)); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['seqno'] = $track_sequence_number; + break; + + case 0x01: // Text: generic + $text_generic = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['text'] = $text_generic; + $thisfile_midi['comments']['comment'][] = $text_generic; + break; + + case 0x02: // Text: copyright + $text_copyright = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['copyright'] = $text_copyright; + $thisfile_midi['comments']['copyright'][] = $text_copyright; + break; + + case 0x03: // Text: track name + $text_trackname = substr($METAeventData, 0, $METAeventLength); + $thisfile_midi_raw['track'][$tracknumber]['name'] = $text_trackname; + break; + + case 0x04: // Text: track instrument name + $text_instrument = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['instrument'] = $text_instrument; + break; + + case 0x05: // Text: lyrics + $text_lyrics = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['lyrics'] = $text_lyrics; + if (!isset($thisfile_midi['lyrics'])) { + $thisfile_midi['lyrics'] = ''; + } + $thisfile_midi['lyrics'] .= $text_lyrics."\n"; + break; + + case 0x06: // Text: marker + $text_marker = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['marker'] = $text_marker; + break; + + case 0x07: // Text: cue point + $text_cuepoint = substr($METAeventData, 0, $METAeventLength); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['cuepoint'] = $text_cuepoint; + break; + + case 0x2F: // End Of Track + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['EOT'] = $CumulativeDeltaTime; + break; + + case 0x51: // Tempo: microseconds / quarter note + $CurrentMicroSecondsPerBeat = getid3_lib::BigEndian2Int(substr($METAeventData, 0, $METAeventLength)); + if ($CurrentMicroSecondsPerBeat == 0) { + $info['error'][] = 'Corrupt MIDI file: CurrentMicroSecondsPerBeat == zero'; + return false; + } + $thisfile_midi_raw['events'][$tracknumber][$CumulativeDeltaTime]['us_qnote'] = $CurrentMicroSecondsPerBeat; + $CurrentBeatsPerMinute = (1000000 / $CurrentMicroSecondsPerBeat) * 60; + $MicroSecondsPerQuarterNoteAfter[$CumulativeDeltaTime] = $CurrentMicroSecondsPerBeat; + $TicksAtCurrentBPM = 0; + break; + + case 0x58: // Time signature + $timesig_numerator = getid3_lib::BigEndian2Int($METAeventData{0}); + $timesig_denominator = pow(2, getid3_lib::BigEndian2Int($METAeventData{1})); // $02 -> x/4, $03 -> x/8, etc + $timesig_32inqnote = getid3_lib::BigEndian2Int($METAeventData{2}); // number of 32nd notes to the quarter note + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_32inqnote'] = $timesig_32inqnote; + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_numerator'] = $timesig_numerator; + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_denominator'] = $timesig_denominator; + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['timesig_text'] = $timesig_numerator.'/'.$timesig_denominator; + $thisfile_midi['timesignature'][] = $timesig_numerator.'/'.$timesig_denominator; + break; + + case 0x59: // Keysignature + $keysig_sharpsflats = getid3_lib::BigEndian2Int($METAeventData{0}); + if ($keysig_sharpsflats & 0x80) { + // (-7 -> 7 flats, 0 ->key of C, 7 -> 7 sharps) + $keysig_sharpsflats -= 256; + } + + $keysig_majorminor = getid3_lib::BigEndian2Int($METAeventData{1}); // 0 -> major, 1 -> minor + $keysigs = array(-7=>'Cb', -6=>'Gb', -5=>'Db', -4=>'Ab', -3=>'Eb', -2=>'Bb', -1=>'F', 0=>'C', 1=>'G', 2=>'D', 3=>'A', 4=>'E', 5=>'B', 6=>'F#', 7=>'C#'); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_sharps'] = (($keysig_sharpsflats > 0) ? abs($keysig_sharpsflats) : 0); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_flats'] = (($keysig_sharpsflats < 0) ? abs($keysig_sharpsflats) : 0); + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] = (bool) $keysig_majorminor; + //$thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_text'] = $keysigs[$keysig_sharpsflats].' '.($thisfile_midi_raw['events'][$tracknumber][$eventid]['keysig_minor'] ? 'minor' : 'major'); + + // $keysigs[$keysig_sharpsflats] gets an int key (correct) - $keysigs["$keysig_sharpsflats"] gets a string key (incorrect) + $thisfile_midi['keysignature'][] = $keysigs[$keysig_sharpsflats].' '.((bool) $keysig_majorminor ? 'minor' : 'major'); + break; + + case 0x7F: // Sequencer specific information + $custom_data = substr($METAeventData, 0, $METAeventLength); + break; + + default: + $info['warning'][] = 'Unhandled META Event Command: '.$METAeventCommand; + break; + } + + } else { + + $info['warning'][] = 'Unhandled MIDI Event ID: '.$MIDIevents[$tracknumber][$eventid]['eventid'].' + Channel ID: '.$MIDIevents[$tracknumber][$eventid]['channel']; + + } + } + if (($tracknumber > 0) || (count($trackdataarray) == 1)) { + $thisfile_midi['totalticks'] = max($thisfile_midi['totalticks'], $CumulativeDeltaTime); + } + } + $previoustickoffset = null; + + ksort($MicroSecondsPerQuarterNoteAfter); + foreach ($MicroSecondsPerQuarterNoteAfter as $tickoffset => $microsecondsperbeat) { + if (is_null($previoustickoffset)) { + $prevmicrosecondsperbeat = $microsecondsperbeat; + $previoustickoffset = $tickoffset; + continue; + } + if ($thisfile_midi['totalticks'] > $tickoffset) { + + if ($thisfile_midi_raw['ticksperqnote'] == 0) { + $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero'; + return false; + } + + $info['playtime_seconds'] += (($tickoffset - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($prevmicrosecondsperbeat / 1000000); + + $prevmicrosecondsperbeat = $microsecondsperbeat; + $previoustickoffset = $tickoffset; + } + } + if ($thisfile_midi['totalticks'] > $previoustickoffset) { + + if ($thisfile_midi_raw['ticksperqnote'] == 0) { + $info['error'][] = 'Corrupt MIDI file: ticksperqnote == zero'; + return false; + } + + $info['playtime_seconds'] += (($thisfile_midi['totalticks'] - $previoustickoffset) / $thisfile_midi_raw['ticksperqnote']) * ($microsecondsperbeat / 1000000); + + } + } + + + if (!empty($info['playtime_seconds'])) { + $info['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + + if (!empty($thisfile_midi['lyrics'])) { + $thisfile_midi['comments']['lyrics'][] = $thisfile_midi['lyrics']; + } + + return true; + } + + public function GeneralMIDIinstrumentLookup($instrumentid) { + + $begin = __LINE__; + + /** This is not a comment! + + 0 Acoustic Grand + 1 Bright Acoustic + 2 Electric Grand + 3 Honky-Tonk + 4 Electric Piano 1 + 5 Electric Piano 2 + 6 Harpsichord + 7 Clavier + 8 Celesta + 9 Glockenspiel + 10 Music Box + 11 Vibraphone + 12 Marimba + 13 Xylophone + 14 Tubular Bells + 15 Dulcimer + 16 Drawbar Organ + 17 Percussive Organ + 18 Rock Organ + 19 Church Organ + 20 Reed Organ + 21 Accordian + 22 Harmonica + 23 Tango Accordian + 24 Acoustic Guitar (nylon) + 25 Acoustic Guitar (steel) + 26 Electric Guitar (jazz) + 27 Electric Guitar (clean) + 28 Electric Guitar (muted) + 29 Overdriven Guitar + 30 Distortion Guitar + 31 Guitar Harmonics + 32 Acoustic Bass + 33 Electric Bass (finger) + 34 Electric Bass (pick) + 35 Fretless Bass + 36 Slap Bass 1 + 37 Slap Bass 2 + 38 Synth Bass 1 + 39 Synth Bass 2 + 40 Violin + 41 Viola + 42 Cello + 43 Contrabass + 44 Tremolo Strings + 45 Pizzicato Strings + 46 Orchestral Strings + 47 Timpani + 48 String Ensemble 1 + 49 String Ensemble 2 + 50 SynthStrings 1 + 51 SynthStrings 2 + 52 Choir Aahs + 53 Voice Oohs + 54 Synth Voice + 55 Orchestra Hit + 56 Trumpet + 57 Trombone + 58 Tuba + 59 Muted Trumpet + 60 French Horn + 61 Brass Section + 62 SynthBrass 1 + 63 SynthBrass 2 + 64 Soprano Sax + 65 Alto Sax + 66 Tenor Sax + 67 Baritone Sax + 68 Oboe + 69 English Horn + 70 Bassoon + 71 Clarinet + 72 Piccolo + 73 Flute + 74 Recorder + 75 Pan Flute + 76 Blown Bottle + 77 Shakuhachi + 78 Whistle + 79 Ocarina + 80 Lead 1 (square) + 81 Lead 2 (sawtooth) + 82 Lead 3 (calliope) + 83 Lead 4 (chiff) + 84 Lead 5 (charang) + 85 Lead 6 (voice) + 86 Lead 7 (fifths) + 87 Lead 8 (bass + lead) + 88 Pad 1 (new age) + 89 Pad 2 (warm) + 90 Pad 3 (polysynth) + 91 Pad 4 (choir) + 92 Pad 5 (bowed) + 93 Pad 6 (metallic) + 94 Pad 7 (halo) + 95 Pad 8 (sweep) + 96 FX 1 (rain) + 97 FX 2 (soundtrack) + 98 FX 3 (crystal) + 99 FX 4 (atmosphere) + 100 FX 5 (brightness) + 101 FX 6 (goblins) + 102 FX 7 (echoes) + 103 FX 8 (sci-fi) + 104 Sitar + 105 Banjo + 106 Shamisen + 107 Koto + 108 Kalimba + 109 Bagpipe + 110 Fiddle + 111 Shanai + 112 Tinkle Bell + 113 Agogo + 114 Steel Drums + 115 Woodblock + 116 Taiko Drum + 117 Melodic Tom + 118 Synth Drum + 119 Reverse Cymbal + 120 Guitar Fret Noise + 121 Breath Noise + 122 Seashore + 123 Bird Tweet + 124 Telephone Ring + 125 Helicopter + 126 Applause + 127 Gunshot + + */ + + return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIinstrument'); + } + + public function GeneralMIDIpercussionLookup($instrumentid) { + + $begin = __LINE__; + + /** This is not a comment! + + 35 Acoustic Bass Drum + 36 Bass Drum 1 + 37 Side Stick + 38 Acoustic Snare + 39 Hand Clap + 40 Electric Snare + 41 Low Floor Tom + 42 Closed Hi-Hat + 43 High Floor Tom + 44 Pedal Hi-Hat + 45 Low Tom + 46 Open Hi-Hat + 47 Low-Mid Tom + 48 Hi-Mid Tom + 49 Crash Cymbal 1 + 50 High Tom + 51 Ride Cymbal 1 + 52 Chinese Cymbal + 53 Ride Bell + 54 Tambourine + 55 Splash Cymbal + 56 Cowbell + 57 Crash Cymbal 2 + 59 Ride Cymbal 2 + 60 Hi Bongo + 61 Low Bongo + 62 Mute Hi Conga + 63 Open Hi Conga + 64 Low Conga + 65 High Timbale + 66 Low Timbale + 67 High Agogo + 68 Low Agogo + 69 Cabasa + 70 Maracas + 71 Short Whistle + 72 Long Whistle + 73 Short Guiro + 74 Long Guiro + 75 Claves + 76 Hi Wood Block + 77 Low Wood Block + 78 Mute Cuica + 79 Open Cuica + 80 Mute Triangle + 81 Open Triangle + + */ + + return getid3_lib::EmbeddedLookup($instrumentid, $begin, __LINE__, __FILE__, 'GeneralMIDIpercussion'); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.mod.php b/app/libs/vendor/getid3/module.audio.mod.php index a2ae51c8..3bed8586 100644 --- a/app/libs/vendor/getid3/module.audio.mod.php +++ b/app/libs/vendor/getid3/module.audio.mod.php @@ -1,98 +1,98 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.mod.php // -// module for analyzing MOD Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_mod extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $fileheader = fread($this->getid3->fp, 1088); - if (preg_match('#^IMPM#', $fileheader)) { - return $this->getITheaderFilepointer(); - } elseif (preg_match('#^Extended Module#', $fileheader)) { - return $this->getXMheaderFilepointer(); - } elseif (preg_match('#^.{44}SCRM#', $fileheader)) { - return $this->getS3MheaderFilepointer(); - } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) { - return $this->getMODheaderFilepointer(); - } - $info['error'][] = 'This is not a known type of MOD file'; - return false; - } - - - public function getMODheaderFilepointer() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'] + 1080); - $FormatID = fread($this->getid3->fp, 4); - if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) { - $info['error'][] = 'This is not a known type of MOD file'; - return false; - } - - $info['fileformat'] = 'mod'; - - $info['error'][] = 'MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; - return false; - } - - public function getXMheaderFilepointer() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset']); - $FormatID = fread($this->getid3->fp, 15); - if (!preg_match('#^Extended Module$#', $FormatID)) { - $info['error'][] = 'This is not a known type of XM-MOD file'; - return false; - } - - $info['fileformat'] = 'xm'; - - $info['error'][] = 'XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; - return false; - } - - public function getS3MheaderFilepointer() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'] + 44); - $FormatID = fread($this->getid3->fp, 4); - if (!preg_match('#^SCRM$#', $FormatID)) { - $info['error'][] = 'This is not a ScreamTracker MOD file'; - return false; - } - - $info['fileformat'] = 's3m'; - - $info['error'][] = 'ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; - return false; - } - - public function getITheaderFilepointer() { - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset']); - $FormatID = fread($this->getid3->fp, 4); - if (!preg_match('#^IMPM$#', $FormatID)) { - $info['error'][] = 'This is not an ImpulseTracker MOD file'; - return false; - } - - $info['fileformat'] = 'it'; - - $info['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.mod.php // +// module for analyzing MOD Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_mod extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $fileheader = fread($this->getid3->fp, 1088); + if (preg_match('#^IMPM#', $fileheader)) { + return $this->getITheaderFilepointer(); + } elseif (preg_match('#^Extended Module#', $fileheader)) { + return $this->getXMheaderFilepointer(); + } elseif (preg_match('#^.{44}SCRM#', $fileheader)) { + return $this->getS3MheaderFilepointer(); + } elseif (preg_match('#^.{1080}(M\\.K\\.|M!K!|FLT4|FLT8|[5-9]CHN|[1-3][0-9]CH)#', $fileheader)) { + return $this->getMODheaderFilepointer(); + } + $info['error'][] = 'This is not a known type of MOD file'; + return false; + } + + + public function getMODheaderFilepointer() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'] + 1080); + $FormatID = fread($this->getid3->fp, 4); + if (!preg_match('#^(M.K.|[5-9]CHN|[1-3][0-9]CH)$#', $FormatID)) { + $info['error'][] = 'This is not a known type of MOD file'; + return false; + } + + $info['fileformat'] = 'mod'; + + $info['error'][] = 'MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; + return false; + } + + public function getXMheaderFilepointer() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset']); + $FormatID = fread($this->getid3->fp, 15); + if (!preg_match('#^Extended Module$#', $FormatID)) { + $info['error'][] = 'This is not a known type of XM-MOD file'; + return false; + } + + $info['fileformat'] = 'xm'; + + $info['error'][] = 'XM-MOD parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; + return false; + } + + public function getS3MheaderFilepointer() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'] + 44); + $FormatID = fread($this->getid3->fp, 4); + if (!preg_match('#^SCRM$#', $FormatID)) { + $info['error'][] = 'This is not a ScreamTracker MOD file'; + return false; + } + + $info['fileformat'] = 's3m'; + + $info['error'][] = 'ScreamTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; + return false; + } + + public function getITheaderFilepointer() { + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset']); + $FormatID = fread($this->getid3->fp, 4); + if (!preg_match('#^IMPM$#', $FormatID)) { + $info['error'][] = 'This is not an ImpulseTracker MOD file'; + return false; + } + + $info['fileformat'] = 'it'; + + $info['error'][] = 'ImpulseTracker parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; + return false; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.monkey.php b/app/libs/vendor/getid3/module.audio.monkey.php index 1dbb88db..941a0b3e 100644 --- a/app/libs/vendor/getid3/module.audio.monkey.php +++ b/app/libs/vendor/getid3/module.audio.monkey.php @@ -1,203 +1,203 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.monkey.php // -// module for analyzing Monkey's Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_monkey extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - // based loosely on code from TMonkey by Jurgen Faul - // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html - - $info['fileformat'] = 'mac'; - $info['audio']['dataformat'] = 'mac'; - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['lossless'] = true; - - $info['monkeys_audio']['raw'] = array(); - $thisfile_monkeysaudio = &$info['monkeys_audio']; - $thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw']; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $MACheaderData = fread($this->getid3->fp, 74); - - $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4); - $magic = 'MAC '; - if ($thisfile_monkeysaudio_raw['magic'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"'; - unset($info['fileformat']); - return false; - } - $thisfile_monkeysaudio_raw['nVersion'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 4, 2)); // appears to be uint32 in 3.98+ - - if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) { - $thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 6, 2)); - $thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 8, 2)); - $thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 10, 2)); - $thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 12, 4)); - $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 16, 4)); - $thisfile_monkeysaudio_raw['nWAVTerminatingBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 20, 4)); - $thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 24, 4)); - $thisfile_monkeysaudio_raw['nFinalFrameSamples'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 28, 4)); - $thisfile_monkeysaudio_raw['nPeakLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 32, 4)); - $thisfile_monkeysaudio_raw['nSeekElements'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 38, 2)); - $offset = 8; - } else { - $offset = 8; - // APE_DESCRIPTOR - $thisfile_monkeysaudio_raw['nDescriptorBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nHeaderBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nSeekTableBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nAPEFrameDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nAPEFrameDataBytesHigh'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nTerminatingDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16); - $offset += 16; - - // APE_HEADER - $thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); - $offset += 2; - $thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); - $offset += 2; - $thisfile_monkeysaudio_raw['nBlocksPerFrame'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nFinalFrameBlocks'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - $thisfile_monkeysaudio_raw['nBitsPerSample'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); - $offset += 2; - $thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); - $offset += 2; - $thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); - $offset += 4; - } - - $thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0001); - $thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0002); - $thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0004); - $thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0008); - $thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0010); - $thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0020); - $thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000; - $thisfile_monkeysaudio['compression'] = $this->MonkeyCompressionLevelNameLookup($thisfile_monkeysaudio_raw['nCompressionLevel']); - if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) { - $thisfile_monkeysaudio['samples_per_frame'] = $this->MonkeySamplesPerFrame($thisfile_monkeysaudio_raw['nVersion'], $thisfile_monkeysaudio_raw['nCompressionLevel']); - } - $thisfile_monkeysaudio['bits_per_sample'] = ($thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16)); - $thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels']; - $info['audio']['channels'] = $thisfile_monkeysaudio['channels']; - $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate']; - if ($thisfile_monkeysaudio['sample_rate'] == 0) { - $info['error'][] = 'Corrupt MAC file: frequency == zero'; - return false; - } - $info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate']; - if ($thisfile_monkeysaudio['flags']['peak_level']) { - $thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel']; - $thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1); - } - if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { - $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame']) + $thisfile_monkeysaudio_raw['nFinalFrameBlocks']; - } else { - $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame']) + $thisfile_monkeysaudio_raw['nFinalFrameSamples']; - } - $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate']; - if ($thisfile_monkeysaudio['playtime'] == 0) { - $info['error'][] = 'Corrupt MAC file: playtime == zero'; - return false; - } - $info['playtime_seconds'] = $thisfile_monkeysaudio['playtime']; - $thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset']; - $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8); - if ($thisfile_monkeysaudio['uncompressed_size'] == 0) { - $info['error'][] = 'Corrupt MAC file: uncompressed_size == zero'; - return false; - } - $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']); - $thisfile_monkeysaudio['bitrate'] = (($thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample']) / $thisfile_monkeysaudio['playtime']) * $thisfile_monkeysaudio['compression_ratio']; - $info['audio']['bitrate'] = $thisfile_monkeysaudio['bitrate']; - - // add size of MAC header to avdataoffset - if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { - $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nDescriptorBytes']; - $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderBytes']; - $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nSeekTableBytes']; - $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderDataBytes']; - - $info['avdataend'] -= $thisfile_monkeysaudio_raw['nTerminatingDataBytes']; - } else { - $info['avdataoffset'] += $offset; - } - - if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { - if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) { - //$info['warning'][] = 'cFileMD5 is null'; - } else { - $info['md5_data_source'] = ''; - $md5 = $thisfile_monkeysaudio_raw['cFileMD5']; - for ($i = 0; $i < strlen($md5); $i++) { - $info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); - } - if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) { - unset($info['md5_data_source']); - } - } - } - - - - $info['audio']['bits_per_sample'] = $thisfile_monkeysaudio['bits_per_sample']; - $info['audio']['encoder'] = 'MAC v'.number_format($thisfile_monkeysaudio['version'], 2); - $info['audio']['encoder_options'] = ucfirst($thisfile_monkeysaudio['compression']).' compression'; - - return true; - } - - public function MonkeyCompressionLevelNameLookup($compressionlevel) { - static $MonkeyCompressionLevelNameLookup = array( - 0 => 'unknown', - 1000 => 'fast', - 2000 => 'normal', - 3000 => 'high', - 4000 => 'extra-high', - 5000 => 'insane' - ); - return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid'); - } - - public function MonkeySamplesPerFrame($versionid, $compressionlevel) { - if ($versionid >= 3950) { - return 73728 * 4; - } elseif ($versionid >= 3900) { - return 73728; - } elseif (($versionid >= 3800) && ($compressionlevel == 4000)) { - return 73728; - } else { - return 9216; - } - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.monkey.php // +// module for analyzing Monkey's Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_monkey extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + // based loosely on code from TMonkey by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + $info['fileformat'] = 'mac'; + $info['audio']['dataformat'] = 'mac'; + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['lossless'] = true; + + $info['monkeys_audio']['raw'] = array(); + $thisfile_monkeysaudio = &$info['monkeys_audio']; + $thisfile_monkeysaudio_raw = &$thisfile_monkeysaudio['raw']; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $MACheaderData = fread($this->getid3->fp, 74); + + $thisfile_monkeysaudio_raw['magic'] = substr($MACheaderData, 0, 4); + $magic = 'MAC '; + if ($thisfile_monkeysaudio_raw['magic'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_monkeysaudio_raw['magic']).'"'; + unset($info['fileformat']); + return false; + } + $thisfile_monkeysaudio_raw['nVersion'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 4, 2)); // appears to be uint32 in 3.98+ + + if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) { + $thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 6, 2)); + $thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 8, 2)); + $thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 10, 2)); + $thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 12, 4)); + $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 16, 4)); + $thisfile_monkeysaudio_raw['nWAVTerminatingBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 20, 4)); + $thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 24, 4)); + $thisfile_monkeysaudio_raw['nFinalFrameSamples'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 28, 4)); + $thisfile_monkeysaudio_raw['nPeakLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 32, 4)); + $thisfile_monkeysaudio_raw['nSeekElements'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, 38, 2)); + $offset = 8; + } else { + $offset = 8; + // APE_DESCRIPTOR + $thisfile_monkeysaudio_raw['nDescriptorBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nHeaderBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nSeekTableBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nHeaderDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nAPEFrameDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nAPEFrameDataBytesHigh'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nTerminatingDataBytes'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['cFileMD5'] = substr($MACheaderData, $offset, 16); + $offset += 16; + + // APE_HEADER + $thisfile_monkeysaudio_raw['nCompressionLevel'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); + $offset += 2; + $thisfile_monkeysaudio_raw['nFormatFlags'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); + $offset += 2; + $thisfile_monkeysaudio_raw['nBlocksPerFrame'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nFinalFrameBlocks'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nTotalFrames'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + $thisfile_monkeysaudio_raw['nBitsPerSample'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); + $offset += 2; + $thisfile_monkeysaudio_raw['nChannels'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 2)); + $offset += 2; + $thisfile_monkeysaudio_raw['nSampleRate'] = getid3_lib::LittleEndian2Int(substr($MACheaderData, $offset, 4)); + $offset += 4; + } + + $thisfile_monkeysaudio['flags']['8-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0001); + $thisfile_monkeysaudio['flags']['crc-32'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0002); + $thisfile_monkeysaudio['flags']['peak_level'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0004); + $thisfile_monkeysaudio['flags']['24-bit'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0008); + $thisfile_monkeysaudio['flags']['seek_elements'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0010); + $thisfile_monkeysaudio['flags']['no_wav_header'] = (bool) ($thisfile_monkeysaudio_raw['nFormatFlags'] & 0x0020); + $thisfile_monkeysaudio['version'] = $thisfile_monkeysaudio_raw['nVersion'] / 1000; + $thisfile_monkeysaudio['compression'] = $this->MonkeyCompressionLevelNameLookup($thisfile_monkeysaudio_raw['nCompressionLevel']); + if ($thisfile_monkeysaudio_raw['nVersion'] < 3980) { + $thisfile_monkeysaudio['samples_per_frame'] = $this->MonkeySamplesPerFrame($thisfile_monkeysaudio_raw['nVersion'], $thisfile_monkeysaudio_raw['nCompressionLevel']); + } + $thisfile_monkeysaudio['bits_per_sample'] = ($thisfile_monkeysaudio['flags']['24-bit'] ? 24 : ($thisfile_monkeysaudio['flags']['8-bit'] ? 8 : 16)); + $thisfile_monkeysaudio['channels'] = $thisfile_monkeysaudio_raw['nChannels']; + $info['audio']['channels'] = $thisfile_monkeysaudio['channels']; + $thisfile_monkeysaudio['sample_rate'] = $thisfile_monkeysaudio_raw['nSampleRate']; + if ($thisfile_monkeysaudio['sample_rate'] == 0) { + $info['error'][] = 'Corrupt MAC file: frequency == zero'; + return false; + } + $info['audio']['sample_rate'] = $thisfile_monkeysaudio['sample_rate']; + if ($thisfile_monkeysaudio['flags']['peak_level']) { + $thisfile_monkeysaudio['peak_level'] = $thisfile_monkeysaudio_raw['nPeakLevel']; + $thisfile_monkeysaudio['peak_ratio'] = $thisfile_monkeysaudio['peak_level'] / pow(2, $thisfile_monkeysaudio['bits_per_sample'] - 1); + } + if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { + $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio_raw['nBlocksPerFrame']) + $thisfile_monkeysaudio_raw['nFinalFrameBlocks']; + } else { + $thisfile_monkeysaudio['samples'] = (($thisfile_monkeysaudio_raw['nTotalFrames'] - 1) * $thisfile_monkeysaudio['samples_per_frame']) + $thisfile_monkeysaudio_raw['nFinalFrameSamples']; + } + $thisfile_monkeysaudio['playtime'] = $thisfile_monkeysaudio['samples'] / $thisfile_monkeysaudio['sample_rate']; + if ($thisfile_monkeysaudio['playtime'] == 0) { + $info['error'][] = 'Corrupt MAC file: playtime == zero'; + return false; + } + $info['playtime_seconds'] = $thisfile_monkeysaudio['playtime']; + $thisfile_monkeysaudio['compressed_size'] = $info['avdataend'] - $info['avdataoffset']; + $thisfile_monkeysaudio['uncompressed_size'] = $thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * ($thisfile_monkeysaudio['bits_per_sample'] / 8); + if ($thisfile_monkeysaudio['uncompressed_size'] == 0) { + $info['error'][] = 'Corrupt MAC file: uncompressed_size == zero'; + return false; + } + $thisfile_monkeysaudio['compression_ratio'] = $thisfile_monkeysaudio['compressed_size'] / ($thisfile_monkeysaudio['uncompressed_size'] + $thisfile_monkeysaudio_raw['nHeaderDataBytes']); + $thisfile_monkeysaudio['bitrate'] = (($thisfile_monkeysaudio['samples'] * $thisfile_monkeysaudio['channels'] * $thisfile_monkeysaudio['bits_per_sample']) / $thisfile_monkeysaudio['playtime']) * $thisfile_monkeysaudio['compression_ratio']; + $info['audio']['bitrate'] = $thisfile_monkeysaudio['bitrate']; + + // add size of MAC header to avdataoffset + if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { + $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nDescriptorBytes']; + $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderBytes']; + $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nSeekTableBytes']; + $info['avdataoffset'] += $thisfile_monkeysaudio_raw['nHeaderDataBytes']; + + $info['avdataend'] -= $thisfile_monkeysaudio_raw['nTerminatingDataBytes']; + } else { + $info['avdataoffset'] += $offset; + } + + if ($thisfile_monkeysaudio_raw['nVersion'] >= 3980) { + if ($thisfile_monkeysaudio_raw['cFileMD5'] === str_repeat("\x00", 16)) { + //$info['warning'][] = 'cFileMD5 is null'; + } else { + $info['md5_data_source'] = ''; + $md5 = $thisfile_monkeysaudio_raw['cFileMD5']; + for ($i = 0; $i < strlen($md5); $i++) { + $info['md5_data_source'] .= str_pad(dechex(ord($md5{$i})), 2, '00', STR_PAD_LEFT); + } + if (!preg_match('/^[0-9a-f]{32}$/', $info['md5_data_source'])) { + unset($info['md5_data_source']); + } + } + } + + + + $info['audio']['bits_per_sample'] = $thisfile_monkeysaudio['bits_per_sample']; + $info['audio']['encoder'] = 'MAC v'.number_format($thisfile_monkeysaudio['version'], 2); + $info['audio']['encoder_options'] = ucfirst($thisfile_monkeysaudio['compression']).' compression'; + + return true; + } + + public function MonkeyCompressionLevelNameLookup($compressionlevel) { + static $MonkeyCompressionLevelNameLookup = array( + 0 => 'unknown', + 1000 => 'fast', + 2000 => 'normal', + 3000 => 'high', + 4000 => 'extra-high', + 5000 => 'insane' + ); + return (isset($MonkeyCompressionLevelNameLookup[$compressionlevel]) ? $MonkeyCompressionLevelNameLookup[$compressionlevel] : 'invalid'); + } + + public function MonkeySamplesPerFrame($versionid, $compressionlevel) { + if ($versionid >= 3950) { + return 73728 * 4; + } elseif ($versionid >= 3900) { + return 73728; + } elseif (($versionid >= 3800) && ($compressionlevel == 4000)) { + return 73728; + } else { + return 9216; + } + } + +} diff --git a/app/libs/vendor/getid3/module.audio.mp3.php b/app/libs/vendor/getid3/module.audio.mp3.php index 554e6903..e6ffea94 100644 --- a/app/libs/vendor/getid3/module.audio.mp3.php +++ b/app/libs/vendor/getid3/module.audio.mp3.php @@ -1,2009 +1,2009 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.mp3.php // -// module for analyzing MP3 files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -// number of frames to scan to determine if MPEG-audio sequence is valid -// Lower this number to 5-20 for faster scanning -// Increase this number to 50+ for most accurate detection of valid VBR/CBR -// mpeg-audio streams -define('GETID3_MP3_VALID_CHECK_FRAMES', 35); - - -class getid3_mp3 extends getid3_handler -{ - - public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files - - public function Analyze() { - $info = &$this->getid3->info; - - $initialOffset = $info['avdataoffset']; - - if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) { - if ($this->allow_bruteforce) { - $info['error'][] = 'Rescanning file in BruteForce mode'; - $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info); - } - } - - - if (isset($info['mpeg']['audio']['bitrate_mode'])) { - $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); - } - - if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) { - - $synchoffsetwarning = 'Unknown data before synch '; - if (isset($info['id3v2']['headerlength'])) { - $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, '; - } elseif ($initialOffset > 0) { - $synchoffsetwarning .= '(should be at '.$initialOffset.', '; - } else { - $synchoffsetwarning .= '(should be at beginning of file, '; - } - $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')'; - if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) { - - if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) { - - $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.'; - $info['audio']['codec'] = 'LAME'; - $CurrentDataLAMEversionString = 'LAME3.'; - - } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) { - - $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.'; - $info['audio']['codec'] = 'LAME'; - $CurrentDataLAMEversionString = 'LAME3.'; - - } - - } - $info['warning'][] = $synchoffsetwarning; - - } - - if (isset($info['mpeg']['audio']['LAME'])) { - $info['audio']['codec'] = 'LAME'; - if (!empty($info['mpeg']['audio']['LAME']['long_version'])) { - $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00"); - } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) { - $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00"); - } - } - - $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : '')); - if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) { - // a version number of LAME that does not end with a number like "LAME3.92" - // or with a closing parenthesis like "LAME3.88 (alpha)" - // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92) - - // not sure what the actual last frame length will be, but will be less than or equal to 1441 - $PossiblyLongerLAMEversion_FrameLength = 1441; - - // Not sure what version of LAME this is - look in padding of last frame for longer version string - $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength; - fseek($this->getid3->fp, $PossibleLAMEversionStringOffset); - $PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength); - switch (substr($CurrentDataLAMEversionString, -1)) { - case 'a': - case 'b': - // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example - // need to trim off "a" to match longer string - $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1); - break; - } - if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) { - if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) { - $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)" - if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) { - $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString; - } - } - } - } - if (!empty($info['audio']['encoder'])) { - $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 "); - } - - switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') { - case 1: - case 2: - $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; - break; - } - if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) { - switch ($info['audio']['dataformat']) { - case 'mp1': - case 'mp2': - case 'mp3': - $info['fileformat'] = $info['audio']['dataformat']; - break; - - default: - $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"'; - break; - } - } - - if (empty($info['fileformat'])) { - unset($info['fileformat']); - unset($info['audio']['bitrate_mode']); - unset($info['avdataoffset']); - unset($info['avdataend']); - return false; - } - - $info['mime_type'] = 'audio/mpeg'; - $info['audio']['lossless'] = false; - - // Calculate playtime - if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) { - $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; - } - - $info['audio']['encoder_options'] = $this->GuessEncoderOptions(); - - return true; - } - - - public function GuessEncoderOptions() { - // shortcuts - $info = &$this->getid3->info; - if (!empty($info['mpeg']['audio'])) { - $thisfile_mpeg_audio = &$info['mpeg']['audio']; - if (!empty($thisfile_mpeg_audio['LAME'])) { - $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; - } - } - - $encoder_options = ''; - static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256); - - if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) { - - $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality']; - - } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) { - - $encoder_options = $thisfile_mpeg_audio_lame['preset_used']; - - } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) { - - static $KnownEncoderValues = array(); - if (empty($KnownEncoderValues)) { - - //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name'; - $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92 - $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91 - $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95 - $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92 - $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91 - $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3 - $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92 - $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91 - $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3 - $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3 - $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92 - $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91 - $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95 - $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3 - $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3 - - $KnownEncoderValues[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1 - $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93 - $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95 - $KnownEncoderValues[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1 - $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93 - $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95 - $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1 - $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95 - $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 - $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1 - $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95 - $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1 - $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95 - $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14 - $KnownEncoderValues[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92 - $KnownEncoderValues[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91 - $KnownEncoderValues[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1 - $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95 - $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14 - $KnownEncoderValues[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15 - $KnownEncoderValues[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1 - $KnownEncoderValues[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93 - $KnownEncoderValues[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95 - $KnownEncoderValues[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14 - $KnownEncoderValues[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15 - $KnownEncoderValues[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1 - $KnownEncoderValues[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93 - $KnownEncoderValues[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95 - } - - if (isset($KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { - - $encoder_options = $KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; - - } elseif (isset($KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { - - $encoder_options = $KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; - - } elseif ($info['audio']['bitrate_mode'] == 'vbr') { - - // http://gabriel.mp3-tech.org/mp3infotag.html - // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h - - - $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10); - $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10); - $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value; - - } elseif ($info['audio']['bitrate_mode'] == 'cbr') { - - $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); - - } else { - - $encoder_options = strtoupper($info['audio']['bitrate_mode']); - - } - - } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) { - - $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr']; - - } elseif (!empty($info['audio']['bitrate'])) { - - if ($info['audio']['bitrate_mode'] == 'cbr') { - $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); - } else { - $encoder_options = strtoupper($info['audio']['bitrate_mode']); - } - - } - if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) { - $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; - } - - if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) { - $encoder_options .= ' --nogap'; - } - - if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) { - $ExplodedOptions = explode(' ', $encoder_options, 4); - if ($ExplodedOptions[0] == '--r3mix') { - $ExplodedOptions[1] = 'r3mix'; - } - switch ($ExplodedOptions[0]) { - case '--preset': - case '--alt-preset': - case '--r3mix': - if ($ExplodedOptions[1] == 'fast') { - $ExplodedOptions[1] .= ' '.$ExplodedOptions[2]; - } - switch ($ExplodedOptions[1]) { - case 'portable': - case 'medium': - case 'standard': - case 'extreme': - case 'insane': - case 'fast portable': - case 'fast medium': - case 'fast standard': - case 'fast extreme': - case 'fast insane': - case 'r3mix': - static $ExpectedLowpass = array( - 'insane|20500' => 20500, - 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91 - 'medium|18000' => 18000, - 'fast medium|18000' => 18000, - 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 - 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 - 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 - 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 - 'standard|19000' => 19000, - 'fast standard|19000' => 19000, - 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92 - 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91 - 'r3mix|18000' => 18000, // 3.94, 3.95 - ); - if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) { - $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency']; - } - break; - - default: - break; - } - break; - } - } - - if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) { - if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) { - $encoder_options .= ' --resample 44100'; - } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) { - $encoder_options .= ' --resample 48000'; - } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) { - switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) { - case 0: // <= 32000 - // may or may not be same as source frequency - ignore - break; - case 1: // 44100 - case 2: // 48000 - case 3: // 48000+ - $ExplodedOptions = explode(' ', $encoder_options, 4); - switch ($ExplodedOptions[0]) { - case '--preset': - case '--alt-preset': - switch ($ExplodedOptions[1]) { - case 'fast': - case 'portable': - case 'medium': - case 'standard': - case 'extreme': - case 'insane': - $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; - break; - - default: - static $ExpectedResampledRate = array( - 'phon+/lw/mw-eu/sw|16000' => 16000, - 'mw-us|24000' => 24000, // 3.95 - 'mw-us|32000' => 32000, // 3.93 - 'mw-us|16000' => 16000, // 3.92 - 'phone|16000' => 16000, - 'phone|11025' => 11025, // 3.94a15 - 'radio|32000' => 32000, // 3.94a15 - 'fm/radio|32000' => 32000, // 3.92 - 'fm|32000' => 32000, // 3.90 - 'voice|32000' => 32000); - if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) { - $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; - } - break; - } - break; - - case '--r3mix': - default: - $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; - break; - } - break; - } - } - } - if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) { - //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); - $encoder_options = strtoupper($info['audio']['bitrate_mode']); - } - - return $encoder_options; - } - - - public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) { - static $MPEGaudioVersionLookup; - static $MPEGaudioLayerLookup; - static $MPEGaudioBitrateLookup; - static $MPEGaudioFrequencyLookup; - static $MPEGaudioChannelModeLookup; - static $MPEGaudioModeExtensionLookup; - static $MPEGaudioEmphasisLookup; - if (empty($MPEGaudioVersionLookup)) { - $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); - $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); - $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); - $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); - $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); - $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); - $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); - } - - if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) { - $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset; - return false; - } - //$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame - $headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data - - // MP3 audio frame structure: - // $aa $aa $aa $aa [$bb $bb] $cc... - // where $aa..$aa is the four-byte mpeg-audio header (below) - // $bb $bb is the optional 2-byte CRC - // and $cc... is the audio data - - $head4 = substr($headerstring, 0, 4); - - static $MPEGaudioHeaderDecodeCache = array(); - if (isset($MPEGaudioHeaderDecodeCache[$head4])) { - $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4]; - } else { - $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4); - $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray; - } - - static $MPEGaudioHeaderValidCache = array(); - if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache - //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1) - $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false); - } - - // shortcut - if (!isset($info['mpeg']['audio'])) { - $info['mpeg']['audio'] = array(); - } - $thisfile_mpeg_audio = &$info['mpeg']['audio']; - - - if ($MPEGaudioHeaderValidCache[$head4]) { - $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; - } else { - $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset; - return false; - } - - if (!$FastMPEGheaderScan) { - $thisfile_mpeg_audio['version'] = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']]; - $thisfile_mpeg_audio['layer'] = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']]; - - $thisfile_mpeg_audio['channelmode'] = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']]; - $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2); - $thisfile_mpeg_audio['sample_rate'] = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']]; - $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection']; - $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private']; - $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']]; - $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright']; - $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original']; - $thisfile_mpeg_audio['emphasis'] = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']]; - - $info['audio']['channels'] = $thisfile_mpeg_audio['channels']; - $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate']; - - if ($thisfile_mpeg_audio['protection']) { - $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2)); - } - } - - if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) { - // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0 - $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1'; - $thisfile_mpeg_audio['raw']['bitrate'] = 0; - } - $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding']; - $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']]; - - if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) { - // only skip multiple frame check if free-format bitstream found at beginning of file - // otherwise is quite possibly simply corrupted data - $recursivesearch = false; - } - - // For Layer 2 there are some combinations of bitrate and mode which are not allowed. - if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) { - - $info['audio']['dataformat'] = 'mp2'; - switch ($thisfile_mpeg_audio['channelmode']) { - - case 'mono': - if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) { - // these are ok - } else { - $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'; - return false; - } - break; - - case 'stereo': - case 'joint stereo': - case 'dual channel': - if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) { - // these are ok - } else { - $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'; - return false; - } - break; - - } - - } - - - if ($info['audio']['sample_rate'] > 0) { - $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']); - } - - $nextframetestoffset = $offset + 1; - if ($thisfile_mpeg_audio['bitrate'] != 'free') { - - $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; - - if (isset($thisfile_mpeg_audio['framelength'])) { - $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength']; - } else { - $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.'; - return false; - } - - } - - $ExpectedNumberOfAudioBytes = 0; - - //////////////////////////////////////////////////////////////////////////////////// - // Variable-bitrate headers - - if (substr($headerstring, 4 + 32, 4) == 'VBRI') { - // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36) - // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html - - $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; - $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer'; - $info['audio']['codec'] = 'Fraunhofer'; - - $SideInfoData = substr($headerstring, 4 + 2, 32); - - $FraunhoferVBROffset = 36; - - $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2)); // VbriVersion - $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2)); // VbriDelay - $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2)); // VbriQuality - $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes - $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames - $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize - $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale - $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes - $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames - - $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes']; - - $previousbyteoffset = $offset; - for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) { - $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes'])); - $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes']; - $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']); - $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset; - $previousbyteoffset += $Fraunhofer_OffsetN; - } - - - } else { - - // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36) - // depending on MPEG layer and number of channels - - $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']); - $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4); - - if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) { - // 'Xing' is traditional Xing VBR frame - // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.) - // 'Info' *can* legally be used to specify a VBR file as well, however. - - // http://www.multiweb.cz/twoinches/MP3inside.htm - //00..03 = "Xing" or "Info" - //04..07 = Flags: - // 0x01 Frames Flag set if value for number of frames in file is stored - // 0x02 Bytes Flag set if value for filesize in bytes is stored - // 0x04 TOC Flag set if values for TOC are stored - // 0x08 VBR Scale Flag set if values for VBR scale is stored - //08..11 Frames: Number of frames in file (including the first Xing/Info one) - //12..15 Bytes: File length in Bytes - //16..115 TOC (Table of Contents): - // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file. - // Each Byte has a value according this formula: - // (TOC[i] / 256) * fileLenInBytes - // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use: - // TOC[(60/240)*100] = TOC[25] - // and corresponding Byte in file is then approximately at: - // (TOC[25]/256) * 5000000 - //116..119 VBR Scale - - - // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME -// if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') { - $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; - $thisfile_mpeg_audio['VBR_method'] = 'Xing'; -// } else { -// $ScanAsCBR = true; -// $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; -// } - - $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4)); - - $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001); - $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002); - $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004); - $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008); - - if ($thisfile_mpeg_audio['xing_flags']['frames']) { - $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4)); - //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame - } - if ($thisfile_mpeg_audio['xing_flags']['bytes']) { - $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4)); - } - - //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { - if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { - - $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']; - - if ($thisfile_mpeg_audio['layer'] == '1') { - // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 - //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12; - $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12; - } else { - // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 - //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; - $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144; - } - $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat); - } - - if ($thisfile_mpeg_audio['xing_flags']['toc']) { - $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100); - for ($i = 0; $i < 100; $i++) { - $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i}); - } - } - if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) { - $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4)); - } - - - // http://gabriel.mp3-tech.org/mp3infotag.html - if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') { - - // shortcut - $thisfile_mpeg_audio['LAME'] = array(); - $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; - - - $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20); - $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9); - - if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') { - - // extra 11 chars are not part of version string when LAMEtag present - unset($thisfile_mpeg_audio_lame['long_version']); - - // It the LAME tag was only introduced in LAME v3.90 - // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 - - // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html - // are assuming a 'Xing' identifier offset of 0x24, which is the case for - // MPEG-1 non-mono, but not for other combinations - $LAMEtagOffsetContant = $VBRidOffset - 0x24; - - // shortcuts - $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array()); - $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD']; - $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track']; - $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album']; - $thisfile_mpeg_audio_lame['raw'] = array(); - $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw']; - - // byte $9B VBR Quality - // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications. - // Actually overwrites original Xing bytes - unset($thisfile_mpeg_audio['VBR_scale']); - $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1)); - - // bytes $9C-$A4 Encoder short VersionString - $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9); - - // byte $A5 Info Tag revision + VBR method - $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1)); - - $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4; - $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F; - $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']); - $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr' - - // byte $A6 Lowpass filter value - $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; - - // bytes $A7-$AE Replay Gain - // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html - // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" - if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { - // LAME 3.94a16 and later - 9.23 fixed point - // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 - $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); - } else { - // LAME 3.94a15 and earlier - 32-bit floating point - // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15 - $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4)); - } - if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) { - unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); - } else { - $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); - } - - $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2)); - $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2)); - - - if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) { - - $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13; - $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10; - $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9; - $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF; - $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']); - $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']); - $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']); - - if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { - $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; - } - $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator']; - $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db']; - } else { - unset($thisfile_mpeg_audio_lame_RGAD['track']); - } - if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) { - - $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13; - $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10; - $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9; - $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF; - $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']); - $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']); - $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']); - - if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { - $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; - } - $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator']; - $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db']; - } else { - unset($thisfile_mpeg_audio_lame_RGAD['album']); - } - if (empty($thisfile_mpeg_audio_lame_RGAD)) { - unset($thisfile_mpeg_audio_lame['RGAD']); - } - - - // byte $AF Encoding flags + ATH Type - $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1)); - $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10); - $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20); - $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40); - $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80); - $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F; - - // byte $B0 if ABR {specified bitrate} else {minimal bitrate} - $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1)); - if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR) - $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; - } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR) - // ignore - } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate - $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; - } - - // bytes $B1-$B3 Encoder delays - $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3)); - $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12; - $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF; - - // byte $B4 Misc - $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1)); - $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03); - $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2; - $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5; - $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6; - $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping']; - $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']); - $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality']; - $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']); - - // byte $B5 MP3 Gain - $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true); - $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain']; - $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6)); - - // bytes $B6-$B7 Preset and surround info - $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2)); - // Reserved = ($PresetSurroundBytes & 0xC000); - $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800); - $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']); - $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF); - $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame); - if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) { - $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org'; - } - if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) { - // this may change if 3.90.4 ever comes out - $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3'; - } - - // bytes $B8-$BB MusicLength - $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4)); - $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']); - - // bytes $BC-$BD MusicCRC - $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2)); - - // bytes $BE-$BF CRC-16 of Info Tag - $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2)); - - - // LAME CBR - if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { - - $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; - $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); - $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; - //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) { - // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min']; - //} - - } - - } - } - - } else { - - // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header) - $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; - if ($recursivesearch) { - $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; - if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) { - $recursivesearch = false; - $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; - } - if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') { - $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.'; - } - } - - } - - } - - if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) { - if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) { - if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) { - // ignore, audio data is broken into chunks so will always be data "missing" - } elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) { - $info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)'; - } else { - $info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)'; - } - } else { - if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) { - // $prenullbytefileoffset = ftell($this->getid3->fp); - // fseek($this->getid3->fp, $info['avdataend'], SEEK_SET); - // $PossibleNullByte = fread($this->getid3->fp, 1); - // fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET); - // if ($PossibleNullByte === "\x00") { - $info['avdataend']--; - // $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'; - // } else { - // $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'; - // } - } else { - $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'; - } - } - } - - if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) { - if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) { - $framebytelength = $this->FreeFormatFrameLength($offset, true); - if ($framebytelength > 0) { - $thisfile_mpeg_audio['framelength'] = $framebytelength; - if ($thisfile_mpeg_audio['layer'] == '1') { - // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 - $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12; - } else { - // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 - $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; - } - } else { - $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header'; - } - } - } - - if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') { - switch ($thisfile_mpeg_audio['bitrate_mode']) { - case 'vbr': - case 'abr': - $bytes_per_frame = 1152; - if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) { - $bytes_per_frame = 384; - } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) { - $bytes_per_frame = 576; - } - $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0); - if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) { - $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; - $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion - } - break; - } - } - - // End variable-bitrate headers - //////////////////////////////////////////////////////////////////////////////////// - - if ($recursivesearch) { - - if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) { - return false; - } - - } - - - //if (false) { - // // experimental side info parsing section - not returning anything useful yet - // - // $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData); - // $SideInfoOffset = 0; - // - // if ($thisfile_mpeg_audio['version'] == '1') { - // if ($thisfile_mpeg_audio['channelmode'] == 'mono') { - // // MPEG-1 (mono) - // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9); - // $SideInfoOffset += 9; - // $SideInfoOffset += 5; - // } else { - // // MPEG-1 (stereo, joint-stereo, dual-channel) - // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9); - // $SideInfoOffset += 9; - // $SideInfoOffset += 3; - // } - // } else { // 2 or 2.5 - // if ($thisfile_mpeg_audio['channelmode'] == 'mono') { - // // MPEG-2, MPEG-2.5 (mono) - // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8); - // $SideInfoOffset += 8; - // $SideInfoOffset += 1; - // } else { - // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel) - // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8); - // $SideInfoOffset += 8; - // $SideInfoOffset += 2; - // } - // } - // - // if ($thisfile_mpeg_audio['version'] == '1') { - // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) { - // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) { - // $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 2; - // } - // } - // } - // for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) { - // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) { - // $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12); - // $SideInfoOffset += 12; - // $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9); - // $SideInfoOffset += 9; - // $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8); - // $SideInfoOffset += 8; - // if ($thisfile_mpeg_audio['version'] == '1') { - // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4); - // $SideInfoOffset += 4; - // } else { - // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9); - // $SideInfoOffset += 9; - // } - // $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 1; - // - // if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') { - // - // $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2); - // $SideInfoOffset += 2; - // $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 1; - // - // for ($region = 0; $region < 2; $region++) { - // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5); - // $SideInfoOffset += 5; - // } - // $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0; - // - // for ($window = 0; $window < 3; $window++) { - // $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3); - // $SideInfoOffset += 3; - // } - // - // } else { - // - // for ($region = 0; $region < 3; $region++) { - // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5); - // $SideInfoOffset += 5; - // } - // - // $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4); - // $SideInfoOffset += 4; - // $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3); - // $SideInfoOffset += 3; - // $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0; - // } - // - // if ($thisfile_mpeg_audio['version'] == '1') { - // $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 1; - // } - // $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 1; - // $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); - // $SideInfoOffset += 1; - // } - // } - //} - - return true; - } - - public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) { - $info = &$this->getid3->info; - $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); - $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false); - - for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) { - // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch - if (($nextframetestoffset + 4) >= $info['avdataend']) { - // end of file - return true; - } - - $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); - if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { - if ($ScanAsCBR) { - // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header - if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { - return false; - } - } - - - // next frame is OK, get ready to check the one after that - if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) { - $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength']; - } else { - $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.'; - return false; - } - - } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) { - - // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK - return true; - - } else { - - // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence - $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.'; - - return false; - } - } - return true; - } - - public function FreeFormatFrameLength($offset, $deepscan=false) { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $offset, SEEK_SET); - $MPEGaudioData = fread($this->getid3->fp, 32768); - - $SyncPattern1 = substr($MPEGaudioData, 0, 4); - // may be different pattern due to padding - $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3}; - if ($SyncPattern2 === $SyncPattern1) { - $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3}; - } - - $framelength = false; - $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4); - $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4); - if ($framelength1 > 4) { - $framelength = $framelength1; - } - if (($framelength2 > 4) && ($framelength2 < $framelength1)) { - $framelength = $framelength2; - } - if (!$framelength) { - - // LAME 3.88 has a different value for modeextension on the first frame vs the rest - $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4); - $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4); - - if ($framelength1 > 4) { - $framelength = $framelength1; - } - if (($framelength2 > 4) && ($framelength2 < $framelength1)) { - $framelength = $framelength2; - } - if (!$framelength) { - $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset; - return false; - } else { - $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)'; - $info['audio']['codec'] = 'LAME'; - $info['audio']['encoder'] = 'LAME3.88'; - $SyncPattern1 = substr($SyncPattern1, 0, 3); - $SyncPattern2 = substr($SyncPattern2, 0, 3); - } - } - - if ($deepscan) { - - $ActualFrameLengthValues = array(); - $nextoffset = $offset + $framelength; - while ($nextoffset < ($info['avdataend'] - 6)) { - fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET); - $NextSyncPattern = fread($this->getid3->fp, 6); - if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) { - // good - found where expected - $ActualFrameLengthValues[] = $framelength; - } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) { - // ok - found one byte earlier than expected (last frame wasn't padded, first frame was) - $ActualFrameLengthValues[] = ($framelength - 1); - $nextoffset--; - } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) { - // ok - found one byte later than expected (last frame was padded, first frame wasn't) - $ActualFrameLengthValues[] = ($framelength + 1); - $nextoffset++; - } else { - $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset; - return false; - } - $nextoffset += $framelength; - } - if (count($ActualFrameLengthValues) > 0) { - $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues))); - } - } - return $framelength; - } - - public function getOnlyMPEGaudioInfoBruteForce() { - $MPEGaudioHeaderDecodeCache = array(); - $MPEGaudioHeaderValidCache = array(); - $MPEGaudioHeaderLengthCache = array(); - $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); - $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); - $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); - $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); - $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); - $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); - $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); - $LongMPEGversionLookup = array(); - $LongMPEGlayerLookup = array(); - $LongMPEGbitrateLookup = array(); - $LongMPEGpaddingLookup = array(); - $LongMPEGfrequencyLookup = array(); - $Distribution['bitrate'] = array(); - $Distribution['frequency'] = array(); - $Distribution['layer'] = array(); - $Distribution['version'] = array(); - $Distribution['padding'] = array(); - - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $max_frames_scan = 5000; - $frames_scanned = 0; - - $previousvalidframe = $info['avdataoffset']; - while (ftell($this->getid3->fp) < $info['avdataend']) { - set_time_limit(30); - $head4 = fread($this->getid3->fp, 4); - if (strlen($head4) < 4) { - break; - } - if ($head4{0} != "\xFF") { - for ($i = 1; $i < 4; $i++) { - if ($head4{$i} == "\xFF") { - fseek($this->getid3->fp, $i - 4, SEEK_CUR); - continue 2; - } - } - continue; - } - if (!isset($MPEGaudioHeaderDecodeCache[$head4])) { - $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4); - } - if (!isset($MPEGaudioHeaderValidCache[$head4])) { - $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false); - } - if ($MPEGaudioHeaderValidCache[$head4]) { - - if (!isset($MPEGaudioHeaderLengthCache[$head4])) { - $LongMPEGversionLookup[$head4] = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']]; - $LongMPEGlayerLookup[$head4] = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']]; - $LongMPEGbitrateLookup[$head4] = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']]; - $LongMPEGpaddingLookup[$head4] = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding']; - $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']]; - $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength( - $LongMPEGbitrateLookup[$head4], - $LongMPEGversionLookup[$head4], - $LongMPEGlayerLookup[$head4], - $LongMPEGpaddingLookup[$head4], - $LongMPEGfrequencyLookup[$head4]); - } - if ($MPEGaudioHeaderLengthCache[$head4] > 4) { - $WhereWeWere = ftell($this->getid3->fp); - fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR); - $next4 = fread($this->getid3->fp, 4); - if ($next4{0} == "\xFF") { - if (!isset($MPEGaudioHeaderDecodeCache[$next4])) { - $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4); - } - if (!isset($MPEGaudioHeaderValidCache[$next4])) { - $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false); - } - if ($MPEGaudioHeaderValidCache[$next4]) { - fseek($this->getid3->fp, -4, SEEK_CUR); - - getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]); - getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]); - getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]); - getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]); - getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]); - if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) { - $pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); - $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'; - foreach ($Distribution as $key1 => $value1) { - foreach ($value1 as $key2 => $value2) { - $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); - } - } - break; - } - continue; - } - } - unset($next4); - fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET); - } - - } - } - foreach ($Distribution as $key => $value) { - ksort($Distribution[$key], SORT_NUMERIC); - } - ksort($Distribution['version'], SORT_STRING); - $info['mpeg']['audio']['bitrate_distribution'] = $Distribution['bitrate']; - $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency']; - $info['mpeg']['audio']['layer_distribution'] = $Distribution['layer']; - $info['mpeg']['audio']['version_distribution'] = $Distribution['version']; - $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding']; - if (count($Distribution['version']) > 1) { - $info['error'][] = 'Corrupt file - more than one MPEG version detected'; - } - if (count($Distribution['layer']) > 1) { - $info['error'][] = 'Corrupt file - more than one MPEG layer detected'; - } - if (count($Distribution['frequency']) > 1) { - $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected'; - } - - - $bittotal = 0; - foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) { - if ($bitratevalue != 'free') { - $bittotal += ($bitratevalue * $bitratecount); - } - } - $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']); - if ($info['mpeg']['audio']['frame_count'] == 0) { - $info['error'][] = 'no MPEG audio frames found'; - return false; - } - $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']); - $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr'); - $info['mpeg']['audio']['sample_rate'] = getid3_lib::array_max($Distribution['frequency'], true); - - $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; - $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode']; - $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; - $info['audio']['dataformat'] = 'mp'.getid3_lib::array_max($Distribution['layer'], true); - $info['fileformat'] = $info['audio']['dataformat']; - - return true; - } - - - public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { - // looks for synch, decodes MPEG audio header - - $info = &$this->getid3->info; - - static $MPEGaudioVersionLookup; - static $MPEGaudioLayerLookup; - static $MPEGaudioBitrateLookup; - if (empty($MPEGaudioVersionLookup)) { - $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); - $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); - $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); - - } - - fseek($this->getid3->fp, $avdataoffset, SEEK_SET); - $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset); - if ($sync_seek_buffer_size <= 0) { - $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset; - return false; - } - $header = fread($this->getid3->fp, $sync_seek_buffer_size); - $sync_seek_buffer_size = strlen($header); - $SynchSeekOffset = 0; - while ($SynchSeekOffset < $sync_seek_buffer_size) { - if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { - - if ($SynchSeekOffset > $sync_seek_buffer_size) { - // if a synch's not found within the first 128k bytes, then give up - $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB'; - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (empty($info['mpeg'])) { - unset($info['mpeg']); - } - return false; - - } elseif (feof($this->getid3->fp)) { - - $info['error'][] = 'Could not find valid MPEG audio synch before end of file'; - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { - unset($info['mpeg']); - } - return false; - } - } - - if (($SynchSeekOffset + 1) >= strlen($header)) { - $info['error'][] = 'Could not find valid MPEG synch before end of file'; - return false; - } - - if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected - if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { - $FirstFrameThisfileInfo = $info; - $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset; - if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) { - // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's - // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below - unset($FirstFrameThisfileInfo); - } - } - - $dummy = $info; // only overwrite real data if valid header found - if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) { - $info = $dummy; - $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset; - switch (isset($info['fileformat']) ? $info['fileformat'] : '') { - case '': - case 'id3': - case 'ape': - case 'mp3': - $info['fileformat'] = 'mp3'; - $info['audio']['dataformat'] = 'mp3'; - break; - } - if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) { - if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) { - // If there is garbage data between a valid VBR header frame and a sequence - // of valid MPEG-audio frames the VBR data is no longer discarded. - $info = $FirstFrameThisfileInfo; - $info['avdataoffset'] = $FirstFrameAVDataOffset; - $info['fileformat'] = 'mp3'; - $info['audio']['dataformat'] = 'mp3'; - $dummy = $info; - unset($dummy['mpeg']['audio']); - $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength']; - $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset; - if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) { - $info = $dummy; - $info['avdataoffset'] = $GarbageOffsetEnd; - $info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd; - } else { - $info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')'; - } - } - } - if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) { - // VBR file with no VBR header - $BitrateHistogram = true; - } - - if ($BitrateHistogram) { - - $info['mpeg']['audio']['stereo_distribution'] = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0); - $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0); - - if ($info['mpeg']['audio']['version'] == '1') { - if ($info['mpeg']['audio']['layer'] == 3) { - $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0); - } elseif ($info['mpeg']['audio']['layer'] == 2) { - $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0); - } elseif ($info['mpeg']['audio']['layer'] == 1) { - $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0); - } - } elseif ($info['mpeg']['audio']['layer'] == 1) { - $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0); - } else { - $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0); - } - - $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); - $synchstartoffset = $info['avdataoffset']; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - // you can play with these numbers: - $max_frames_scan = 50000; - $max_scan_segments = 10; - - // don't play with these numbers: - $FastMode = false; - $SynchErrorsFound = 0; - $frames_scanned = 0; - $this_scan_segment = 0; - $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments); - $pct_data_scanned = 0; - for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) { - $frames_scanned_this_segment = 0; - if (ftell($this->getid3->fp) >= $info['avdataend']) { - break; - } - $scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments))); - if ($current_segment > 0) { - fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET); - $buffer_4k = fread($this->getid3->fp, 4096); - for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) { - if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected - if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) { - $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength']; - if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) { - $scan_start_offset[$current_segment] += $j; - break; - } - } - } - } - } - $synchstartoffset = $scan_start_offset[$current_segment]; - while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) { - $FastMode = true; - $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']]; - - if (empty($dummy['mpeg']['audio']['framelength'])) { - $SynchErrorsFound++; - $synchstartoffset++; - } else { - getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]); - getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]); - getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]); - $synchstartoffset += $dummy['mpeg']['audio']['framelength']; - } - $frames_scanned++; - if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { - $this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); - if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { - // file likely contains < $max_frames_scan, just scan as one segment - $max_scan_segments = 1; - $frames_scan_per_segment = $max_frames_scan; - } else { - $pct_data_scanned += $this_pct_scanned; - break; - } - } - } - } - if ($pct_data_scanned > 0) { - $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'; - foreach ($info['mpeg']['audio'] as $key1 => $value1) { - if (!preg_match('#_distribution$#i', $key1)) { - continue; - } - foreach ($value1 as $key2 => $value2) { - $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned); - } - } - } - - if ($SynchErrorsFound > 0) { - $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis'; - //return false; - } - - $bittotal = 0; - $framecounter = 0; - foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) { - $framecounter += $bitratecount; - if ($bitratevalue != 'free') { - $bittotal += ($bitratevalue * $bitratecount); - } - } - if ($framecounter == 0) { - $info['error'][] = 'Corrupt MP3 file: framecounter == zero'; - return false; - } - $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter); - $info['mpeg']['audio']['bitrate'] = ($bittotal / $framecounter); - - $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; - - - // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently - $distinct_bitrates = 0; - foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) { - if ($bitrate_count > 0) { - $distinct_bitrates++; - } - } - if ($distinct_bitrates > 1) { - $info['mpeg']['audio']['bitrate_mode'] = 'vbr'; - } else { - $info['mpeg']['audio']['bitrate_mode'] = 'cbr'; - } - $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode']; - - } - - break; // exit while() - } - } - - $SynchSeekOffset++; - if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) { - // end of file/data - - if (empty($info['mpeg']['audio'])) { - - $info['error'][] = 'could not find valid MPEG synch before end of file'; - if (isset($info['audio']['bitrate'])) { - unset($info['audio']['bitrate']); - } - if (isset($info['mpeg']['audio'])) { - unset($info['mpeg']['audio']); - } - if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) { - unset($info['mpeg']); - } - return false; - - } - break; - } - - } - $info['audio']['channels'] = $info['mpeg']['audio']['channels']; - $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; - $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; - return true; - } - - - public static function MPEGaudioVersionArray() { - static $MPEGaudioVersion = array('2.5', false, '2', '1'); - return $MPEGaudioVersion; - } - - public static function MPEGaudioLayerArray() { - static $MPEGaudioLayer = array(false, 3, 2, 1); - return $MPEGaudioLayer; - } - - public static function MPEGaudioBitrateArray() { - static $MPEGaudioBitrate; - if (empty($MPEGaudioBitrate)) { - $MPEGaudioBitrate = array ( - '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), - 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), - 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000) - ), - - '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000), - 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000), - ) - ); - $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2]; - $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2']; - } - return $MPEGaudioBitrate; - } - - public static function MPEGaudioFrequencyArray() { - static $MPEGaudioFrequency; - if (empty($MPEGaudioFrequency)) { - $MPEGaudioFrequency = array ( - '1' => array(44100, 48000, 32000), - '2' => array(22050, 24000, 16000), - '2.5' => array(11025, 12000, 8000) - ); - } - return $MPEGaudioFrequency; - } - - public static function MPEGaudioChannelModeArray() { - static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono'); - return $MPEGaudioChannelMode; - } - - public static function MPEGaudioModeExtensionArray() { - static $MPEGaudioModeExtension; - if (empty($MPEGaudioModeExtension)) { - $MPEGaudioModeExtension = array ( - 1 => array('4-31', '8-31', '12-31', '16-31'), - 2 => array('4-31', '8-31', '12-31', '16-31'), - 3 => array('', 'IS', 'MS', 'IS+MS') - ); - } - return $MPEGaudioModeExtension; - } - - public static function MPEGaudioEmphasisArray() { - static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17'); - return $MPEGaudioEmphasis; - } - - public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) { - return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15); - } - - public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) { - if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) { - return false; - } - - static $MPEGaudioVersionLookup; - static $MPEGaudioLayerLookup; - static $MPEGaudioBitrateLookup; - static $MPEGaudioFrequencyLookup; - static $MPEGaudioChannelModeLookup; - static $MPEGaudioModeExtensionLookup; - static $MPEGaudioEmphasisLookup; - if (empty($MPEGaudioVersionLookup)) { - $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); - $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); - $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); - $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); - $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); - $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); - $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); - } - - if (isset($MPEGaudioVersionLookup[$rawarray['version']])) { - $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']]; - } else { - echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : ''); - return false; - } - if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) { - $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']]; - } else { - echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : ''); - return false; - } - if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) { - echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : ''); - if ($rawarray['bitrate'] == 15) { - // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0 - // let it go through here otherwise file will not be identified - if (!$allowBitrate15) { - return false; - } - } else { - return false; - } - } - if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) { - echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : ''); - return false; - } - if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) { - echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : ''); - return false; - } - if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) { - echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : ''); - return false; - } - if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) { - echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : ''); - return false; - } - // These are just either set or not set, you can't mess that up :) - // $rawarray['protection']; - // $rawarray['padding']; - // $rawarray['private']; - // $rawarray['copyright']; - // $rawarray['original']; - - return true; - } - - public static function MPEGaudioHeaderDecode($Header4Bytes) { - // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM - // A - Frame sync (all bits set) - // B - MPEG Audio version ID - // C - Layer description - // D - Protection bit - // E - Bitrate index - // F - Sampling rate frequency index - // G - Padding bit - // H - Private bit - // I - Channel Mode - // J - Mode extension (Only if Joint stereo) - // K - Copyright - // L - Original - // M - Emphasis - - if (strlen($Header4Bytes) != 4) { - return false; - } - - $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; - $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB - $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC - $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D - $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE - $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF - $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G - $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H - $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II - $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ - $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K - $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L - $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM - - return $MPEGrawHeader; - } - - public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) { - static $AudioFrameLengthCache = array(); - - if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) { - $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false; - if ($bitrate != 'free') { - - if ($version == '1') { - - if ($layer == '1') { - - // For Layer I slot is 32 bits long - $FrameLengthCoefficient = 48; - $SlotLength = 4; - - } else { // Layer 2 / 3 - - // for Layer 2 and Layer 3 slot is 8 bits long. - $FrameLengthCoefficient = 144; - $SlotLength = 1; - - } - - } else { // MPEG-2 / MPEG-2.5 - - if ($layer == '1') { - - // For Layer I slot is 32 bits long - $FrameLengthCoefficient = 24; - $SlotLength = 4; - - } elseif ($layer == '2') { - - // for Layer 2 and Layer 3 slot is 8 bits long. - $FrameLengthCoefficient = 144; - $SlotLength = 1; - - } else { // layer 3 - - // for Layer 2 and Layer 3 slot is 8 bits long. - $FrameLengthCoefficient = 72; - $SlotLength = 1; - - } - - } - - // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding - if ($samplerate > 0) { - $NewFramelength = ($FrameLengthCoefficient * $bitrate) / $samplerate; - $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I) - if ($padding) { - $NewFramelength += $SlotLength; - } - $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength; - } - } - } - return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate]; - } - - public static function ClosestStandardMP3Bitrate($bit_rate) { - static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000); - static $bit_rate_table = array (0=>'-'); - $round_bit_rate = intval(round($bit_rate, -3)); - if (!isset($bit_rate_table[$round_bit_rate])) { - if ($round_bit_rate > max($standard_bit_rates)) { - $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate)); - } else { - $bit_rate_table[$round_bit_rate] = max($standard_bit_rates); - foreach ($standard_bit_rates as $standard_bit_rate) { - if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) { - break; - } - $bit_rate_table[$round_bit_rate] = $standard_bit_rate; - } - } - } - return $bit_rate_table[$round_bit_rate]; - } - - public static function XingVBRidOffset($version, $channelmode) { - static $XingVBRidOffsetCache = array(); - if (empty($XingVBRidOffset)) { - $XingVBRidOffset = array ( - '1' => array ('mono' => 0x15, // 4 + 17 = 21 - 'stereo' => 0x24, // 4 + 32 = 36 - 'joint stereo' => 0x24, - 'dual channel' => 0x24 - ), - - '2' => array ('mono' => 0x0D, // 4 + 9 = 13 - 'stereo' => 0x15, // 4 + 17 = 21 - 'joint stereo' => 0x15, - 'dual channel' => 0x15 - ), - - '2.5' => array ('mono' => 0x15, - 'stereo' => 0x15, - 'joint stereo' => 0x15, - 'dual channel' => 0x15 - ) - ); - } - return $XingVBRidOffset[$version][$channelmode]; - } - - public static function LAMEvbrMethodLookup($VBRmethodID) { - static $LAMEvbrMethodLookup = array( - 0x00 => 'unknown', - 0x01 => 'cbr', - 0x02 => 'abr', - 0x03 => 'vbr-old / vbr-rh', - 0x04 => 'vbr-new / vbr-mtrh', - 0x05 => 'vbr-mt', - 0x06 => 'vbr (full vbr method 4)', - 0x08 => 'cbr (constant bitrate 2 pass)', - 0x09 => 'abr (2 pass)', - 0x0F => 'reserved' - ); - return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : ''); - } - - public static function LAMEmiscStereoModeLookup($StereoModeID) { - static $LAMEmiscStereoModeLookup = array( - 0 => 'mono', - 1 => 'stereo', - 2 => 'dual mono', - 3 => 'joint stereo', - 4 => 'forced stereo', - 5 => 'auto', - 6 => 'intensity stereo', - 7 => 'other' - ); - return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : ''); - } - - public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) { - static $LAMEmiscSourceSampleFrequencyLookup = array( - 0 => '<= 32 kHz', - 1 => '44.1 kHz', - 2 => '48 kHz', - 3 => '> 48kHz' - ); - return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : ''); - } - - public static function LAMEsurroundInfoLookup($SurroundInfoID) { - static $LAMEsurroundInfoLookup = array( - 0 => 'no surround info', - 1 => 'DPL encoding', - 2 => 'DPL2 encoding', - 3 => 'Ambisonic encoding' - ); - return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved'); - } - - public static function LAMEpresetUsedLookup($LAMEtag) { - - if ($LAMEtag['preset_used_id'] == 0) { - // no preset used (LAME >=3.93) - // no preset recorded (LAME <3.93) - return ''; - } - $LAMEpresetUsedLookup = array(); - - ///// THIS PART CANNOT BE STATIC . - for ($i = 8; $i <= 320; $i++) { - switch ($LAMEtag['vbr_method']) { - case 'cbr': - $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i; - break; - case 'abr': - default: // other VBR modes shouldn't be here(?) - $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i; - break; - } - } - - // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions() - - // named alt-presets - $LAMEpresetUsedLookup[1000] = '--r3mix'; - $LAMEpresetUsedLookup[1001] = '--alt-preset standard'; - $LAMEpresetUsedLookup[1002] = '--alt-preset extreme'; - $LAMEpresetUsedLookup[1003] = '--alt-preset insane'; - $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard'; - $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme'; - $LAMEpresetUsedLookup[1006] = '--alt-preset medium'; - $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium'; - - // LAME 3.94 additions/changes - $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003 - $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003 - - $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003 - $LAMEpresetUsedLookup[410] = '-V9'; - $LAMEpresetUsedLookup[420] = '-V8'; - $LAMEpresetUsedLookup[440] = '-V6'; - $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003 - $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003 - $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003 - $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003 - $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003 - $LAMEpresetUsedLookup[490] = '-V1'; - $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003 - - return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org'); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.mp3.php // +// module for analyzing MP3 files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +// number of frames to scan to determine if MPEG-audio sequence is valid +// Lower this number to 5-20 for faster scanning +// Increase this number to 50+ for most accurate detection of valid VBR/CBR +// mpeg-audio streams +define('GETID3_MP3_VALID_CHECK_FRAMES', 35); + + +class getid3_mp3 extends getid3_handler +{ + + public $allow_bruteforce = false; // forces getID3() to scan the file byte-by-byte and log all the valid audio frame headers - extremely slow, unrecommended, but may provide data from otherwise-unusuable files + + public function Analyze() { + $info = &$this->getid3->info; + + $initialOffset = $info['avdataoffset']; + + if (!$this->getOnlyMPEGaudioInfo($info['avdataoffset'])) { + if ($this->allow_bruteforce) { + $info['error'][] = 'Rescanning file in BruteForce mode'; + $this->getOnlyMPEGaudioInfoBruteForce($this->getid3->fp, $info); + } + } + + + if (isset($info['mpeg']['audio']['bitrate_mode'])) { + $info['audio']['bitrate_mode'] = strtolower($info['mpeg']['audio']['bitrate_mode']); + } + + if (((isset($info['id3v2']['headerlength']) && ($info['avdataoffset'] > $info['id3v2']['headerlength'])) || (!isset($info['id3v2']) && ($info['avdataoffset'] > 0) && ($info['avdataoffset'] != $initialOffset)))) { + + $synchoffsetwarning = 'Unknown data before synch '; + if (isset($info['id3v2']['headerlength'])) { + $synchoffsetwarning .= '(ID3v2 header ends at '.$info['id3v2']['headerlength'].', then '.($info['avdataoffset'] - $info['id3v2']['headerlength']).' bytes garbage, '; + } elseif ($initialOffset > 0) { + $synchoffsetwarning .= '(should be at '.$initialOffset.', '; + } else { + $synchoffsetwarning .= '(should be at beginning of file, '; + } + $synchoffsetwarning .= 'synch detected at '.$info['avdataoffset'].')'; + if (isset($info['audio']['bitrate_mode']) && ($info['audio']['bitrate_mode'] == 'cbr')) { + + if (!empty($info['id3v2']['headerlength']) && (($info['avdataoffset'] - $info['id3v2']['headerlength']) == $info['mpeg']['audio']['framelength'])) { + + $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90-3.92) DLL in CBR mode.'; + $info['audio']['codec'] = 'LAME'; + $CurrentDataLAMEversionString = 'LAME3.'; + + } elseif (empty($info['id3v2']['headerlength']) && ($info['avdataoffset'] == $info['mpeg']['audio']['framelength'])) { + + $synchoffsetwarning .= '. This is a known problem with some versions of LAME (3.90 - 3.92) DLL in CBR mode.'; + $info['audio']['codec'] = 'LAME'; + $CurrentDataLAMEversionString = 'LAME3.'; + + } + + } + $info['warning'][] = $synchoffsetwarning; + + } + + if (isset($info['mpeg']['audio']['LAME'])) { + $info['audio']['codec'] = 'LAME'; + if (!empty($info['mpeg']['audio']['LAME']['long_version'])) { + $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['long_version'], "\x00"); + } elseif (!empty($info['mpeg']['audio']['LAME']['short_version'])) { + $info['audio']['encoder'] = rtrim($info['mpeg']['audio']['LAME']['short_version'], "\x00"); + } + } + + $CurrentDataLAMEversionString = (!empty($CurrentDataLAMEversionString) ? $CurrentDataLAMEversionString : (isset($info['audio']['encoder']) ? $info['audio']['encoder'] : '')); + if (!empty($CurrentDataLAMEversionString) && (substr($CurrentDataLAMEversionString, 0, 6) == 'LAME3.') && !preg_match('[0-9\)]', substr($CurrentDataLAMEversionString, -1))) { + // a version number of LAME that does not end with a number like "LAME3.92" + // or with a closing parenthesis like "LAME3.88 (alpha)" + // or a version of LAME with the LAMEtag-not-filled-in-DLL-mode bug (3.90-3.92) + + // not sure what the actual last frame length will be, but will be less than or equal to 1441 + $PossiblyLongerLAMEversion_FrameLength = 1441; + + // Not sure what version of LAME this is - look in padding of last frame for longer version string + $PossibleLAMEversionStringOffset = $info['avdataend'] - $PossiblyLongerLAMEversion_FrameLength; + fseek($this->getid3->fp, $PossibleLAMEversionStringOffset); + $PossiblyLongerLAMEversion_Data = fread($this->getid3->fp, $PossiblyLongerLAMEversion_FrameLength); + switch (substr($CurrentDataLAMEversionString, -1)) { + case 'a': + case 'b': + // "LAME3.94a" will have a longer version string of "LAME3.94 (alpha)" for example + // need to trim off "a" to match longer string + $CurrentDataLAMEversionString = substr($CurrentDataLAMEversionString, 0, -1); + break; + } + if (($PossiblyLongerLAMEversion_String = strstr($PossiblyLongerLAMEversion_Data, $CurrentDataLAMEversionString)) !== false) { + if (substr($PossiblyLongerLAMEversion_String, 0, strlen($CurrentDataLAMEversionString)) == $CurrentDataLAMEversionString) { + $PossiblyLongerLAMEversion_NewString = substr($PossiblyLongerLAMEversion_String, 0, strspn($PossiblyLongerLAMEversion_String, 'LAME0123456789., (abcdefghijklmnopqrstuvwxyzJFSOND)')); //"LAME3.90.3" "LAME3.87 (beta 1, Sep 27 2000)" "LAME3.88 (beta)" + if (empty($info['audio']['encoder']) || (strlen($PossiblyLongerLAMEversion_NewString) > strlen($info['audio']['encoder']))) { + $info['audio']['encoder'] = $PossiblyLongerLAMEversion_NewString; + } + } + } + } + if (!empty($info['audio']['encoder'])) { + $info['audio']['encoder'] = rtrim($info['audio']['encoder'], "\x00 "); + } + + switch (isset($info['mpeg']['audio']['layer']) ? $info['mpeg']['audio']['layer'] : '') { + case 1: + case 2: + $info['audio']['dataformat'] = 'mp'.$info['mpeg']['audio']['layer']; + break; + } + if (isset($info['fileformat']) && ($info['fileformat'] == 'mp3')) { + switch ($info['audio']['dataformat']) { + case 'mp1': + case 'mp2': + case 'mp3': + $info['fileformat'] = $info['audio']['dataformat']; + break; + + default: + $info['warning'][] = 'Expecting [audio][dataformat] to be mp1/mp2/mp3 when fileformat == mp3, [audio][dataformat] actually "'.$info['audio']['dataformat'].'"'; + break; + } + } + + if (empty($info['fileformat'])) { + unset($info['fileformat']); + unset($info['audio']['bitrate_mode']); + unset($info['avdataoffset']); + unset($info['avdataend']); + return false; + } + + $info['mime_type'] = 'audio/mpeg'; + $info['audio']['lossless'] = false; + + // Calculate playtime + if (!isset($info['playtime_seconds']) && isset($info['audio']['bitrate']) && ($info['audio']['bitrate'] > 0)) { + $info['playtime_seconds'] = ($info['avdataend'] - $info['avdataoffset']) * 8 / $info['audio']['bitrate']; + } + + $info['audio']['encoder_options'] = $this->GuessEncoderOptions(); + + return true; + } + + + public function GuessEncoderOptions() { + // shortcuts + $info = &$this->getid3->info; + if (!empty($info['mpeg']['audio'])) { + $thisfile_mpeg_audio = &$info['mpeg']['audio']; + if (!empty($thisfile_mpeg_audio['LAME'])) { + $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; + } + } + + $encoder_options = ''; + static $NamedPresetBitrates = array(16, 24, 40, 56, 112, 128, 160, 192, 256); + + if (isset($thisfile_mpeg_audio['VBR_method']) && ($thisfile_mpeg_audio['VBR_method'] == 'Fraunhofer') && !empty($thisfile_mpeg_audio['VBR_quality'])) { + + $encoder_options = 'VBR q'.$thisfile_mpeg_audio['VBR_quality']; + + } elseif (!empty($thisfile_mpeg_audio_lame['preset_used']) && (!in_array($thisfile_mpeg_audio_lame['preset_used_id'], $NamedPresetBitrates))) { + + $encoder_options = $thisfile_mpeg_audio_lame['preset_used']; + + } elseif (!empty($thisfile_mpeg_audio_lame['vbr_quality'])) { + + static $KnownEncoderValues = array(); + if (empty($KnownEncoderValues)) { + + //$KnownEncoderValues[abrbitrate_minbitrate][vbr_quality][raw_vbr_method][raw_noise_shaping][raw_stereo_mode][ath_type][lowpass_frequency] = 'preset name'; + $KnownEncoderValues[0xFF][58][1][1][3][2][20500] = '--alt-preset insane'; // 3.90, 3.90.1, 3.92 + $KnownEncoderValues[0xFF][58][1][1][3][2][20600] = '--alt-preset insane'; // 3.90.2, 3.90.3, 3.91 + $KnownEncoderValues[0xFF][57][1][1][3][4][20500] = '--alt-preset insane'; // 3.94, 3.95 + $KnownEncoderValues['**'][78][3][2][3][2][19500] = '--alt-preset extreme'; // 3.90, 3.90.1, 3.92 + $KnownEncoderValues['**'][78][3][2][3][2][19600] = '--alt-preset extreme'; // 3.90.2, 3.91 + $KnownEncoderValues['**'][78][3][1][3][2][19600] = '--alt-preset extreme'; // 3.90.3 + $KnownEncoderValues['**'][78][4][2][3][2][19500] = '--alt-preset fast extreme'; // 3.90, 3.90.1, 3.92 + $KnownEncoderValues['**'][78][4][2][3][2][19600] = '--alt-preset fast extreme'; // 3.90.2, 3.90.3, 3.91 + $KnownEncoderValues['**'][78][3][2][3][4][19000] = '--alt-preset standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues['**'][78][3][1][3][4][19000] = '--alt-preset standard'; // 3.90.3 + $KnownEncoderValues['**'][78][4][2][3][4][19000] = '--alt-preset fast standard'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues['**'][78][4][1][3][4][19000] = '--alt-preset fast standard'; // 3.90.3 + $KnownEncoderValues['**'][88][4][1][3][3][19500] = '--r3mix'; // 3.90, 3.90.1, 3.92 + $KnownEncoderValues['**'][88][4][1][3][3][19600] = '--r3mix'; // 3.90.2, 3.90.3, 3.91 + $KnownEncoderValues['**'][67][4][1][3][4][18000] = '--r3mix'; // 3.94, 3.95 + $KnownEncoderValues['**'][68][3][2][3][4][18000] = '--alt-preset medium'; // 3.90.3 + $KnownEncoderValues['**'][68][4][2][3][4][18000] = '--alt-preset fast medium'; // 3.90.3 + + $KnownEncoderValues[0xFF][99][1][1][1][2][0] = '--preset studio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0xFF][58][2][1][3][2][20600] = '--preset studio'; // 3.90.3, 3.93.1 + $KnownEncoderValues[0xFF][58][2][1][3][2][20500] = '--preset studio'; // 3.93 + $KnownEncoderValues[0xFF][57][2][1][3][4][20500] = '--preset studio'; // 3.94, 3.95 + $KnownEncoderValues[0xC0][88][1][1][1][2][0] = '--preset cd'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0xC0][58][2][2][3][2][19600] = '--preset cd'; // 3.90.3, 3.93.1 + $KnownEncoderValues[0xC0][58][2][2][3][2][19500] = '--preset cd'; // 3.93 + $KnownEncoderValues[0xC0][57][2][1][3][4][19500] = '--preset cd'; // 3.94, 3.95 + $KnownEncoderValues[0xA0][78][1][1][3][2][18000] = '--preset hifi'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0xA0][58][2][2][3][2][18000] = '--preset hifi'; // 3.90.3, 3.93, 3.93.1 + $KnownEncoderValues[0xA0][57][2][1][3][4][18000] = '--preset hifi'; // 3.94, 3.95 + $KnownEncoderValues[0x80][67][1][1][3][2][18000] = '--preset tape'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0x80][67][1][1][3][2][15000] = '--preset radio'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0x70][67][1][1][3][2][15000] = '--preset fm'; // 3.90, 3.90.1, 3.90.2, 3.91, 3.92 + $KnownEncoderValues[0x70][58][2][2][3][2][16000] = '--preset tape/radio/fm'; // 3.90.3, 3.93, 3.93.1 + $KnownEncoderValues[0x70][57][2][1][3][4][16000] = '--preset tape/radio/fm'; // 3.94, 3.95 + $KnownEncoderValues[0x38][58][2][2][0][2][10000] = '--preset voice'; // 3.90.3, 3.93, 3.93.1 + $KnownEncoderValues[0x38][57][2][1][0][4][15000] = '--preset voice'; // 3.94, 3.95 + $KnownEncoderValues[0x38][57][2][1][0][4][16000] = '--preset voice'; // 3.94a14 + $KnownEncoderValues[0x28][65][1][1][0][2][7500] = '--preset mw-us'; // 3.90, 3.90.1, 3.92 + $KnownEncoderValues[0x28][65][1][1][0][2][7600] = '--preset mw-us'; // 3.90.2, 3.91 + $KnownEncoderValues[0x28][58][2][2][0][2][7000] = '--preset mw-us'; // 3.90.3, 3.93, 3.93.1 + $KnownEncoderValues[0x28][57][2][1][0][4][10500] = '--preset mw-us'; // 3.94, 3.95 + $KnownEncoderValues[0x28][57][2][1][0][4][11200] = '--preset mw-us'; // 3.94a14 + $KnownEncoderValues[0x28][57][2][1][0][4][8800] = '--preset mw-us'; // 3.94a15 + $KnownEncoderValues[0x18][58][2][2][0][2][4000] = '--preset phon+/lw/mw-eu/sw'; // 3.90.3, 3.93.1 + $KnownEncoderValues[0x18][58][2][2][0][2][3900] = '--preset phon+/lw/mw-eu/sw'; // 3.93 + $KnownEncoderValues[0x18][57][2][1][0][4][5900] = '--preset phon+/lw/mw-eu/sw'; // 3.94, 3.95 + $KnownEncoderValues[0x18][57][2][1][0][4][6200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a14 + $KnownEncoderValues[0x18][57][2][1][0][4][3200] = '--preset phon+/lw/mw-eu/sw'; // 3.94a15 + $KnownEncoderValues[0x10][58][2][2][0][2][3800] = '--preset phone'; // 3.90.3, 3.93.1 + $KnownEncoderValues[0x10][58][2][2][0][2][3700] = '--preset phone'; // 3.93 + $KnownEncoderValues[0x10][57][2][1][0][4][5600] = '--preset phone'; // 3.94, 3.95 + } + + if (isset($KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { + + $encoder_options = $KnownEncoderValues[$thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; + + } elseif (isset($KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']])) { + + $encoder_options = $KnownEncoderValues['**'][$thisfile_mpeg_audio_lame['vbr_quality']][$thisfile_mpeg_audio_lame['raw']['vbr_method']][$thisfile_mpeg_audio_lame['raw']['noise_shaping']][$thisfile_mpeg_audio_lame['raw']['stereo_mode']][$thisfile_mpeg_audio_lame['ath_type']][$thisfile_mpeg_audio_lame['lowpass_frequency']]; + + } elseif ($info['audio']['bitrate_mode'] == 'vbr') { + + // http://gabriel.mp3-tech.org/mp3infotag.html + // int Quality = (100 - 10 * gfp->VBR_q - gfp->quality)h + + + $LAME_V_value = 10 - ceil($thisfile_mpeg_audio_lame['vbr_quality'] / 10); + $LAME_q_value = 100 - $thisfile_mpeg_audio_lame['vbr_quality'] - ($LAME_V_value * 10); + $encoder_options = '-V'.$LAME_V_value.' -q'.$LAME_q_value; + + } elseif ($info['audio']['bitrate_mode'] == 'cbr') { + + $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + + } else { + + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + + } + + } elseif (!empty($thisfile_mpeg_audio_lame['bitrate_abr'])) { + + $encoder_options = 'ABR'.$thisfile_mpeg_audio_lame['bitrate_abr']; + + } elseif (!empty($info['audio']['bitrate'])) { + + if ($info['audio']['bitrate_mode'] == 'cbr') { + $encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + } else { + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + } + + } + if (!empty($thisfile_mpeg_audio_lame['bitrate_min'])) { + $encoder_options .= ' -b'.$thisfile_mpeg_audio_lame['bitrate_min']; + } + + if (!empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev']) || !empty($thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'])) { + $encoder_options .= ' --nogap'; + } + + if (!empty($thisfile_mpeg_audio_lame['lowpass_frequency'])) { + $ExplodedOptions = explode(' ', $encoder_options, 4); + if ($ExplodedOptions[0] == '--r3mix') { + $ExplodedOptions[1] = 'r3mix'; + } + switch ($ExplodedOptions[0]) { + case '--preset': + case '--alt-preset': + case '--r3mix': + if ($ExplodedOptions[1] == 'fast') { + $ExplodedOptions[1] .= ' '.$ExplodedOptions[2]; + } + switch ($ExplodedOptions[1]) { + case 'portable': + case 'medium': + case 'standard': + case 'extreme': + case 'insane': + case 'fast portable': + case 'fast medium': + case 'fast standard': + case 'fast extreme': + case 'fast insane': + case 'r3mix': + static $ExpectedLowpass = array( + 'insane|20500' => 20500, + 'insane|20600' => 20600, // 3.90.2, 3.90.3, 3.91 + 'medium|18000' => 18000, + 'fast medium|18000' => 18000, + 'extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 + 'extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 + 'fast extreme|19500' => 19500, // 3.90, 3.90.1, 3.92, 3.95 + 'fast extreme|19600' => 19600, // 3.90.2, 3.90.3, 3.91, 3.93.1 + 'standard|19000' => 19000, + 'fast standard|19000' => 19000, + 'r3mix|19500' => 19500, // 3.90, 3.90.1, 3.92 + 'r3mix|19600' => 19600, // 3.90.2, 3.90.3, 3.91 + 'r3mix|18000' => 18000, // 3.94, 3.95 + ); + if (!isset($ExpectedLowpass[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio_lame['lowpass_frequency']]) && ($thisfile_mpeg_audio_lame['lowpass_frequency'] < 22050) && (round($thisfile_mpeg_audio_lame['lowpass_frequency'] / 1000) < round($thisfile_mpeg_audio['sample_rate'] / 2000))) { + $encoder_options .= ' --lowpass '.$thisfile_mpeg_audio_lame['lowpass_frequency']; + } + break; + + default: + break; + } + break; + } + } + + if (isset($thisfile_mpeg_audio_lame['raw']['source_sample_freq'])) { + if (($thisfile_mpeg_audio['sample_rate'] == 44100) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 1)) { + $encoder_options .= ' --resample 44100'; + } elseif (($thisfile_mpeg_audio['sample_rate'] == 48000) && ($thisfile_mpeg_audio_lame['raw']['source_sample_freq'] != 2)) { + $encoder_options .= ' --resample 48000'; + } elseif ($thisfile_mpeg_audio['sample_rate'] < 44100) { + switch ($thisfile_mpeg_audio_lame['raw']['source_sample_freq']) { + case 0: // <= 32000 + // may or may not be same as source frequency - ignore + break; + case 1: // 44100 + case 2: // 48000 + case 3: // 48000+ + $ExplodedOptions = explode(' ', $encoder_options, 4); + switch ($ExplodedOptions[0]) { + case '--preset': + case '--alt-preset': + switch ($ExplodedOptions[1]) { + case 'fast': + case 'portable': + case 'medium': + case 'standard': + case 'extreme': + case 'insane': + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + break; + + default: + static $ExpectedResampledRate = array( + 'phon+/lw/mw-eu/sw|16000' => 16000, + 'mw-us|24000' => 24000, // 3.95 + 'mw-us|32000' => 32000, // 3.93 + 'mw-us|16000' => 16000, // 3.92 + 'phone|16000' => 16000, + 'phone|11025' => 11025, // 3.94a15 + 'radio|32000' => 32000, // 3.94a15 + 'fm/radio|32000' => 32000, // 3.92 + 'fm|32000' => 32000, // 3.90 + 'voice|32000' => 32000); + if (!isset($ExpectedResampledRate[$ExplodedOptions[1].'|'.$thisfile_mpeg_audio['sample_rate']])) { + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + } + break; + } + break; + + case '--r3mix': + default: + $encoder_options .= ' --resample '.$thisfile_mpeg_audio['sample_rate']; + break; + } + break; + } + } + } + if (empty($encoder_options) && !empty($info['audio']['bitrate']) && !empty($info['audio']['bitrate_mode'])) { + //$encoder_options = strtoupper($info['audio']['bitrate_mode']).ceil($info['audio']['bitrate'] / 1000); + $encoder_options = strtoupper($info['audio']['bitrate_mode']); + } + + return $encoder_options; + } + + + public function decodeMPEGaudioHeader($offset, &$info, $recursivesearch=true, $ScanAsCBR=false, $FastMPEGheaderScan=false) { + static $MPEGaudioVersionLookup; + static $MPEGaudioLayerLookup; + static $MPEGaudioBitrateLookup; + static $MPEGaudioFrequencyLookup; + static $MPEGaudioChannelModeLookup; + static $MPEGaudioModeExtensionLookup; + static $MPEGaudioEmphasisLookup; + if (empty($MPEGaudioVersionLookup)) { + $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); + $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); + $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); + $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); + $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); + $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); + $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); + } + + if (fseek($this->getid3->fp, $offset, SEEK_SET) != 0) { + $info['error'][] = 'decodeMPEGaudioHeader() failed to seek to next offset at '.$offset; + return false; + } + //$headerstring = fread($this->getid3->fp, 1441); // worst-case max length = 32kHz @ 320kbps layer 3 = 1441 bytes/frame + $headerstring = fread($this->getid3->fp, 226); // LAME header at offset 36 + 190 bytes of Xing/LAME data + + // MP3 audio frame structure: + // $aa $aa $aa $aa [$bb $bb] $cc... + // where $aa..$aa is the four-byte mpeg-audio header (below) + // $bb $bb is the optional 2-byte CRC + // and $cc... is the audio data + + $head4 = substr($headerstring, 0, 4); + + static $MPEGaudioHeaderDecodeCache = array(); + if (isset($MPEGaudioHeaderDecodeCache[$head4])) { + $MPEGheaderRawArray = $MPEGaudioHeaderDecodeCache[$head4]; + } else { + $MPEGheaderRawArray = self::MPEGaudioHeaderDecode($head4); + $MPEGaudioHeaderDecodeCache[$head4] = $MPEGheaderRawArray; + } + + static $MPEGaudioHeaderValidCache = array(); + if (!isset($MPEGaudioHeaderValidCache[$head4])) { // Not in cache + //$MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, true); // allow badly-formatted freeformat (from LAME 3.90 - 3.93.1) + $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGheaderRawArray, false, false); + } + + // shortcut + if (!isset($info['mpeg']['audio'])) { + $info['mpeg']['audio'] = array(); + } + $thisfile_mpeg_audio = &$info['mpeg']['audio']; + + + if ($MPEGaudioHeaderValidCache[$head4]) { + $thisfile_mpeg_audio['raw'] = $MPEGheaderRawArray; + } else { + $info['error'][] = 'Invalid MPEG audio header ('.getid3_lib::PrintHexBytes($head4).') at offset '.$offset; + return false; + } + + if (!$FastMPEGheaderScan) { + $thisfile_mpeg_audio['version'] = $MPEGaudioVersionLookup[$thisfile_mpeg_audio['raw']['version']]; + $thisfile_mpeg_audio['layer'] = $MPEGaudioLayerLookup[$thisfile_mpeg_audio['raw']['layer']]; + + $thisfile_mpeg_audio['channelmode'] = $MPEGaudioChannelModeLookup[$thisfile_mpeg_audio['raw']['channelmode']]; + $thisfile_mpeg_audio['channels'] = (($thisfile_mpeg_audio['channelmode'] == 'mono') ? 1 : 2); + $thisfile_mpeg_audio['sample_rate'] = $MPEGaudioFrequencyLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['raw']['sample_rate']]; + $thisfile_mpeg_audio['protection'] = !$thisfile_mpeg_audio['raw']['protection']; + $thisfile_mpeg_audio['private'] = (bool) $thisfile_mpeg_audio['raw']['private']; + $thisfile_mpeg_audio['modeextension'] = $MPEGaudioModeExtensionLookup[$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['modeextension']]; + $thisfile_mpeg_audio['copyright'] = (bool) $thisfile_mpeg_audio['raw']['copyright']; + $thisfile_mpeg_audio['original'] = (bool) $thisfile_mpeg_audio['raw']['original']; + $thisfile_mpeg_audio['emphasis'] = $MPEGaudioEmphasisLookup[$thisfile_mpeg_audio['raw']['emphasis']]; + + $info['audio']['channels'] = $thisfile_mpeg_audio['channels']; + $info['audio']['sample_rate'] = $thisfile_mpeg_audio['sample_rate']; + + if ($thisfile_mpeg_audio['protection']) { + $thisfile_mpeg_audio['crc'] = getid3_lib::BigEndian2Int(substr($headerstring, 4, 2)); + } + } + + if ($thisfile_mpeg_audio['raw']['bitrate'] == 15) { + // http://www.hydrogenaudio.org/?act=ST&f=16&t=9682&st=0 + $info['warning'][] = 'Invalid bitrate index (15), this is a known bug in free-format MP3s encoded by LAME v3.90 - 3.93.1'; + $thisfile_mpeg_audio['raw']['bitrate'] = 0; + } + $thisfile_mpeg_audio['padding'] = (bool) $thisfile_mpeg_audio['raw']['padding']; + $thisfile_mpeg_audio['bitrate'] = $MPEGaudioBitrateLookup[$thisfile_mpeg_audio['version']][$thisfile_mpeg_audio['layer']][$thisfile_mpeg_audio['raw']['bitrate']]; + + if (($thisfile_mpeg_audio['bitrate'] == 'free') && ($offset == $info['avdataoffset'])) { + // only skip multiple frame check if free-format bitstream found at beginning of file + // otherwise is quite possibly simply corrupted data + $recursivesearch = false; + } + + // For Layer 2 there are some combinations of bitrate and mode which are not allowed. + if (!$FastMPEGheaderScan && ($thisfile_mpeg_audio['layer'] == '2')) { + + $info['audio']['dataformat'] = 'mp2'; + switch ($thisfile_mpeg_audio['channelmode']) { + + case 'mono': + if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] <= 192000)) { + // these are ok + } else { + $info['error'][] = $thisfile_mpeg_audio['bitrate'].'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'; + return false; + } + break; + + case 'stereo': + case 'joint stereo': + case 'dual channel': + if (($thisfile_mpeg_audio['bitrate'] == 'free') || ($thisfile_mpeg_audio['bitrate'] == 64000) || ($thisfile_mpeg_audio['bitrate'] >= 96000)) { + // these are ok + } else { + $info['error'][] = intval(round($thisfile_mpeg_audio['bitrate'] / 1000)).'kbps not allowed in Layer 2, '.$thisfile_mpeg_audio['channelmode'].'.'; + return false; + } + break; + + } + + } + + + if ($info['audio']['sample_rate'] > 0) { + $thisfile_mpeg_audio['framelength'] = self::MPEGaudioFrameLength($thisfile_mpeg_audio['bitrate'], $thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['layer'], (int) $thisfile_mpeg_audio['padding'], $info['audio']['sample_rate']); + } + + $nextframetestoffset = $offset + 1; + if ($thisfile_mpeg_audio['bitrate'] != 'free') { + + $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; + + if (isset($thisfile_mpeg_audio['framelength'])) { + $nextframetestoffset = $offset + $thisfile_mpeg_audio['framelength']; + } else { + $info['error'][] = 'Frame at offset('.$offset.') is has an invalid frame length.'; + return false; + } + + } + + $ExpectedNumberOfAudioBytes = 0; + + //////////////////////////////////////////////////////////////////////////////////// + // Variable-bitrate headers + + if (substr($headerstring, 4 + 32, 4) == 'VBRI') { + // Fraunhofer VBR header is hardcoded 'VBRI' at offset 0x24 (36) + // specs taken from http://minnie.tuhs.org/pipermail/mp3encoder/2001-January/001800.html + + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + $thisfile_mpeg_audio['VBR_method'] = 'Fraunhofer'; + $info['audio']['codec'] = 'Fraunhofer'; + + $SideInfoData = substr($headerstring, 4 + 2, 32); + + $FraunhoferVBROffset = 36; + + $thisfile_mpeg_audio['VBR_encoder_version'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 4, 2)); // VbriVersion + $thisfile_mpeg_audio['VBR_encoder_delay'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 6, 2)); // VbriDelay + $thisfile_mpeg_audio['VBR_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 8, 2)); // VbriQuality + $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 10, 4)); // VbriStreamBytes + $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 14, 4)); // VbriStreamFrames + $thisfile_mpeg_audio['VBR_seek_offsets'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 18, 2)); // VbriTableSize + $thisfile_mpeg_audio['VBR_seek_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 20, 2)); // VbriTableScale + $thisfile_mpeg_audio['VBR_entry_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 22, 2)); // VbriEntryBytes + $thisfile_mpeg_audio['VBR_entry_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset + 24, 2)); // VbriEntryFrames + + $ExpectedNumberOfAudioBytes = $thisfile_mpeg_audio['VBR_bytes']; + + $previousbyteoffset = $offset; + for ($i = 0; $i < $thisfile_mpeg_audio['VBR_seek_offsets']; $i++) { + $Fraunhofer_OffsetN = getid3_lib::BigEndian2Int(substr($headerstring, $FraunhoferVBROffset, $thisfile_mpeg_audio['VBR_entry_bytes'])); + $FraunhoferVBROffset += $thisfile_mpeg_audio['VBR_entry_bytes']; + $thisfile_mpeg_audio['VBR_offsets_relative'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']); + $thisfile_mpeg_audio['VBR_offsets_absolute'][$i] = ($Fraunhofer_OffsetN * $thisfile_mpeg_audio['VBR_seek_scale']) + $previousbyteoffset; + $previousbyteoffset += $Fraunhofer_OffsetN; + } + + + } else { + + // Xing VBR header is hardcoded 'Xing' at a offset 0x0D (13), 0x15 (21) or 0x24 (36) + // depending on MPEG layer and number of channels + + $VBRidOffset = self::XingVBRidOffset($thisfile_mpeg_audio['version'], $thisfile_mpeg_audio['channelmode']); + $SideInfoData = substr($headerstring, 4 + 2, $VBRidOffset - 4); + + if ((substr($headerstring, $VBRidOffset, strlen('Xing')) == 'Xing') || (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Info')) { + // 'Xing' is traditional Xing VBR frame + // 'Info' is LAME-encoded CBR (This was done to avoid CBR files to be recognized as traditional Xing VBR files by some decoders.) + // 'Info' *can* legally be used to specify a VBR file as well, however. + + // http://www.multiweb.cz/twoinches/MP3inside.htm + //00..03 = "Xing" or "Info" + //04..07 = Flags: + // 0x01 Frames Flag set if value for number of frames in file is stored + // 0x02 Bytes Flag set if value for filesize in bytes is stored + // 0x04 TOC Flag set if values for TOC are stored + // 0x08 VBR Scale Flag set if values for VBR scale is stored + //08..11 Frames: Number of frames in file (including the first Xing/Info one) + //12..15 Bytes: File length in Bytes + //16..115 TOC (Table of Contents): + // Contains of 100 indexes (one Byte length) for easier lookup in file. Approximately solves problem with moving inside file. + // Each Byte has a value according this formula: + // (TOC[i] / 256) * fileLenInBytes + // So if song lasts eg. 240 sec. and you want to jump to 60. sec. (and file is 5 000 000 Bytes length) you can use: + // TOC[(60/240)*100] = TOC[25] + // and corresponding Byte in file is then approximately at: + // (TOC[25]/256) * 5000000 + //116..119 VBR Scale + + + // should be safe to leave this at 'vbr' and let it be overriden to 'cbr' if a CBR preset/mode is used by LAME +// if (substr($headerstring, $VBRidOffset, strlen('Info')) == 'Xing') { + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + $thisfile_mpeg_audio['VBR_method'] = 'Xing'; +// } else { +// $ScanAsCBR = true; +// $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; +// } + + $thisfile_mpeg_audio['xing_flags_raw'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 4, 4)); + + $thisfile_mpeg_audio['xing_flags']['frames'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000001); + $thisfile_mpeg_audio['xing_flags']['bytes'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000002); + $thisfile_mpeg_audio['xing_flags']['toc'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000004); + $thisfile_mpeg_audio['xing_flags']['vbr_scale'] = (bool) ($thisfile_mpeg_audio['xing_flags_raw'] & 0x00000008); + + if ($thisfile_mpeg_audio['xing_flags']['frames']) { + $thisfile_mpeg_audio['VBR_frames'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 8, 4)); + //$thisfile_mpeg_audio['VBR_frames']--; // don't count header Xing/Info frame + } + if ($thisfile_mpeg_audio['xing_flags']['bytes']) { + $thisfile_mpeg_audio['VBR_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 12, 4)); + } + + //if (($thisfile_mpeg_audio['bitrate'] == 'free') && !empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { + if (!empty($thisfile_mpeg_audio['VBR_frames']) && !empty($thisfile_mpeg_audio['VBR_bytes'])) { + + $framelengthfloat = $thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']; + + if ($thisfile_mpeg_audio['layer'] == '1') { + // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 + //$info['audio']['bitrate'] = ((($framelengthfloat / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12; + $info['audio']['bitrate'] = ($framelengthfloat / 4) * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 12; + } else { + // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 + //$info['audio']['bitrate'] = (($framelengthfloat - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; + $info['audio']['bitrate'] = $framelengthfloat * $thisfile_mpeg_audio['sample_rate'] * (2 / $info['audio']['channels']) / 144; + } + $thisfile_mpeg_audio['framelength'] = floor($framelengthfloat); + } + + if ($thisfile_mpeg_audio['xing_flags']['toc']) { + $LAMEtocData = substr($headerstring, $VBRidOffset + 16, 100); + for ($i = 0; $i < 100; $i++) { + $thisfile_mpeg_audio['toc'][$i] = ord($LAMEtocData{$i}); + } + } + if ($thisfile_mpeg_audio['xing_flags']['vbr_scale']) { + $thisfile_mpeg_audio['VBR_scale'] = getid3_lib::BigEndian2Int(substr($headerstring, $VBRidOffset + 116, 4)); + } + + + // http://gabriel.mp3-tech.org/mp3infotag.html + if (substr($headerstring, $VBRidOffset + 120, 4) == 'LAME') { + + // shortcut + $thisfile_mpeg_audio['LAME'] = array(); + $thisfile_mpeg_audio_lame = &$thisfile_mpeg_audio['LAME']; + + + $thisfile_mpeg_audio_lame['long_version'] = substr($headerstring, $VBRidOffset + 120, 20); + $thisfile_mpeg_audio_lame['short_version'] = substr($thisfile_mpeg_audio_lame['long_version'], 0, 9); + + if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.90') { + + // extra 11 chars are not part of version string when LAMEtag present + unset($thisfile_mpeg_audio_lame['long_version']); + + // It the LAME tag was only introduced in LAME v3.90 + // http://www.hydrogenaudio.org/?act=ST&f=15&t=9933 + + // Offsets of various bytes in http://gabriel.mp3-tech.org/mp3infotag.html + // are assuming a 'Xing' identifier offset of 0x24, which is the case for + // MPEG-1 non-mono, but not for other combinations + $LAMEtagOffsetContant = $VBRidOffset - 0x24; + + // shortcuts + $thisfile_mpeg_audio_lame['RGAD'] = array('track'=>array(), 'album'=>array()); + $thisfile_mpeg_audio_lame_RGAD = &$thisfile_mpeg_audio_lame['RGAD']; + $thisfile_mpeg_audio_lame_RGAD_track = &$thisfile_mpeg_audio_lame_RGAD['track']; + $thisfile_mpeg_audio_lame_RGAD_album = &$thisfile_mpeg_audio_lame_RGAD['album']; + $thisfile_mpeg_audio_lame['raw'] = array(); + $thisfile_mpeg_audio_lame_raw = &$thisfile_mpeg_audio_lame['raw']; + + // byte $9B VBR Quality + // This field is there to indicate a quality level, although the scale was not precised in the original Xing specifications. + // Actually overwrites original Xing bytes + unset($thisfile_mpeg_audio['VBR_scale']); + $thisfile_mpeg_audio_lame['vbr_quality'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0x9B, 1)); + + // bytes $9C-$A4 Encoder short VersionString + $thisfile_mpeg_audio_lame['short_version'] = substr($headerstring, $LAMEtagOffsetContant + 0x9C, 9); + + // byte $A5 Info Tag revision + VBR method + $LAMEtagRevisionVBRmethod = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA5, 1)); + + $thisfile_mpeg_audio_lame['tag_revision'] = ($LAMEtagRevisionVBRmethod & 0xF0) >> 4; + $thisfile_mpeg_audio_lame_raw['vbr_method'] = $LAMEtagRevisionVBRmethod & 0x0F; + $thisfile_mpeg_audio_lame['vbr_method'] = self::LAMEvbrMethodLookup($thisfile_mpeg_audio_lame_raw['vbr_method']); + $thisfile_mpeg_audio['bitrate_mode'] = substr($thisfile_mpeg_audio_lame['vbr_method'], 0, 3); // usually either 'cbr' or 'vbr', but truncates 'vbr-old / vbr-rh' to 'vbr' + + // byte $A6 Lowpass filter value + $thisfile_mpeg_audio_lame['lowpass_frequency'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA6, 1)) * 100; + + // bytes $A7-$AE Replay Gain + // http://privatewww.essex.ac.uk/~djmrob/replaygain/rg_data_format.html + // bytes $A7-$AA : 32 bit floating point "Peak signal amplitude" + if ($thisfile_mpeg_audio_lame['short_version'] >= 'LAME3.94b') { + // LAME 3.94a16 and later - 9.23 fixed point + // ie 0x0059E2EE / (2^23) = 5890798 / 8388608 = 0.7022378444671630859375 + $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = (float) ((getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4))) / 8388608); + } else { + // LAME 3.94a15 and earlier - 32-bit floating point + // Actually 3.94a16 will fall in here too and be WRONG, but is hard to detect 3.94a16 vs 3.94a15 + $thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] = getid3_lib::LittleEndian2Float(substr($headerstring, $LAMEtagOffsetContant + 0xA7, 4)); + } + if ($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'] == 0) { + unset($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); + } else { + $thisfile_mpeg_audio_lame_RGAD['peak_db'] = getid3_lib::RGADamplitude2dB($thisfile_mpeg_audio_lame_RGAD['peak_amplitude']); + } + + $thisfile_mpeg_audio_lame_raw['RGAD_track'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAB, 2)); + $thisfile_mpeg_audio_lame_raw['RGAD_album'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAD, 2)); + + + if ($thisfile_mpeg_audio_lame_raw['RGAD_track'] != 0) { + + $thisfile_mpeg_audio_lame_RGAD_track['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0xE000) >> 13; + $thisfile_mpeg_audio_lame_RGAD_track['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x1C00) >> 10; + $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x0200) >> 9; + $thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_track'] & 0x01FF; + $thisfile_mpeg_audio_lame_RGAD_track['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['name']); + $thisfile_mpeg_audio_lame_RGAD_track['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['originator']); + $thisfile_mpeg_audio_lame_RGAD_track['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_track['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_track['raw']['sign_bit']); + + if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { + $info['replay_gain']['track']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; + } + $info['replay_gain']['track']['originator'] = $thisfile_mpeg_audio_lame_RGAD_track['originator']; + $info['replay_gain']['track']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_track['gain_db']; + } else { + unset($thisfile_mpeg_audio_lame_RGAD['track']); + } + if ($thisfile_mpeg_audio_lame_raw['RGAD_album'] != 0) { + + $thisfile_mpeg_audio_lame_RGAD_album['raw']['name'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0xE000) >> 13; + $thisfile_mpeg_audio_lame_RGAD_album['raw']['originator'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x1C00) >> 10; + $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit'] = ($thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x0200) >> 9; + $thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'] = $thisfile_mpeg_audio_lame_raw['RGAD_album'] & 0x01FF; + $thisfile_mpeg_audio_lame_RGAD_album['name'] = getid3_lib::RGADnameLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['name']); + $thisfile_mpeg_audio_lame_RGAD_album['originator'] = getid3_lib::RGADoriginatorLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['originator']); + $thisfile_mpeg_audio_lame_RGAD_album['gain_db'] = getid3_lib::RGADadjustmentLookup($thisfile_mpeg_audio_lame_RGAD_album['raw']['gain_adjust'], $thisfile_mpeg_audio_lame_RGAD_album['raw']['sign_bit']); + + if (!empty($thisfile_mpeg_audio_lame_RGAD['peak_amplitude'])) { + $info['replay_gain']['album']['peak'] = $thisfile_mpeg_audio_lame_RGAD['peak_amplitude']; + } + $info['replay_gain']['album']['originator'] = $thisfile_mpeg_audio_lame_RGAD_album['originator']; + $info['replay_gain']['album']['adjustment'] = $thisfile_mpeg_audio_lame_RGAD_album['gain_db']; + } else { + unset($thisfile_mpeg_audio_lame_RGAD['album']); + } + if (empty($thisfile_mpeg_audio_lame_RGAD)) { + unset($thisfile_mpeg_audio_lame['RGAD']); + } + + + // byte $AF Encoding flags + ATH Type + $EncodingFlagsATHtype = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xAF, 1)); + $thisfile_mpeg_audio_lame['encoding_flags']['nspsytune'] = (bool) ($EncodingFlagsATHtype & 0x10); + $thisfile_mpeg_audio_lame['encoding_flags']['nssafejoint'] = (bool) ($EncodingFlagsATHtype & 0x20); + $thisfile_mpeg_audio_lame['encoding_flags']['nogap_next'] = (bool) ($EncodingFlagsATHtype & 0x40); + $thisfile_mpeg_audio_lame['encoding_flags']['nogap_prev'] = (bool) ($EncodingFlagsATHtype & 0x80); + $thisfile_mpeg_audio_lame['ath_type'] = $EncodingFlagsATHtype & 0x0F; + + // byte $B0 if ABR {specified bitrate} else {minimal bitrate} + $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB0, 1)); + if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 2) { // Average BitRate (ABR) + $thisfile_mpeg_audio_lame['bitrate_abr'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; + } elseif ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { // Constant BitRate (CBR) + // ignore + } elseif ($thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate'] > 0) { // Variable BitRate (VBR) - minimum bitrate + $thisfile_mpeg_audio_lame['bitrate_min'] = $thisfile_mpeg_audio_lame['raw']['abrbitrate_minbitrate']; + } + + // bytes $B1-$B3 Encoder delays + $EncoderDelays = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB1, 3)); + $thisfile_mpeg_audio_lame['encoder_delay'] = ($EncoderDelays & 0xFFF000) >> 12; + $thisfile_mpeg_audio_lame['end_padding'] = $EncoderDelays & 0x000FFF; + + // byte $B4 Misc + $MiscByte = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB4, 1)); + $thisfile_mpeg_audio_lame_raw['noise_shaping'] = ($MiscByte & 0x03); + $thisfile_mpeg_audio_lame_raw['stereo_mode'] = ($MiscByte & 0x1C) >> 2; + $thisfile_mpeg_audio_lame_raw['not_optimal_quality'] = ($MiscByte & 0x20) >> 5; + $thisfile_mpeg_audio_lame_raw['source_sample_freq'] = ($MiscByte & 0xC0) >> 6; + $thisfile_mpeg_audio_lame['noise_shaping'] = $thisfile_mpeg_audio_lame_raw['noise_shaping']; + $thisfile_mpeg_audio_lame['stereo_mode'] = self::LAMEmiscStereoModeLookup($thisfile_mpeg_audio_lame_raw['stereo_mode']); + $thisfile_mpeg_audio_lame['not_optimal_quality'] = (bool) $thisfile_mpeg_audio_lame_raw['not_optimal_quality']; + $thisfile_mpeg_audio_lame['source_sample_freq'] = self::LAMEmiscSourceSampleFrequencyLookup($thisfile_mpeg_audio_lame_raw['source_sample_freq']); + + // byte $B5 MP3 Gain + $thisfile_mpeg_audio_lame_raw['mp3_gain'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB5, 1), false, true); + $thisfile_mpeg_audio_lame['mp3_gain_db'] = (getid3_lib::RGADamplitude2dB(2) / 4) * $thisfile_mpeg_audio_lame_raw['mp3_gain']; + $thisfile_mpeg_audio_lame['mp3_gain_factor'] = pow(2, ($thisfile_mpeg_audio_lame['mp3_gain_db'] / 6)); + + // bytes $B6-$B7 Preset and surround info + $PresetSurroundBytes = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB6, 2)); + // Reserved = ($PresetSurroundBytes & 0xC000); + $thisfile_mpeg_audio_lame_raw['surround_info'] = ($PresetSurroundBytes & 0x3800); + $thisfile_mpeg_audio_lame['surround_info'] = self::LAMEsurroundInfoLookup($thisfile_mpeg_audio_lame_raw['surround_info']); + $thisfile_mpeg_audio_lame['preset_used_id'] = ($PresetSurroundBytes & 0x07FF); + $thisfile_mpeg_audio_lame['preset_used'] = self::LAMEpresetUsedLookup($thisfile_mpeg_audio_lame); + if (!empty($thisfile_mpeg_audio_lame['preset_used_id']) && empty($thisfile_mpeg_audio_lame['preset_used'])) { + $info['warning'][] = 'Unknown LAME preset used ('.$thisfile_mpeg_audio_lame['preset_used_id'].') - please report to info@getid3.org'; + } + if (($thisfile_mpeg_audio_lame['short_version'] == 'LAME3.90.') && !empty($thisfile_mpeg_audio_lame['preset_used_id'])) { + // this may change if 3.90.4 ever comes out + $thisfile_mpeg_audio_lame['short_version'] = 'LAME3.90.3'; + } + + // bytes $B8-$BB MusicLength + $thisfile_mpeg_audio_lame['audio_bytes'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xB8, 4)); + $ExpectedNumberOfAudioBytes = (($thisfile_mpeg_audio_lame['audio_bytes'] > 0) ? $thisfile_mpeg_audio_lame['audio_bytes'] : $thisfile_mpeg_audio['VBR_bytes']); + + // bytes $BC-$BD MusicCRC + $thisfile_mpeg_audio_lame['music_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBC, 2)); + + // bytes $BE-$BF CRC-16 of Info Tag + $thisfile_mpeg_audio_lame['lame_tag_crc'] = getid3_lib::BigEndian2Int(substr($headerstring, $LAMEtagOffsetContant + 0xBE, 2)); + + + // LAME CBR + if ($thisfile_mpeg_audio_lame_raw['vbr_method'] == 1) { + + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + $thisfile_mpeg_audio['bitrate'] = self::ClosestStandardMP3Bitrate($thisfile_mpeg_audio['bitrate']); + $info['audio']['bitrate'] = $thisfile_mpeg_audio['bitrate']; + //if (empty($thisfile_mpeg_audio['bitrate']) || (!empty($thisfile_mpeg_audio_lame['bitrate_min']) && ($thisfile_mpeg_audio_lame['bitrate_min'] != 255))) { + // $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio_lame['bitrate_min']; + //} + + } + + } + } + + } else { + + // not Fraunhofer or Xing VBR methods, most likely CBR (but could be VBR with no header) + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + if ($recursivesearch) { + $thisfile_mpeg_audio['bitrate_mode'] = 'vbr'; + if ($this->RecursiveFrameScanning($offset, $nextframetestoffset, true)) { + $recursivesearch = false; + $thisfile_mpeg_audio['bitrate_mode'] = 'cbr'; + } + if ($thisfile_mpeg_audio['bitrate_mode'] == 'vbr') { + $info['warning'][] = 'VBR file with no VBR header. Bitrate values calculated from actual frame bitrates.'; + } + } + + } + + } + + if (($ExpectedNumberOfAudioBytes > 0) && ($ExpectedNumberOfAudioBytes != ($info['avdataend'] - $info['avdataoffset']))) { + if ($ExpectedNumberOfAudioBytes > ($info['avdataend'] - $info['avdataoffset'])) { + if (isset($info['fileformat']) && ($info['fileformat'] == 'riff')) { + // ignore, audio data is broken into chunks so will always be data "missing" + } elseif (($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])) == 1) { + $info['warning'][] = 'Last byte of data truncated (this is a known bug in Meracl ID3 Tag Writer before v1.3.5)'; + } else { + $info['warning'][] = 'Probable truncated file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, only found '.($info['avdataend'] - $info['avdataoffset']).' (short by '.($ExpectedNumberOfAudioBytes - ($info['avdataend'] - $info['avdataoffset'])).' bytes)'; + } + } else { + if ((($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes) == 1) { + // $prenullbytefileoffset = ftell($this->getid3->fp); + // fseek($this->getid3->fp, $info['avdataend'], SEEK_SET); + // $PossibleNullByte = fread($this->getid3->fp, 1); + // fseek($this->getid3->fp, $prenullbytefileoffset, SEEK_SET); + // if ($PossibleNullByte === "\x00") { + $info['avdataend']--; + // $info['warning'][] = 'Extra null byte at end of MP3 data assumed to be RIFF padding and therefore ignored'; + // } else { + // $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'; + // } + } else { + $info['warning'][] = 'Too much data in file: expecting '.$ExpectedNumberOfAudioBytes.' bytes of audio data, found '.($info['avdataend'] - $info['avdataoffset']).' ('.(($info['avdataend'] - $info['avdataoffset']) - $ExpectedNumberOfAudioBytes).' bytes too many)'; + } + } + } + + if (($thisfile_mpeg_audio['bitrate'] == 'free') && empty($info['audio']['bitrate'])) { + if (($offset == $info['avdataoffset']) && empty($thisfile_mpeg_audio['VBR_frames'])) { + $framebytelength = $this->FreeFormatFrameLength($offset, true); + if ($framebytelength > 0) { + $thisfile_mpeg_audio['framelength'] = $framebytelength; + if ($thisfile_mpeg_audio['layer'] == '1') { + // BitRate = (((FrameLengthInBytes / 4) - Padding) * SampleRate) / 12 + $info['audio']['bitrate'] = ((($framebytelength / 4) - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 12; + } else { + // Bitrate = ((FrameLengthInBytes - Padding) * SampleRate) / 144 + $info['audio']['bitrate'] = (($framebytelength - intval($thisfile_mpeg_audio['padding'])) * $thisfile_mpeg_audio['sample_rate']) / 144; + } + } else { + $info['error'][] = 'Error calculating frame length of free-format MP3 without Xing/LAME header'; + } + } + } + + if (isset($thisfile_mpeg_audio['VBR_frames']) ? $thisfile_mpeg_audio['VBR_frames'] : '') { + switch ($thisfile_mpeg_audio['bitrate_mode']) { + case 'vbr': + case 'abr': + $bytes_per_frame = 1152; + if (($thisfile_mpeg_audio['version'] == '1') && ($thisfile_mpeg_audio['layer'] == 1)) { + $bytes_per_frame = 384; + } elseif ((($thisfile_mpeg_audio['version'] == '2') || ($thisfile_mpeg_audio['version'] == '2.5')) && ($thisfile_mpeg_audio['layer'] == 3)) { + $bytes_per_frame = 576; + } + $thisfile_mpeg_audio['VBR_bitrate'] = (isset($thisfile_mpeg_audio['VBR_bytes']) ? (($thisfile_mpeg_audio['VBR_bytes'] / $thisfile_mpeg_audio['VBR_frames']) * 8) * ($info['audio']['sample_rate'] / $bytes_per_frame) : 0); + if ($thisfile_mpeg_audio['VBR_bitrate'] > 0) { + $info['audio']['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; + $thisfile_mpeg_audio['bitrate'] = $thisfile_mpeg_audio['VBR_bitrate']; // to avoid confusion + } + break; + } + } + + // End variable-bitrate headers + //////////////////////////////////////////////////////////////////////////////////// + + if ($recursivesearch) { + + if (!$this->RecursiveFrameScanning($offset, $nextframetestoffset, $ScanAsCBR)) { + return false; + } + + } + + + //if (false) { + // // experimental side info parsing section - not returning anything useful yet + // + // $SideInfoBitstream = getid3_lib::BigEndian2Bin($SideInfoData); + // $SideInfoOffset = 0; + // + // if ($thisfile_mpeg_audio['version'] == '1') { + // if ($thisfile_mpeg_audio['channelmode'] == 'mono') { + // // MPEG-1 (mono) + // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9); + // $SideInfoOffset += 9; + // $SideInfoOffset += 5; + // } else { + // // MPEG-1 (stereo, joint-stereo, dual-channel) + // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 9); + // $SideInfoOffset += 9; + // $SideInfoOffset += 3; + // } + // } else { // 2 or 2.5 + // if ($thisfile_mpeg_audio['channelmode'] == 'mono') { + // // MPEG-2, MPEG-2.5 (mono) + // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8); + // $SideInfoOffset += 8; + // $SideInfoOffset += 1; + // } else { + // // MPEG-2, MPEG-2.5 (stereo, joint-stereo, dual-channel) + // $thisfile_mpeg_audio['side_info']['main_data_begin'] = substr($SideInfoBitstream, $SideInfoOffset, 8); + // $SideInfoOffset += 8; + // $SideInfoOffset += 2; + // } + // } + // + // if ($thisfile_mpeg_audio['version'] == '1') { + // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) { + // for ($scfsi_band = 0; $scfsi_band < 4; $scfsi_band++) { + // $thisfile_mpeg_audio['scfsi'][$channel][$scfsi_band] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 2; + // } + // } + // } + // for ($granule = 0; $granule < (($thisfile_mpeg_audio['version'] == '1') ? 2 : 1); $granule++) { + // for ($channel = 0; $channel < $info['audio']['channels']; $channel++) { + // $thisfile_mpeg_audio['part2_3_length'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 12); + // $SideInfoOffset += 12; + // $thisfile_mpeg_audio['big_values'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9); + // $SideInfoOffset += 9; + // $thisfile_mpeg_audio['global_gain'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 8); + // $SideInfoOffset += 8; + // if ($thisfile_mpeg_audio['version'] == '1') { + // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4); + // $SideInfoOffset += 4; + // } else { + // $thisfile_mpeg_audio['scalefac_compress'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 9); + // $SideInfoOffset += 9; + // } + // $thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 1; + // + // if ($thisfile_mpeg_audio['window_switching_flag'][$granule][$channel] == '1') { + // + // $thisfile_mpeg_audio['block_type'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 2); + // $SideInfoOffset += 2; + // $thisfile_mpeg_audio['mixed_block_flag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 1; + // + // for ($region = 0; $region < 2; $region++) { + // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5); + // $SideInfoOffset += 5; + // } + // $thisfile_mpeg_audio['table_select'][$granule][$channel][2] = 0; + // + // for ($window = 0; $window < 3; $window++) { + // $thisfile_mpeg_audio['subblock_gain'][$granule][$channel][$window] = substr($SideInfoBitstream, $SideInfoOffset, 3); + // $SideInfoOffset += 3; + // } + // + // } else { + // + // for ($region = 0; $region < 3; $region++) { + // $thisfile_mpeg_audio['table_select'][$granule][$channel][$region] = substr($SideInfoBitstream, $SideInfoOffset, 5); + // $SideInfoOffset += 5; + // } + // + // $thisfile_mpeg_audio['region0_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 4); + // $SideInfoOffset += 4; + // $thisfile_mpeg_audio['region1_count'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 3); + // $SideInfoOffset += 3; + // $thisfile_mpeg_audio['block_type'][$granule][$channel] = 0; + // } + // + // if ($thisfile_mpeg_audio['version'] == '1') { + // $thisfile_mpeg_audio['preflag'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 1; + // } + // $thisfile_mpeg_audio['scalefac_scale'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 1; + // $thisfile_mpeg_audio['count1table_select'][$granule][$channel] = substr($SideInfoBitstream, $SideInfoOffset, 1); + // $SideInfoOffset += 1; + // } + // } + //} + + return true; + } + + public function RecursiveFrameScanning(&$offset, &$nextframetestoffset, $ScanAsCBR) { + $info = &$this->getid3->info; + $firstframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); + $this->decodeMPEGaudioHeader($offset, $firstframetestarray, false); + + for ($i = 0; $i < GETID3_MP3_VALID_CHECK_FRAMES; $i++) { + // check next GETID3_MP3_VALID_CHECK_FRAMES frames for validity, to make sure we haven't run across a false synch + if (($nextframetestoffset + 4) >= $info['avdataend']) { + // end of file + return true; + } + + $nextframetestarray = array('error'=>'', 'warning'=>'', 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); + if ($this->decodeMPEGaudioHeader($nextframetestoffset, $nextframetestarray, false)) { + if ($ScanAsCBR) { + // force CBR mode, used for trying to pick out invalid audio streams with valid(?) VBR headers, or VBR streams with no VBR header + if (!isset($nextframetestarray['mpeg']['audio']['bitrate']) || !isset($firstframetestarray['mpeg']['audio']['bitrate']) || ($nextframetestarray['mpeg']['audio']['bitrate'] != $firstframetestarray['mpeg']['audio']['bitrate'])) { + return false; + } + } + + + // next frame is OK, get ready to check the one after that + if (isset($nextframetestarray['mpeg']['audio']['framelength']) && ($nextframetestarray['mpeg']['audio']['framelength'] > 0)) { + $nextframetestoffset += $nextframetestarray['mpeg']['audio']['framelength']; + } else { + $info['error'][] = 'Frame at offset ('.$offset.') is has an invalid frame length.'; + return false; + } + + } elseif (!empty($firstframetestarray['mpeg']['audio']['framelength']) && (($nextframetestoffset + $firstframetestarray['mpeg']['audio']['framelength']) > $info['avdataend'])) { + + // it's not the end of the file, but there's not enough data left for another frame, so assume it's garbage/padding and return OK + return true; + + } else { + + // next frame is not valid, note the error and fail, so scanning can contiue for a valid frame sequence + $info['warning'][] = 'Frame at offset ('.$offset.') is valid, but the next one at ('.$nextframetestoffset.') is not.'; + + return false; + } + } + return true; + } + + public function FreeFormatFrameLength($offset, $deepscan=false) { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $offset, SEEK_SET); + $MPEGaudioData = fread($this->getid3->fp, 32768); + + $SyncPattern1 = substr($MPEGaudioData, 0, 4); + // may be different pattern due to padding + $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) | 0x02).$SyncPattern1{3}; + if ($SyncPattern2 === $SyncPattern1) { + $SyncPattern2 = $SyncPattern1{0}.$SyncPattern1{1}.chr(ord($SyncPattern1{2}) & 0xFD).$SyncPattern1{3}; + } + + $framelength = false; + $framelength1 = strpos($MPEGaudioData, $SyncPattern1, 4); + $framelength2 = strpos($MPEGaudioData, $SyncPattern2, 4); + if ($framelength1 > 4) { + $framelength = $framelength1; + } + if (($framelength2 > 4) && ($framelength2 < $framelength1)) { + $framelength = $framelength2; + } + if (!$framelength) { + + // LAME 3.88 has a different value for modeextension on the first frame vs the rest + $framelength1 = strpos($MPEGaudioData, substr($SyncPattern1, 0, 3), 4); + $framelength2 = strpos($MPEGaudioData, substr($SyncPattern2, 0, 3), 4); + + if ($framelength1 > 4) { + $framelength = $framelength1; + } + if (($framelength2 > 4) && ($framelength2 < $framelength1)) { + $framelength = $framelength2; + } + if (!$framelength) { + $info['error'][] = 'Cannot find next free-format synch pattern ('.getid3_lib::PrintHexBytes($SyncPattern1).' or '.getid3_lib::PrintHexBytes($SyncPattern2).') after offset '.$offset; + return false; + } else { + $info['warning'][] = 'ModeExtension varies between first frame and other frames (known free-format issue in LAME 3.88)'; + $info['audio']['codec'] = 'LAME'; + $info['audio']['encoder'] = 'LAME3.88'; + $SyncPattern1 = substr($SyncPattern1, 0, 3); + $SyncPattern2 = substr($SyncPattern2, 0, 3); + } + } + + if ($deepscan) { + + $ActualFrameLengthValues = array(); + $nextoffset = $offset + $framelength; + while ($nextoffset < ($info['avdataend'] - 6)) { + fseek($this->getid3->fp, $nextoffset - 1, SEEK_SET); + $NextSyncPattern = fread($this->getid3->fp, 6); + if ((substr($NextSyncPattern, 1, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 1, strlen($SyncPattern2)) == $SyncPattern2)) { + // good - found where expected + $ActualFrameLengthValues[] = $framelength; + } elseif ((substr($NextSyncPattern, 0, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 0, strlen($SyncPattern2)) == $SyncPattern2)) { + // ok - found one byte earlier than expected (last frame wasn't padded, first frame was) + $ActualFrameLengthValues[] = ($framelength - 1); + $nextoffset--; + } elseif ((substr($NextSyncPattern, 2, strlen($SyncPattern1)) == $SyncPattern1) || (substr($NextSyncPattern, 2, strlen($SyncPattern2)) == $SyncPattern2)) { + // ok - found one byte later than expected (last frame was padded, first frame wasn't) + $ActualFrameLengthValues[] = ($framelength + 1); + $nextoffset++; + } else { + $info['error'][] = 'Did not find expected free-format sync pattern at offset '.$nextoffset; + return false; + } + $nextoffset += $framelength; + } + if (count($ActualFrameLengthValues) > 0) { + $framelength = intval(round(array_sum($ActualFrameLengthValues) / count($ActualFrameLengthValues))); + } + } + return $framelength; + } + + public function getOnlyMPEGaudioInfoBruteForce() { + $MPEGaudioHeaderDecodeCache = array(); + $MPEGaudioHeaderValidCache = array(); + $MPEGaudioHeaderLengthCache = array(); + $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); + $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); + $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); + $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); + $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); + $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); + $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); + $LongMPEGversionLookup = array(); + $LongMPEGlayerLookup = array(); + $LongMPEGbitrateLookup = array(); + $LongMPEGpaddingLookup = array(); + $LongMPEGfrequencyLookup = array(); + $Distribution['bitrate'] = array(); + $Distribution['frequency'] = array(); + $Distribution['layer'] = array(); + $Distribution['version'] = array(); + $Distribution['padding'] = array(); + + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $max_frames_scan = 5000; + $frames_scanned = 0; + + $previousvalidframe = $info['avdataoffset']; + while (ftell($this->getid3->fp) < $info['avdataend']) { + set_time_limit(30); + $head4 = fread($this->getid3->fp, 4); + if (strlen($head4) < 4) { + break; + } + if ($head4{0} != "\xFF") { + for ($i = 1; $i < 4; $i++) { + if ($head4{$i} == "\xFF") { + fseek($this->getid3->fp, $i - 4, SEEK_CUR); + continue 2; + } + } + continue; + } + if (!isset($MPEGaudioHeaderDecodeCache[$head4])) { + $MPEGaudioHeaderDecodeCache[$head4] = self::MPEGaudioHeaderDecode($head4); + } + if (!isset($MPEGaudioHeaderValidCache[$head4])) { + $MPEGaudioHeaderValidCache[$head4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$head4], false, false); + } + if ($MPEGaudioHeaderValidCache[$head4]) { + + if (!isset($MPEGaudioHeaderLengthCache[$head4])) { + $LongMPEGversionLookup[$head4] = $MPEGaudioVersionLookup[$MPEGaudioHeaderDecodeCache[$head4]['version']]; + $LongMPEGlayerLookup[$head4] = $MPEGaudioLayerLookup[$MPEGaudioHeaderDecodeCache[$head4]['layer']]; + $LongMPEGbitrateLookup[$head4] = $MPEGaudioBitrateLookup[$LongMPEGversionLookup[$head4]][$LongMPEGlayerLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['bitrate']]; + $LongMPEGpaddingLookup[$head4] = (bool) $MPEGaudioHeaderDecodeCache[$head4]['padding']; + $LongMPEGfrequencyLookup[$head4] = $MPEGaudioFrequencyLookup[$LongMPEGversionLookup[$head4]][$MPEGaudioHeaderDecodeCache[$head4]['sample_rate']]; + $MPEGaudioHeaderLengthCache[$head4] = self::MPEGaudioFrameLength( + $LongMPEGbitrateLookup[$head4], + $LongMPEGversionLookup[$head4], + $LongMPEGlayerLookup[$head4], + $LongMPEGpaddingLookup[$head4], + $LongMPEGfrequencyLookup[$head4]); + } + if ($MPEGaudioHeaderLengthCache[$head4] > 4) { + $WhereWeWere = ftell($this->getid3->fp); + fseek($this->getid3->fp, $MPEGaudioHeaderLengthCache[$head4] - 4, SEEK_CUR); + $next4 = fread($this->getid3->fp, 4); + if ($next4{0} == "\xFF") { + if (!isset($MPEGaudioHeaderDecodeCache[$next4])) { + $MPEGaudioHeaderDecodeCache[$next4] = self::MPEGaudioHeaderDecode($next4); + } + if (!isset($MPEGaudioHeaderValidCache[$next4])) { + $MPEGaudioHeaderValidCache[$next4] = self::MPEGaudioHeaderValid($MPEGaudioHeaderDecodeCache[$next4], false, false); + } + if ($MPEGaudioHeaderValidCache[$next4]) { + fseek($this->getid3->fp, -4, SEEK_CUR); + + getid3_lib::safe_inc($Distribution['bitrate'][$LongMPEGbitrateLookup[$head4]]); + getid3_lib::safe_inc($Distribution['layer'][$LongMPEGlayerLookup[$head4]]); + getid3_lib::safe_inc($Distribution['version'][$LongMPEGversionLookup[$head4]]); + getid3_lib::safe_inc($Distribution['padding'][intval($LongMPEGpaddingLookup[$head4])]); + getid3_lib::safe_inc($Distribution['frequency'][$LongMPEGfrequencyLookup[$head4]]); + if ($max_frames_scan && (++$frames_scanned >= $max_frames_scan)) { + $pct_data_scanned = (ftell($this->getid3->fp) - $info['avdataoffset']) / ($info['avdataend'] - $info['avdataoffset']); + $info['warning'][] = 'too many MPEG audio frames to scan, only scanned first '.$max_frames_scan.' frames ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'; + foreach ($Distribution as $key1 => $value1) { + foreach ($value1 as $key2 => $value2) { + $Distribution[$key1][$key2] = round($value2 / $pct_data_scanned); + } + } + break; + } + continue; + } + } + unset($next4); + fseek($this->getid3->fp, $WhereWeWere - 3, SEEK_SET); + } + + } + } + foreach ($Distribution as $key => $value) { + ksort($Distribution[$key], SORT_NUMERIC); + } + ksort($Distribution['version'], SORT_STRING); + $info['mpeg']['audio']['bitrate_distribution'] = $Distribution['bitrate']; + $info['mpeg']['audio']['frequency_distribution'] = $Distribution['frequency']; + $info['mpeg']['audio']['layer_distribution'] = $Distribution['layer']; + $info['mpeg']['audio']['version_distribution'] = $Distribution['version']; + $info['mpeg']['audio']['padding_distribution'] = $Distribution['padding']; + if (count($Distribution['version']) > 1) { + $info['error'][] = 'Corrupt file - more than one MPEG version detected'; + } + if (count($Distribution['layer']) > 1) { + $info['error'][] = 'Corrupt file - more than one MPEG layer detected'; + } + if (count($Distribution['frequency']) > 1) { + $info['error'][] = 'Corrupt file - more than one MPEG sample rate detected'; + } + + + $bittotal = 0; + foreach ($Distribution['bitrate'] as $bitratevalue => $bitratecount) { + if ($bitratevalue != 'free') { + $bittotal += ($bitratevalue * $bitratecount); + } + } + $info['mpeg']['audio']['frame_count'] = array_sum($Distribution['bitrate']); + if ($info['mpeg']['audio']['frame_count'] == 0) { + $info['error'][] = 'no MPEG audio frames found'; + return false; + } + $info['mpeg']['audio']['bitrate'] = ($bittotal / $info['mpeg']['audio']['frame_count']); + $info['mpeg']['audio']['bitrate_mode'] = ((count($Distribution['bitrate']) > 0) ? 'vbr' : 'cbr'); + $info['mpeg']['audio']['sample_rate'] = getid3_lib::array_max($Distribution['frequency'], true); + + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode']; + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + $info['audio']['dataformat'] = 'mp'.getid3_lib::array_max($Distribution['layer'], true); + $info['fileformat'] = $info['audio']['dataformat']; + + return true; + } + + + public function getOnlyMPEGaudioInfo($avdataoffset, $BitrateHistogram=false) { + // looks for synch, decodes MPEG audio header + + $info = &$this->getid3->info; + + static $MPEGaudioVersionLookup; + static $MPEGaudioLayerLookup; + static $MPEGaudioBitrateLookup; + if (empty($MPEGaudioVersionLookup)) { + $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); + $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); + $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); + + } + + fseek($this->getid3->fp, $avdataoffset, SEEK_SET); + $sync_seek_buffer_size = min(128 * 1024, $info['avdataend'] - $avdataoffset); + if ($sync_seek_buffer_size <= 0) { + $info['error'][] = 'Invalid $sync_seek_buffer_size at offset '.$avdataoffset; + return false; + } + $header = fread($this->getid3->fp, $sync_seek_buffer_size); + $sync_seek_buffer_size = strlen($header); + $SynchSeekOffset = 0; + while ($SynchSeekOffset < $sync_seek_buffer_size) { + if ((($avdataoffset + $SynchSeekOffset) < $info['avdataend']) && !feof($this->getid3->fp)) { + + if ($SynchSeekOffset > $sync_seek_buffer_size) { + // if a synch's not found within the first 128k bytes, then give up + $info['error'][] = 'Could not find valid MPEG audio synch within the first '.round($sync_seek_buffer_size / 1024).'kB'; + if (isset($info['audio']['bitrate'])) { + unset($info['audio']['bitrate']); + } + if (isset($info['mpeg']['audio'])) { + unset($info['mpeg']['audio']); + } + if (empty($info['mpeg'])) { + unset($info['mpeg']); + } + return false; + + } elseif (feof($this->getid3->fp)) { + + $info['error'][] = 'Could not find valid MPEG audio synch before end of file'; + if (isset($info['audio']['bitrate'])) { + unset($info['audio']['bitrate']); + } + if (isset($info['mpeg']['audio'])) { + unset($info['mpeg']['audio']); + } + if (isset($info['mpeg']) && (!is_array($info['mpeg']) || (count($info['mpeg']) == 0))) { + unset($info['mpeg']); + } + return false; + } + } + + if (($SynchSeekOffset + 1) >= strlen($header)) { + $info['error'][] = 'Could not find valid MPEG synch before end of file'; + return false; + } + + if (($header{$SynchSeekOffset} == "\xFF") && ($header{($SynchSeekOffset + 1)} > "\xE0")) { // synch detected + if (!isset($FirstFrameThisfileInfo) && !isset($info['mpeg']['audio'])) { + $FirstFrameThisfileInfo = $info; + $FirstFrameAVDataOffset = $avdataoffset + $SynchSeekOffset; + if (!$this->decodeMPEGaudioHeader($FirstFrameAVDataOffset, $FirstFrameThisfileInfo, false)) { + // if this is the first valid MPEG-audio frame, save it in case it's a VBR header frame and there's + // garbage between this frame and a valid sequence of MPEG-audio frames, to be restored below + unset($FirstFrameThisfileInfo); + } + } + + $dummy = $info; // only overwrite real data if valid header found + if ($this->decodeMPEGaudioHeader($avdataoffset + $SynchSeekOffset, $dummy, true)) { + $info = $dummy; + $info['avdataoffset'] = $avdataoffset + $SynchSeekOffset; + switch (isset($info['fileformat']) ? $info['fileformat'] : '') { + case '': + case 'id3': + case 'ape': + case 'mp3': + $info['fileformat'] = 'mp3'; + $info['audio']['dataformat'] = 'mp3'; + break; + } + if (isset($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode']) && ($FirstFrameThisfileInfo['mpeg']['audio']['bitrate_mode'] == 'vbr')) { + if (!(abs($info['audio']['bitrate'] - $FirstFrameThisfileInfo['audio']['bitrate']) <= 1)) { + // If there is garbage data between a valid VBR header frame and a sequence + // of valid MPEG-audio frames the VBR data is no longer discarded. + $info = $FirstFrameThisfileInfo; + $info['avdataoffset'] = $FirstFrameAVDataOffset; + $info['fileformat'] = 'mp3'; + $info['audio']['dataformat'] = 'mp3'; + $dummy = $info; + unset($dummy['mpeg']['audio']); + $GarbageOffsetStart = $FirstFrameAVDataOffset + $FirstFrameThisfileInfo['mpeg']['audio']['framelength']; + $GarbageOffsetEnd = $avdataoffset + $SynchSeekOffset; + if ($this->decodeMPEGaudioHeader($GarbageOffsetEnd, $dummy, true, true)) { + $info = $dummy; + $info['avdataoffset'] = $GarbageOffsetEnd; + $info['warning'][] = 'apparently-valid VBR header not used because could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.'), but did find valid CBR stream starting at '.$GarbageOffsetEnd; + } else { + $info['warning'][] = 'using data from VBR header even though could not find '.GETID3_MP3_VALID_CHECK_FRAMES.' consecutive MPEG-audio frames immediately after VBR header (garbage data for '.($GarbageOffsetEnd - $GarbageOffsetStart).' bytes between '.$GarbageOffsetStart.' and '.$GarbageOffsetEnd.')'; + } + } + } + if (isset($info['mpeg']['audio']['bitrate_mode']) && ($info['mpeg']['audio']['bitrate_mode'] == 'vbr') && !isset($info['mpeg']['audio']['VBR_method'])) { + // VBR file with no VBR header + $BitrateHistogram = true; + } + + if ($BitrateHistogram) { + + $info['mpeg']['audio']['stereo_distribution'] = array('stereo'=>0, 'joint stereo'=>0, 'dual channel'=>0, 'mono'=>0); + $info['mpeg']['audio']['version_distribution'] = array('1'=>0, '2'=>0, '2.5'=>0); + + if ($info['mpeg']['audio']['version'] == '1') { + if ($info['mpeg']['audio']['layer'] == 3) { + $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0); + } elseif ($info['mpeg']['audio']['layer'] == 2) { + $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 320000=>0, 384000=>0); + } elseif ($info['mpeg']['audio']['layer'] == 1) { + $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 64000=>0, 96000=>0, 128000=>0, 160000=>0, 192000=>0, 224000=>0, 256000=>0, 288000=>0, 320000=>0, 352000=>0, 384000=>0, 416000=>0, 448000=>0); + } + } elseif ($info['mpeg']['audio']['layer'] == 1) { + $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 32000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0, 176000=>0, 192000=>0, 224000=>0, 256000=>0); + } else { + $info['mpeg']['audio']['bitrate_distribution'] = array('free'=>0, 8000=>0, 16000=>0, 24000=>0, 32000=>0, 40000=>0, 48000=>0, 56000=>0, 64000=>0, 80000=>0, 96000=>0, 112000=>0, 128000=>0, 144000=>0, 160000=>0); + } + + $dummy = array('error'=>$info['error'], 'warning'=>$info['warning'], 'avdataend'=>$info['avdataend'], 'avdataoffset'=>$info['avdataoffset']); + $synchstartoffset = $info['avdataoffset']; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + // you can play with these numbers: + $max_frames_scan = 50000; + $max_scan_segments = 10; + + // don't play with these numbers: + $FastMode = false; + $SynchErrorsFound = 0; + $frames_scanned = 0; + $this_scan_segment = 0; + $frames_scan_per_segment = ceil($max_frames_scan / $max_scan_segments); + $pct_data_scanned = 0; + for ($current_segment = 0; $current_segment < $max_scan_segments; $current_segment++) { + $frames_scanned_this_segment = 0; + if (ftell($this->getid3->fp) >= $info['avdataend']) { + break; + } + $scan_start_offset[$current_segment] = max(ftell($this->getid3->fp), $info['avdataoffset'] + round($current_segment * (($info['avdataend'] - $info['avdataoffset']) / $max_scan_segments))); + if ($current_segment > 0) { + fseek($this->getid3->fp, $scan_start_offset[$current_segment], SEEK_SET); + $buffer_4k = fread($this->getid3->fp, 4096); + for ($j = 0; $j < (strlen($buffer_4k) - 4); $j++) { + if (($buffer_4k{$j} == "\xFF") && ($buffer_4k{($j + 1)} > "\xE0")) { // synch detected + if ($this->decodeMPEGaudioHeader($scan_start_offset[$current_segment] + $j, $dummy, false, false, $FastMode)) { + $calculated_next_offset = $scan_start_offset[$current_segment] + $j + $dummy['mpeg']['audio']['framelength']; + if ($this->decodeMPEGaudioHeader($calculated_next_offset, $dummy, false, false, $FastMode)) { + $scan_start_offset[$current_segment] += $j; + break; + } + } + } + } + } + $synchstartoffset = $scan_start_offset[$current_segment]; + while ($this->decodeMPEGaudioHeader($synchstartoffset, $dummy, false, false, $FastMode)) { + $FastMode = true; + $thisframebitrate = $MPEGaudioBitrateLookup[$MPEGaudioVersionLookup[$dummy['mpeg']['audio']['raw']['version']]][$MPEGaudioLayerLookup[$dummy['mpeg']['audio']['raw']['layer']]][$dummy['mpeg']['audio']['raw']['bitrate']]; + + if (empty($dummy['mpeg']['audio']['framelength'])) { + $SynchErrorsFound++; + $synchstartoffset++; + } else { + getid3_lib::safe_inc($info['mpeg']['audio']['bitrate_distribution'][$thisframebitrate]); + getid3_lib::safe_inc($info['mpeg']['audio']['stereo_distribution'][$dummy['mpeg']['audio']['channelmode']]); + getid3_lib::safe_inc($info['mpeg']['audio']['version_distribution'][$dummy['mpeg']['audio']['version']]); + $synchstartoffset += $dummy['mpeg']['audio']['framelength']; + } + $frames_scanned++; + if ($frames_scan_per_segment && (++$frames_scanned_this_segment >= $frames_scan_per_segment)) { + $this_pct_scanned = (ftell($this->getid3->fp) - $scan_start_offset[$current_segment]) / ($info['avdataend'] - $info['avdataoffset']); + if (($current_segment == 0) && (($this_pct_scanned * $max_scan_segments) >= 1)) { + // file likely contains < $max_frames_scan, just scan as one segment + $max_scan_segments = 1; + $frames_scan_per_segment = $max_frames_scan; + } else { + $pct_data_scanned += $this_pct_scanned; + break; + } + } + } + } + if ($pct_data_scanned > 0) { + $info['warning'][] = 'too many MPEG audio frames to scan, only scanned '.$frames_scanned.' frames in '.$max_scan_segments.' segments ('.number_format($pct_data_scanned * 100, 1).'% of file) and extrapolated distribution, playtime and bitrate may be incorrect.'; + foreach ($info['mpeg']['audio'] as $key1 => $value1) { + if (!preg_match('#_distribution$#i', $key1)) { + continue; + } + foreach ($value1 as $key2 => $value2) { + $info['mpeg']['audio'][$key1][$key2] = round($value2 / $pct_data_scanned); + } + } + } + + if ($SynchErrorsFound > 0) { + $info['warning'][] = 'Found '.$SynchErrorsFound.' synch errors in histogram analysis'; + //return false; + } + + $bittotal = 0; + $framecounter = 0; + foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitratevalue => $bitratecount) { + $framecounter += $bitratecount; + if ($bitratevalue != 'free') { + $bittotal += ($bitratevalue * $bitratecount); + } + } + if ($framecounter == 0) { + $info['error'][] = 'Corrupt MP3 file: framecounter == zero'; + return false; + } + $info['mpeg']['audio']['frame_count'] = getid3_lib::CastAsInt($framecounter); + $info['mpeg']['audio']['bitrate'] = ($bittotal / $framecounter); + + $info['audio']['bitrate'] = $info['mpeg']['audio']['bitrate']; + + + // Definitively set VBR vs CBR, even if the Xing/LAME/VBRI header says differently + $distinct_bitrates = 0; + foreach ($info['mpeg']['audio']['bitrate_distribution'] as $bitrate_value => $bitrate_count) { + if ($bitrate_count > 0) { + $distinct_bitrates++; + } + } + if ($distinct_bitrates > 1) { + $info['mpeg']['audio']['bitrate_mode'] = 'vbr'; + } else { + $info['mpeg']['audio']['bitrate_mode'] = 'cbr'; + } + $info['audio']['bitrate_mode'] = $info['mpeg']['audio']['bitrate_mode']; + + } + + break; // exit while() + } + } + + $SynchSeekOffset++; + if (($avdataoffset + $SynchSeekOffset) >= $info['avdataend']) { + // end of file/data + + if (empty($info['mpeg']['audio'])) { + + $info['error'][] = 'could not find valid MPEG synch before end of file'; + if (isset($info['audio']['bitrate'])) { + unset($info['audio']['bitrate']); + } + if (isset($info['mpeg']['audio'])) { + unset($info['mpeg']['audio']); + } + if (isset($info['mpeg']) && (!is_array($info['mpeg']) || empty($info['mpeg']))) { + unset($info['mpeg']); + } + return false; + + } + break; + } + + } + $info['audio']['channels'] = $info['mpeg']['audio']['channels']; + $info['audio']['channelmode'] = $info['mpeg']['audio']['channelmode']; + $info['audio']['sample_rate'] = $info['mpeg']['audio']['sample_rate']; + return true; + } + + + public static function MPEGaudioVersionArray() { + static $MPEGaudioVersion = array('2.5', false, '2', '1'); + return $MPEGaudioVersion; + } + + public static function MPEGaudioLayerArray() { + static $MPEGaudioLayer = array(false, 3, 2, 1); + return $MPEGaudioLayer; + } + + public static function MPEGaudioBitrateArray() { + static $MPEGaudioBitrate; + if (empty($MPEGaudioBitrate)) { + $MPEGaudioBitrate = array ( + '1' => array (1 => array('free', 32000, 64000, 96000, 128000, 160000, 192000, 224000, 256000, 288000, 320000, 352000, 384000, 416000, 448000), + 2 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000, 384000), + 3 => array('free', 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 160000, 192000, 224000, 256000, 320000) + ), + + '2' => array (1 => array('free', 32000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000, 176000, 192000, 224000, 256000), + 2 => array('free', 8000, 16000, 24000, 32000, 40000, 48000, 56000, 64000, 80000, 96000, 112000, 128000, 144000, 160000), + ) + ); + $MPEGaudioBitrate['2'][3] = $MPEGaudioBitrate['2'][2]; + $MPEGaudioBitrate['2.5'] = $MPEGaudioBitrate['2']; + } + return $MPEGaudioBitrate; + } + + public static function MPEGaudioFrequencyArray() { + static $MPEGaudioFrequency; + if (empty($MPEGaudioFrequency)) { + $MPEGaudioFrequency = array ( + '1' => array(44100, 48000, 32000), + '2' => array(22050, 24000, 16000), + '2.5' => array(11025, 12000, 8000) + ); + } + return $MPEGaudioFrequency; + } + + public static function MPEGaudioChannelModeArray() { + static $MPEGaudioChannelMode = array('stereo', 'joint stereo', 'dual channel', 'mono'); + return $MPEGaudioChannelMode; + } + + public static function MPEGaudioModeExtensionArray() { + static $MPEGaudioModeExtension; + if (empty($MPEGaudioModeExtension)) { + $MPEGaudioModeExtension = array ( + 1 => array('4-31', '8-31', '12-31', '16-31'), + 2 => array('4-31', '8-31', '12-31', '16-31'), + 3 => array('', 'IS', 'MS', 'IS+MS') + ); + } + return $MPEGaudioModeExtension; + } + + public static function MPEGaudioEmphasisArray() { + static $MPEGaudioEmphasis = array('none', '50/15ms', false, 'CCIT J.17'); + return $MPEGaudioEmphasis; + } + + public static function MPEGaudioHeaderBytesValid($head4, $allowBitrate15=false) { + return self::MPEGaudioHeaderValid(self::MPEGaudioHeaderDecode($head4), false, $allowBitrate15); + } + + public static function MPEGaudioHeaderValid($rawarray, $echoerrors=false, $allowBitrate15=false) { + if (($rawarray['synch'] & 0x0FFE) != 0x0FFE) { + return false; + } + + static $MPEGaudioVersionLookup; + static $MPEGaudioLayerLookup; + static $MPEGaudioBitrateLookup; + static $MPEGaudioFrequencyLookup; + static $MPEGaudioChannelModeLookup; + static $MPEGaudioModeExtensionLookup; + static $MPEGaudioEmphasisLookup; + if (empty($MPEGaudioVersionLookup)) { + $MPEGaudioVersionLookup = self::MPEGaudioVersionArray(); + $MPEGaudioLayerLookup = self::MPEGaudioLayerArray(); + $MPEGaudioBitrateLookup = self::MPEGaudioBitrateArray(); + $MPEGaudioFrequencyLookup = self::MPEGaudioFrequencyArray(); + $MPEGaudioChannelModeLookup = self::MPEGaudioChannelModeArray(); + $MPEGaudioModeExtensionLookup = self::MPEGaudioModeExtensionArray(); + $MPEGaudioEmphasisLookup = self::MPEGaudioEmphasisArray(); + } + + if (isset($MPEGaudioVersionLookup[$rawarray['version']])) { + $decodedVersion = $MPEGaudioVersionLookup[$rawarray['version']]; + } else { + echo ($echoerrors ? "\n".'invalid Version ('.$rawarray['version'].')' : ''); + return false; + } + if (isset($MPEGaudioLayerLookup[$rawarray['layer']])) { + $decodedLayer = $MPEGaudioLayerLookup[$rawarray['layer']]; + } else { + echo ($echoerrors ? "\n".'invalid Layer ('.$rawarray['layer'].')' : ''); + return false; + } + if (!isset($MPEGaudioBitrateLookup[$decodedVersion][$decodedLayer][$rawarray['bitrate']])) { + echo ($echoerrors ? "\n".'invalid Bitrate ('.$rawarray['bitrate'].')' : ''); + if ($rawarray['bitrate'] == 15) { + // known issue in LAME 3.90 - 3.93.1 where free-format has bitrate ID of 15 instead of 0 + // let it go through here otherwise file will not be identified + if (!$allowBitrate15) { + return false; + } + } else { + return false; + } + } + if (!isset($MPEGaudioFrequencyLookup[$decodedVersion][$rawarray['sample_rate']])) { + echo ($echoerrors ? "\n".'invalid Frequency ('.$rawarray['sample_rate'].')' : ''); + return false; + } + if (!isset($MPEGaudioChannelModeLookup[$rawarray['channelmode']])) { + echo ($echoerrors ? "\n".'invalid ChannelMode ('.$rawarray['channelmode'].')' : ''); + return false; + } + if (!isset($MPEGaudioModeExtensionLookup[$decodedLayer][$rawarray['modeextension']])) { + echo ($echoerrors ? "\n".'invalid Mode Extension ('.$rawarray['modeextension'].')' : ''); + return false; + } + if (!isset($MPEGaudioEmphasisLookup[$rawarray['emphasis']])) { + echo ($echoerrors ? "\n".'invalid Emphasis ('.$rawarray['emphasis'].')' : ''); + return false; + } + // These are just either set or not set, you can't mess that up :) + // $rawarray['protection']; + // $rawarray['padding']; + // $rawarray['private']; + // $rawarray['copyright']; + // $rawarray['original']; + + return true; + } + + public static function MPEGaudioHeaderDecode($Header4Bytes) { + // AAAA AAAA AAAB BCCD EEEE FFGH IIJJ KLMM + // A - Frame sync (all bits set) + // B - MPEG Audio version ID + // C - Layer description + // D - Protection bit + // E - Bitrate index + // F - Sampling rate frequency index + // G - Padding bit + // H - Private bit + // I - Channel Mode + // J - Mode extension (Only if Joint stereo) + // K - Copyright + // L - Original + // M - Emphasis + + if (strlen($Header4Bytes) != 4) { + return false; + } + + $MPEGrawHeader['synch'] = (getid3_lib::BigEndian2Int(substr($Header4Bytes, 0, 2)) & 0xFFE0) >> 4; + $MPEGrawHeader['version'] = (ord($Header4Bytes{1}) & 0x18) >> 3; // BB + $MPEGrawHeader['layer'] = (ord($Header4Bytes{1}) & 0x06) >> 1; // CC + $MPEGrawHeader['protection'] = (ord($Header4Bytes{1}) & 0x01); // D + $MPEGrawHeader['bitrate'] = (ord($Header4Bytes{2}) & 0xF0) >> 4; // EEEE + $MPEGrawHeader['sample_rate'] = (ord($Header4Bytes{2}) & 0x0C) >> 2; // FF + $MPEGrawHeader['padding'] = (ord($Header4Bytes{2}) & 0x02) >> 1; // G + $MPEGrawHeader['private'] = (ord($Header4Bytes{2}) & 0x01); // H + $MPEGrawHeader['channelmode'] = (ord($Header4Bytes{3}) & 0xC0) >> 6; // II + $MPEGrawHeader['modeextension'] = (ord($Header4Bytes{3}) & 0x30) >> 4; // JJ + $MPEGrawHeader['copyright'] = (ord($Header4Bytes{3}) & 0x08) >> 3; // K + $MPEGrawHeader['original'] = (ord($Header4Bytes{3}) & 0x04) >> 2; // L + $MPEGrawHeader['emphasis'] = (ord($Header4Bytes{3}) & 0x03); // MM + + return $MPEGrawHeader; + } + + public static function MPEGaudioFrameLength(&$bitrate, &$version, &$layer, $padding, &$samplerate) { + static $AudioFrameLengthCache = array(); + + if (!isset($AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate])) { + $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = false; + if ($bitrate != 'free') { + + if ($version == '1') { + + if ($layer == '1') { + + // For Layer I slot is 32 bits long + $FrameLengthCoefficient = 48; + $SlotLength = 4; + + } else { // Layer 2 / 3 + + // for Layer 2 and Layer 3 slot is 8 bits long. + $FrameLengthCoefficient = 144; + $SlotLength = 1; + + } + + } else { // MPEG-2 / MPEG-2.5 + + if ($layer == '1') { + + // For Layer I slot is 32 bits long + $FrameLengthCoefficient = 24; + $SlotLength = 4; + + } elseif ($layer == '2') { + + // for Layer 2 and Layer 3 slot is 8 bits long. + $FrameLengthCoefficient = 144; + $SlotLength = 1; + + } else { // layer 3 + + // for Layer 2 and Layer 3 slot is 8 bits long. + $FrameLengthCoefficient = 72; + $SlotLength = 1; + + } + + } + + // FrameLengthInBytes = ((Coefficient * BitRate) / SampleRate) + Padding + if ($samplerate > 0) { + $NewFramelength = ($FrameLengthCoefficient * $bitrate) / $samplerate; + $NewFramelength = floor($NewFramelength / $SlotLength) * $SlotLength; // round to next-lower multiple of SlotLength (1 byte for Layer 2/3, 4 bytes for Layer I) + if ($padding) { + $NewFramelength += $SlotLength; + } + $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate] = (int) $NewFramelength; + } + } + } + return $AudioFrameLengthCache[$bitrate][$version][$layer][$padding][$samplerate]; + } + + public static function ClosestStandardMP3Bitrate($bit_rate) { + static $standard_bit_rates = array (320000, 256000, 224000, 192000, 160000, 128000, 112000, 96000, 80000, 64000, 56000, 48000, 40000, 32000, 24000, 16000, 8000); + static $bit_rate_table = array (0=>'-'); + $round_bit_rate = intval(round($bit_rate, -3)); + if (!isset($bit_rate_table[$round_bit_rate])) { + if ($round_bit_rate > max($standard_bit_rates)) { + $bit_rate_table[$round_bit_rate] = round($bit_rate, 2 - strlen($bit_rate)); + } else { + $bit_rate_table[$round_bit_rate] = max($standard_bit_rates); + foreach ($standard_bit_rates as $standard_bit_rate) { + if ($round_bit_rate >= $standard_bit_rate + (($bit_rate_table[$round_bit_rate] - $standard_bit_rate) / 2)) { + break; + } + $bit_rate_table[$round_bit_rate] = $standard_bit_rate; + } + } + } + return $bit_rate_table[$round_bit_rate]; + } + + public static function XingVBRidOffset($version, $channelmode) { + static $XingVBRidOffsetCache = array(); + if (empty($XingVBRidOffset)) { + $XingVBRidOffset = array ( + '1' => array ('mono' => 0x15, // 4 + 17 = 21 + 'stereo' => 0x24, // 4 + 32 = 36 + 'joint stereo' => 0x24, + 'dual channel' => 0x24 + ), + + '2' => array ('mono' => 0x0D, // 4 + 9 = 13 + 'stereo' => 0x15, // 4 + 17 = 21 + 'joint stereo' => 0x15, + 'dual channel' => 0x15 + ), + + '2.5' => array ('mono' => 0x15, + 'stereo' => 0x15, + 'joint stereo' => 0x15, + 'dual channel' => 0x15 + ) + ); + } + return $XingVBRidOffset[$version][$channelmode]; + } + + public static function LAMEvbrMethodLookup($VBRmethodID) { + static $LAMEvbrMethodLookup = array( + 0x00 => 'unknown', + 0x01 => 'cbr', + 0x02 => 'abr', + 0x03 => 'vbr-old / vbr-rh', + 0x04 => 'vbr-new / vbr-mtrh', + 0x05 => 'vbr-mt', + 0x06 => 'vbr (full vbr method 4)', + 0x08 => 'cbr (constant bitrate 2 pass)', + 0x09 => 'abr (2 pass)', + 0x0F => 'reserved' + ); + return (isset($LAMEvbrMethodLookup[$VBRmethodID]) ? $LAMEvbrMethodLookup[$VBRmethodID] : ''); + } + + public static function LAMEmiscStereoModeLookup($StereoModeID) { + static $LAMEmiscStereoModeLookup = array( + 0 => 'mono', + 1 => 'stereo', + 2 => 'dual mono', + 3 => 'joint stereo', + 4 => 'forced stereo', + 5 => 'auto', + 6 => 'intensity stereo', + 7 => 'other' + ); + return (isset($LAMEmiscStereoModeLookup[$StereoModeID]) ? $LAMEmiscStereoModeLookup[$StereoModeID] : ''); + } + + public static function LAMEmiscSourceSampleFrequencyLookup($SourceSampleFrequencyID) { + static $LAMEmiscSourceSampleFrequencyLookup = array( + 0 => '<= 32 kHz', + 1 => '44.1 kHz', + 2 => '48 kHz', + 3 => '> 48kHz' + ); + return (isset($LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID]) ? $LAMEmiscSourceSampleFrequencyLookup[$SourceSampleFrequencyID] : ''); + } + + public static function LAMEsurroundInfoLookup($SurroundInfoID) { + static $LAMEsurroundInfoLookup = array( + 0 => 'no surround info', + 1 => 'DPL encoding', + 2 => 'DPL2 encoding', + 3 => 'Ambisonic encoding' + ); + return (isset($LAMEsurroundInfoLookup[$SurroundInfoID]) ? $LAMEsurroundInfoLookup[$SurroundInfoID] : 'reserved'); + } + + public static function LAMEpresetUsedLookup($LAMEtag) { + + if ($LAMEtag['preset_used_id'] == 0) { + // no preset used (LAME >=3.93) + // no preset recorded (LAME <3.93) + return ''; + } + $LAMEpresetUsedLookup = array(); + + ///// THIS PART CANNOT BE STATIC . + for ($i = 8; $i <= 320; $i++) { + switch ($LAMEtag['vbr_method']) { + case 'cbr': + $LAMEpresetUsedLookup[$i] = '--alt-preset '.$LAMEtag['vbr_method'].' '.$i; + break; + case 'abr': + default: // other VBR modes shouldn't be here(?) + $LAMEpresetUsedLookup[$i] = '--alt-preset '.$i; + break; + } + } + + // named old-style presets (studio, phone, voice, etc) are handled in GuessEncoderOptions() + + // named alt-presets + $LAMEpresetUsedLookup[1000] = '--r3mix'; + $LAMEpresetUsedLookup[1001] = '--alt-preset standard'; + $LAMEpresetUsedLookup[1002] = '--alt-preset extreme'; + $LAMEpresetUsedLookup[1003] = '--alt-preset insane'; + $LAMEpresetUsedLookup[1004] = '--alt-preset fast standard'; + $LAMEpresetUsedLookup[1005] = '--alt-preset fast extreme'; + $LAMEpresetUsedLookup[1006] = '--alt-preset medium'; + $LAMEpresetUsedLookup[1007] = '--alt-preset fast medium'; + + // LAME 3.94 additions/changes + $LAMEpresetUsedLookup[1010] = '--preset portable'; // 3.94a15 Oct 21 2003 + $LAMEpresetUsedLookup[1015] = '--preset radio'; // 3.94a15 Oct 21 2003 + + $LAMEpresetUsedLookup[320] = '--preset insane'; // 3.94a15 Nov 12 2003 + $LAMEpresetUsedLookup[410] = '-V9'; + $LAMEpresetUsedLookup[420] = '-V8'; + $LAMEpresetUsedLookup[440] = '-V6'; + $LAMEpresetUsedLookup[430] = '--preset radio'; // 3.94a15 Nov 12 2003 + $LAMEpresetUsedLookup[450] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'portable'; // 3.94a15 Nov 12 2003 + $LAMEpresetUsedLookup[460] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'medium'; // 3.94a15 Nov 12 2003 + $LAMEpresetUsedLookup[470] = '--r3mix'; // 3.94b1 Dec 18 2003 + $LAMEpresetUsedLookup[480] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'standard'; // 3.94a15 Nov 12 2003 + $LAMEpresetUsedLookup[490] = '-V1'; + $LAMEpresetUsedLookup[500] = '--preset '.(($LAMEtag['raw']['vbr_method'] == 4) ? 'fast ' : '').'extreme'; // 3.94a15 Nov 12 2003 + + return (isset($LAMEpresetUsedLookup[$LAMEtag['preset_used_id']]) ? $LAMEpresetUsedLookup[$LAMEtag['preset_used_id']] : 'new/unknown preset: '.$LAMEtag['preset_used_id'].' - report to info@getid3.org'); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.mpc.php b/app/libs/vendor/getid3/module.audio.mpc.php index 1264022f..8ab421eb 100644 --- a/app/libs/vendor/getid3/module.audio.mpc.php +++ b/app/libs/vendor/getid3/module.audio.mpc.php @@ -1,506 +1,506 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.mpc.php // -// module for analyzing Musepack/MPEG+ Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_mpc extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['mpc']['header'] = array(); - $thisfile_mpc_header = &$info['mpc']['header']; - - $info['fileformat'] = 'mpc'; - $info['audio']['dataformat'] = 'mpc'; - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['channels'] = 2; // up to SV7 the format appears to have been hardcoded for stereo only - $info['audio']['lossless'] = false; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $MPCheaderData = fread($this->getid3->fp, 4); - $info['mpc']['header']['preamble'] = substr($MPCheaderData, 0, 4); // should be 'MPCK' (SV8) or 'MP+' (SV7), otherwise possible stream data (SV4-SV6) - if (preg_match('#^MPCK#', $info['mpc']['header']['preamble'])) { - - // this is SV8 - return $this->ParseMPCsv8(); - - } elseif (preg_match('#^MP\+#', $info['mpc']['header']['preamble'])) { - - // this is SV7 - return $this->ParseMPCsv7(); - - } elseif (preg_match('/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) { - - // this is SV4 - SV6, handle seperately - return $this->ParseMPCsv6(); - - } else { - - $info['error'][] = 'Expecting "MP+" or "MPCK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($MPCheaderData, 0, 4)).'"'; - unset($info['fileformat']); - unset($info['mpc']); - return false; - - } - return false; - } - - - public function ParseMPCsv8() { - // this is SV8 - // http://trac.musepack.net/trac/wiki/SV8Specification - - $info = &$this->getid3->info; - $thisfile_mpc_header = &$info['mpc']['header']; - - $keyNameSize = 2; - $maxHandledPacketLength = 9; // specs say: "n*8; 0 < n < 10" - - $offset = ftell($this->getid3->fp); - while ($offset < $info['avdataend']) { - $thisPacket = array(); - $thisPacket['offset'] = $offset; - $packet_offset = 0; - - // Size is a variable-size field, could be 1-4 bytes (possibly more?) - // read enough data in and figure out the exact size later - $MPCheaderData = fread($this->getid3->fp, $keyNameSize + $maxHandledPacketLength); - $packet_offset += $keyNameSize; - $thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize); - $thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']); - if ($thisPacket['key'] == $thisPacket['key_name']) { - $info['error'][] = 'Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']; - return false; - } - $packetLength = 0; - $thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field - if ($thisPacket['packet_size'] === false) { - $info['error'][] = 'Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize); - return false; - } - $packet_offset += $packetLength; - $offset += $thisPacket['packet_size']; - - switch ($thisPacket['key']) { - case 'SH': // Stream Header - $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; - if ($moreBytesToRead > 0) { - $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); - } - $thisPacket['crc'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 4)); - $packet_offset += 4; - $thisPacket['stream_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - - $packetLength = 0; - $thisPacket['sample_count'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); - $packet_offset += $packetLength; - - $packetLength = 0; - $thisPacket['beginning_silence'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); - $packet_offset += $packetLength; - - $otherUsefulData = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); - $packet_offset += 2; - $thisPacket['sample_frequency_raw'] = (($otherUsefulData & 0xE000) >> 13); - $thisPacket['max_bands_used'] = (($otherUsefulData & 0x1F00) >> 8); - $thisPacket['channels'] = (($otherUsefulData & 0x00F0) >> 4) + 1; - $thisPacket['ms_used'] = (bool) (($otherUsefulData & 0x0008) >> 3); - $thisPacket['audio_block_frames'] = (($otherUsefulData & 0x0007) >> 0); - $thisPacket['sample_frequency'] = $this->MPCfrequencyLookup($thisPacket['sample_frequency_raw']); - - $thisfile_mpc_header['mid_side_stereo'] = $thisPacket['ms_used']; - $thisfile_mpc_header['sample_rate'] = $thisPacket['sample_frequency']; - $thisfile_mpc_header['samples'] = $thisPacket['sample_count']; - $thisfile_mpc_header['stream_version_major'] = $thisPacket['stream_version']; - - $info['audio']['channels'] = $thisPacket['channels']; - $info['audio']['sample_rate'] = $thisPacket['sample_frequency']; - $info['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - break; - - case 'RG': // Replay Gain - $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; - if ($moreBytesToRead > 0) { - $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); - } - $thisPacket['replaygain_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - $thisPacket['replaygain_title_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); - $packet_offset += 2; - $thisPacket['replaygain_title_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); - $packet_offset += 2; - $thisPacket['replaygain_album_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); - $packet_offset += 2; - $thisPacket['replaygain_album_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); - $packet_offset += 2; - - if ($thisPacket['replaygain_title_gain']) { $info['replay_gain']['title']['gain'] = $thisPacket['replaygain_title_gain']; } - if ($thisPacket['replaygain_title_peak']) { $info['replay_gain']['title']['peak'] = $thisPacket['replaygain_title_peak']; } - if ($thisPacket['replaygain_album_gain']) { $info['replay_gain']['album']['gain'] = $thisPacket['replaygain_album_gain']; } - if ($thisPacket['replaygain_album_peak']) { $info['replay_gain']['album']['peak'] = $thisPacket['replaygain_album_peak']; } - break; - - case 'EI': // Encoder Info - $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; - if ($moreBytesToRead > 0) { - $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); - } - $profile_pns = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - $quality_int = (($profile_pns & 0xF0) >> 4); - $quality_dec = (($profile_pns & 0x0E) >> 3); - $thisPacket['quality'] = (float) $quality_int + ($quality_dec / 8); - $thisPacket['pns_tool'] = (bool) (($profile_pns & 0x01) >> 0); - $thisPacket['version_major'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - $thisPacket['version_minor'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - $thisPacket['version_build'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); - $packet_offset += 1; - $thisPacket['version'] = $thisPacket['version_major'].'.'.$thisPacket['version_minor'].'.'.$thisPacket['version_build']; - - $info['audio']['encoder'] = 'MPC v'.$thisPacket['version'].' ('.(($thisPacket['version_minor'] % 2) ? 'unstable' : 'stable').')'; - $thisfile_mpc_header['encoder_version'] = $info['audio']['encoder']; - //$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] / 1.5875); // values can range from 0.000 to 15.875, mapped to qualities of 0.0 to 10.0 - $thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] - 5); // values can range from 0.000 to 15.875, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0 - break; - - case 'SO': // Seek Table Offset - $packetLength = 0; - $thisPacket['seek_table_offset'] = $thisPacket['offset'] + $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); - $packet_offset += $packetLength; - break; - - case 'ST': // Seek Table - case 'SE': // Stream End - case 'AP': // Audio Data - // nothing useful here, just skip this packet - $thisPacket = array(); - break; - - default: - $info['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']; - return false; - break; - } - if (!empty($thisPacket)) { - $info['mpc']['packets'][] = $thisPacket; - } - fseek($this->getid3->fp, $offset); - } - $thisfile_mpc_header['size'] = $offset; - return true; - } - - public function ParseMPCsv7() { - // this is SV7 - // http://www.uni-jena.de/~pfk/mpp/sv8/header.html - - $info = &$this->getid3->info; - $thisfile_mpc_header = &$info['mpc']['header']; - $offset = 0; - - $thisfile_mpc_header['size'] = 28; - $MPCheaderData = $info['mpc']['header']['preamble']; - $MPCheaderData .= fread($this->getid3->fp, $thisfile_mpc_header['size'] - strlen($info['mpc']['header']['preamble'])); - $offset = strlen('MP+'); - - $StreamVersionByte = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1)); - $offset += 1; - $thisfile_mpc_header['stream_version_major'] = ($StreamVersionByte & 0x0F) >> 0; - $thisfile_mpc_header['stream_version_minor'] = ($StreamVersionByte & 0xF0) >> 4; // should always be 0, subversions no longer exist in SV8 - $thisfile_mpc_header['frame_count'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); - $offset += 4; - - if ($thisfile_mpc_header['stream_version_major'] != 7) { - $info['error'][] = 'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')'; - return false; - } - - $FlagsDWORD1 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); - $offset += 4; - $thisfile_mpc_header['intensity_stereo'] = (bool) (($FlagsDWORD1 & 0x80000000) >> 31); - $thisfile_mpc_header['mid_side_stereo'] = (bool) (($FlagsDWORD1 & 0x40000000) >> 30); - $thisfile_mpc_header['max_subband'] = ($FlagsDWORD1 & 0x3F000000) >> 24; - $thisfile_mpc_header['raw']['profile'] = ($FlagsDWORD1 & 0x00F00000) >> 20; - $thisfile_mpc_header['begin_loud'] = (bool) (($FlagsDWORD1 & 0x00080000) >> 19); - $thisfile_mpc_header['end_loud'] = (bool) (($FlagsDWORD1 & 0x00040000) >> 18); - $thisfile_mpc_header['raw']['sample_rate'] = ($FlagsDWORD1 & 0x00030000) >> 16; - $thisfile_mpc_header['max_level'] = ($FlagsDWORD1 & 0x0000FFFF); - - $thisfile_mpc_header['raw']['title_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2)); - $offset += 2; - $thisfile_mpc_header['raw']['title_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true); - $offset += 2; - - $thisfile_mpc_header['raw']['album_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2)); - $offset += 2; - $thisfile_mpc_header['raw']['album_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true); - $offset += 2; - - $FlagsDWORD2 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); - $offset += 4; - $thisfile_mpc_header['true_gapless'] = (bool) (($FlagsDWORD2 & 0x80000000) >> 31); - $thisfile_mpc_header['last_frame_length'] = ($FlagsDWORD2 & 0x7FF00000) >> 20; - - - $thisfile_mpc_header['raw']['not_sure_what'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 3)); - $offset += 3; - $thisfile_mpc_header['raw']['encoder_version'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1)); - $offset += 1; - - $thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']); - $thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']); - if ($thisfile_mpc_header['sample_rate'] == 0) { - $info['error'][] = 'Corrupt MPC file: frequency == zero'; - return false; - } - $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; - $thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $info['audio']['channels']; - - $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate']; - if ($info['playtime_seconds'] == 0) { - $info['error'][] = 'Corrupt MPC file: playtime_seconds == zero'; - return false; - } - - // add size of file header to avdataoffset - calc bitrate correctly + MD5 data - $info['avdataoffset'] += $thisfile_mpc_header['size']; - - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - $thisfile_mpc_header['title_peak'] = $thisfile_mpc_header['raw']['title_peak']; - $thisfile_mpc_header['title_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['title_peak']); - if ($thisfile_mpc_header['raw']['title_gain'] < 0) { - $thisfile_mpc_header['title_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['title_gain']) / -100; - } else { - $thisfile_mpc_header['title_gain_db'] = (float) $thisfile_mpc_header['raw']['title_gain'] / 100; - } - - $thisfile_mpc_header['album_peak'] = $thisfile_mpc_header['raw']['album_peak']; - $thisfile_mpc_header['album_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['album_peak']); - if ($thisfile_mpc_header['raw']['album_gain'] < 0) { - $thisfile_mpc_header['album_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['album_gain']) / -100; - } else { - $thisfile_mpc_header['album_gain_db'] = (float) $thisfile_mpc_header['raw']['album_gain'] / 100;; - } - $thisfile_mpc_header['encoder_version'] = $this->MPCencoderVersionLookup($thisfile_mpc_header['raw']['encoder_version']); - - $info['replay_gain']['track']['adjustment'] = $thisfile_mpc_header['title_gain_db']; - $info['replay_gain']['album']['adjustment'] = $thisfile_mpc_header['album_gain_db']; - - if ($thisfile_mpc_header['title_peak'] > 0) { - $info['replay_gain']['track']['peak'] = $thisfile_mpc_header['title_peak']; - } elseif (round($thisfile_mpc_header['max_level'] * 1.18) > 0) { - $info['replay_gain']['track']['peak'] = getid3_lib::CastAsInt(round($thisfile_mpc_header['max_level'] * 1.18)); // why? I don't know - see mppdec.c - } - if ($thisfile_mpc_header['album_peak'] > 0) { - $info['replay_gain']['album']['peak'] = $thisfile_mpc_header['album_peak']; - } - - //$info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'].'.'.$thisfile_mpc_header['stream_version_minor'].', '.$thisfile_mpc_header['encoder_version']; - $info['audio']['encoder'] = $thisfile_mpc_header['encoder_version']; - $info['audio']['encoder_options'] = $thisfile_mpc_header['profile']; - $thisfile_mpc_header['quality'] = (float) ($thisfile_mpc_header['raw']['profile'] - 5); // values can range from 0 to 15, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0 - - return true; - } - - public function ParseMPCsv6() { - // this is SV4 - SV6 - - $info = &$this->getid3->info; - $thisfile_mpc_header = &$info['mpc']['header']; - $offset = 0; - - $thisfile_mpc_header['size'] = 8; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $MPCheaderData = fread($this->getid3->fp, $thisfile_mpc_header['size']); - - // add size of file header to avdataoffset - calc bitrate correctly + MD5 data - $info['avdataoffset'] += $thisfile_mpc_header['size']; - - // Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :) - $HeaderDWORD[0] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 0, 4)); - $HeaderDWORD[1] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 4, 4)); - - - // DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA - // aaaa aaaa abcd dddd dddd deee eeff ffff - // - // a = bitrate = anything - // b = IS = anything - // c = MS = anything - // d = streamversion = 0000000004 or 0000000005 or 0000000006 - // e = maxband = anything - // f = blocksize = 000001 for SV5+, anything(?) for SV4 - - $thisfile_mpc_header['target_bitrate'] = (($HeaderDWORD[0] & 0xFF800000) >> 23); - $thisfile_mpc_header['intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x00400000) >> 22); - $thisfile_mpc_header['mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x00200000) >> 21); - $thisfile_mpc_header['stream_version_major'] = ($HeaderDWORD[0] & 0x001FF800) >> 11; - $thisfile_mpc_header['stream_version_minor'] = 0; // no sub-version numbers before SV7 - $thisfile_mpc_header['max_band'] = ($HeaderDWORD[0] & 0x000007C0) >> 6; // related to lowpass frequency, not sure how it translates exactly - $thisfile_mpc_header['block_size'] = ($HeaderDWORD[0] & 0x0000003F); - - switch ($thisfile_mpc_header['stream_version_major']) { - case 4: - $thisfile_mpc_header['frame_count'] = ($HeaderDWORD[1] >> 16); - break; - - case 5: - case 6: - $thisfile_mpc_header['frame_count'] = $HeaderDWORD[1]; - break; - - default: - $info['error'] = 'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header['stream_version_major'].' instead'; - unset($info['mpc']); - return false; - break; - } - - if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) { - $info['warning'][] = 'Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size']; - } - - $thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7 - $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; - $thisfile_mpc_header['samples'] = $thisfile_mpc_header['frame_count'] * 1152 * $info['audio']['channels']; - - if ($thisfile_mpc_header['target_bitrate'] == 0) { - $info['audio']['bitrate_mode'] = 'vbr'; - } else { - $info['audio']['bitrate_mode'] = 'cbr'; - } - - $info['mpc']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 * 44100 / $thisfile_mpc_header['frame_count'] / 1152; - $info['audio']['bitrate'] = $info['mpc']['bitrate']; - $info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major']; - - return true; - } - - - public function MPCprofileNameLookup($profileid) { - static $MPCprofileNameLookup = array( - 0 => 'no profile', - 1 => 'Experimental', - 2 => 'unused', - 3 => 'unused', - 4 => 'unused', - 5 => 'below Telephone (q = 0.0)', - 6 => 'below Telephone (q = 1.0)', - 7 => 'Telephone (q = 2.0)', - 8 => 'Thumb (q = 3.0)', - 9 => 'Radio (q = 4.0)', - 10 => 'Standard (q = 5.0)', - 11 => 'Extreme (q = 6.0)', - 12 => 'Insane (q = 7.0)', - 13 => 'BrainDead (q = 8.0)', - 14 => 'above BrainDead (q = 9.0)', - 15 => 'above BrainDead (q = 10.0)' - ); - return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid'); - } - - public function MPCfrequencyLookup($frequencyid) { - static $MPCfrequencyLookup = array( - 0 => 44100, - 1 => 48000, - 2 => 37800, - 3 => 32000 - ); - return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid'); - } - - public function MPCpeakDBLookup($intvalue) { - if ($intvalue > 0) { - return ((log10($intvalue) / log10(2)) - 15) * 6; - } - return false; - } - - public function MPCencoderVersionLookup($encoderversion) { - //Encoder version * 100 (106 = 1.06) - //EncoderVersion % 10 == 0 Release (1.0) - //EncoderVersion % 2 == 0 Beta (1.06) - //EncoderVersion % 2 == 1 Alpha (1.05a...z) - - if ($encoderversion == 0) { - // very old version, not known exactly which - return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05'; - } - - if (($encoderversion % 10) == 0) { - - // release version - return number_format($encoderversion / 100, 2); - - } elseif (($encoderversion % 2) == 0) { - - // beta version - return number_format($encoderversion / 100, 2).' beta'; - - } - - // alpha version - return number_format($encoderversion / 100, 2).' alpha'; - } - - public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) { - $packet_size = 0; - for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) { - // variable-length size field: - // bits, big-endian - // 0xxx xxxx - value 0 to 2^7-1 - // 1xxx xxxx 0xxx xxxx - value 0 to 2^14-1 - // 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^21-1 - // 1xxx xxxx 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^28-1 - // ... - $thisbyte = ord(substr($data, ($packetLength - 1), 1)); - // look through bytes until find a byte with MSB==0 - $packet_size = ($packet_size << 7); - $packet_size = ($packet_size | ($thisbyte & 0x7F)); - if (($thisbyte & 0x80) === 0) { - break; - } - if ($packetLength >= $maxHandledPacketLength) { - return false; - } - } - return $packet_size; - } - - public function MPCsv8PacketName($packetKey) { - static $MPCsv8PacketName = array(); - if (empty($MPCsv8PacketName)) { - $MPCsv8PacketName = array( - 'AP' => 'Audio Packet', - 'CT' => 'Chapter Tag', - 'EI' => 'Encoder Info', - 'RG' => 'Replay Gain', - 'SE' => 'Stream End', - 'SH' => 'Stream Header', - 'SO' => 'Seek Table Offset', - 'ST' => 'Seek Table', - ); - } - return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey); - } -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.mpc.php // +// module for analyzing Musepack/MPEG+ Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_mpc extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['mpc']['header'] = array(); + $thisfile_mpc_header = &$info['mpc']['header']; + + $info['fileformat'] = 'mpc'; + $info['audio']['dataformat'] = 'mpc'; + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['channels'] = 2; // up to SV7 the format appears to have been hardcoded for stereo only + $info['audio']['lossless'] = false; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $MPCheaderData = fread($this->getid3->fp, 4); + $info['mpc']['header']['preamble'] = substr($MPCheaderData, 0, 4); // should be 'MPCK' (SV8) or 'MP+' (SV7), otherwise possible stream data (SV4-SV6) + if (preg_match('#^MPCK#', $info['mpc']['header']['preamble'])) { + + // this is SV8 + return $this->ParseMPCsv8(); + + } elseif (preg_match('#^MP\+#', $info['mpc']['header']['preamble'])) { + + // this is SV7 + return $this->ParseMPCsv7(); + + } elseif (preg_match('/^[\x00\x01\x10\x11\x40\x41\x50\x51\x80\x81\x90\x91\xC0\xC1\xD0\xD1][\x20-37][\x00\x20\x40\x60\x80\xA0\xC0\xE0]/s', $MPCheaderData)) { + + // this is SV4 - SV6, handle seperately + return $this->ParseMPCsv6(); + + } else { + + $info['error'][] = 'Expecting "MP+" or "MPCK" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($MPCheaderData, 0, 4)).'"'; + unset($info['fileformat']); + unset($info['mpc']); + return false; + + } + return false; + } + + + public function ParseMPCsv8() { + // this is SV8 + // http://trac.musepack.net/trac/wiki/SV8Specification + + $info = &$this->getid3->info; + $thisfile_mpc_header = &$info['mpc']['header']; + + $keyNameSize = 2; + $maxHandledPacketLength = 9; // specs say: "n*8; 0 < n < 10" + + $offset = ftell($this->getid3->fp); + while ($offset < $info['avdataend']) { + $thisPacket = array(); + $thisPacket['offset'] = $offset; + $packet_offset = 0; + + // Size is a variable-size field, could be 1-4 bytes (possibly more?) + // read enough data in and figure out the exact size later + $MPCheaderData = fread($this->getid3->fp, $keyNameSize + $maxHandledPacketLength); + $packet_offset += $keyNameSize; + $thisPacket['key'] = substr($MPCheaderData, 0, $keyNameSize); + $thisPacket['key_name'] = $this->MPCsv8PacketName($thisPacket['key']); + if ($thisPacket['key'] == $thisPacket['key_name']) { + $info['error'][] = 'Found unexpected key value "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']; + return false; + } + $packetLength = 0; + $thisPacket['packet_size'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $keyNameSize), $packetLength); // includes keyname and packet_size field + if ($thisPacket['packet_size'] === false) { + $info['error'][] = 'Did not find expected packet length within '.$maxHandledPacketLength.' bytes at offset '.($thisPacket['offset'] + $keyNameSize); + return false; + } + $packet_offset += $packetLength; + $offset += $thisPacket['packet_size']; + + switch ($thisPacket['key']) { + case 'SH': // Stream Header + $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; + if ($moreBytesToRead > 0) { + $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); + } + $thisPacket['crc'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 4)); + $packet_offset += 4; + $thisPacket['stream_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + + $packetLength = 0; + $thisPacket['sample_count'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); + $packet_offset += $packetLength; + + $packetLength = 0; + $thisPacket['beginning_silence'] = $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); + $packet_offset += $packetLength; + + $otherUsefulData = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); + $packet_offset += 2; + $thisPacket['sample_frequency_raw'] = (($otherUsefulData & 0xE000) >> 13); + $thisPacket['max_bands_used'] = (($otherUsefulData & 0x1F00) >> 8); + $thisPacket['channels'] = (($otherUsefulData & 0x00F0) >> 4) + 1; + $thisPacket['ms_used'] = (bool) (($otherUsefulData & 0x0008) >> 3); + $thisPacket['audio_block_frames'] = (($otherUsefulData & 0x0007) >> 0); + $thisPacket['sample_frequency'] = $this->MPCfrequencyLookup($thisPacket['sample_frequency_raw']); + + $thisfile_mpc_header['mid_side_stereo'] = $thisPacket['ms_used']; + $thisfile_mpc_header['sample_rate'] = $thisPacket['sample_frequency']; + $thisfile_mpc_header['samples'] = $thisPacket['sample_count']; + $thisfile_mpc_header['stream_version_major'] = $thisPacket['stream_version']; + + $info['audio']['channels'] = $thisPacket['channels']; + $info['audio']['sample_rate'] = $thisPacket['sample_frequency']; + $info['playtime_seconds'] = $thisPacket['sample_count'] / $thisPacket['sample_frequency']; + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + break; + + case 'RG': // Replay Gain + $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; + if ($moreBytesToRead > 0) { + $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); + } + $thisPacket['replaygain_version'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + $thisPacket['replaygain_title_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); + $packet_offset += 2; + $thisPacket['replaygain_title_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); + $packet_offset += 2; + $thisPacket['replaygain_album_gain'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); + $packet_offset += 2; + $thisPacket['replaygain_album_peak'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 2)); + $packet_offset += 2; + + if ($thisPacket['replaygain_title_gain']) { $info['replay_gain']['title']['gain'] = $thisPacket['replaygain_title_gain']; } + if ($thisPacket['replaygain_title_peak']) { $info['replay_gain']['title']['peak'] = $thisPacket['replaygain_title_peak']; } + if ($thisPacket['replaygain_album_gain']) { $info['replay_gain']['album']['gain'] = $thisPacket['replaygain_album_gain']; } + if ($thisPacket['replaygain_album_peak']) { $info['replay_gain']['album']['peak'] = $thisPacket['replaygain_album_peak']; } + break; + + case 'EI': // Encoder Info + $moreBytesToRead = $thisPacket['packet_size'] - $keyNameSize - $maxHandledPacketLength; + if ($moreBytesToRead > 0) { + $MPCheaderData .= fread($this->getid3->fp, $moreBytesToRead); + } + $profile_pns = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + $quality_int = (($profile_pns & 0xF0) >> 4); + $quality_dec = (($profile_pns & 0x0E) >> 3); + $thisPacket['quality'] = (float) $quality_int + ($quality_dec / 8); + $thisPacket['pns_tool'] = (bool) (($profile_pns & 0x01) >> 0); + $thisPacket['version_major'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + $thisPacket['version_minor'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + $thisPacket['version_build'] = getid3_lib::BigEndian2Int(substr($MPCheaderData, $packet_offset, 1)); + $packet_offset += 1; + $thisPacket['version'] = $thisPacket['version_major'].'.'.$thisPacket['version_minor'].'.'.$thisPacket['version_build']; + + $info['audio']['encoder'] = 'MPC v'.$thisPacket['version'].' ('.(($thisPacket['version_minor'] % 2) ? 'unstable' : 'stable').')'; + $thisfile_mpc_header['encoder_version'] = $info['audio']['encoder']; + //$thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] / 1.5875); // values can range from 0.000 to 15.875, mapped to qualities of 0.0 to 10.0 + $thisfile_mpc_header['quality'] = (float) ($thisPacket['quality'] - 5); // values can range from 0.000 to 15.875, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0 + break; + + case 'SO': // Seek Table Offset + $packetLength = 0; + $thisPacket['seek_table_offset'] = $thisPacket['offset'] + $this->SV8variableLengthInteger(substr($MPCheaderData, $packet_offset, $maxHandledPacketLength), $packetLength); + $packet_offset += $packetLength; + break; + + case 'ST': // Seek Table + case 'SE': // Stream End + case 'AP': // Audio Data + // nothing useful here, just skip this packet + $thisPacket = array(); + break; + + default: + $info['error'][] = 'Found unhandled key type "'.$thisPacket['key'].'" at offset '.$thisPacket['offset']; + return false; + break; + } + if (!empty($thisPacket)) { + $info['mpc']['packets'][] = $thisPacket; + } + fseek($this->getid3->fp, $offset); + } + $thisfile_mpc_header['size'] = $offset; + return true; + } + + public function ParseMPCsv7() { + // this is SV7 + // http://www.uni-jena.de/~pfk/mpp/sv8/header.html + + $info = &$this->getid3->info; + $thisfile_mpc_header = &$info['mpc']['header']; + $offset = 0; + + $thisfile_mpc_header['size'] = 28; + $MPCheaderData = $info['mpc']['header']['preamble']; + $MPCheaderData .= fread($this->getid3->fp, $thisfile_mpc_header['size'] - strlen($info['mpc']['header']['preamble'])); + $offset = strlen('MP+'); + + $StreamVersionByte = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1)); + $offset += 1; + $thisfile_mpc_header['stream_version_major'] = ($StreamVersionByte & 0x0F) >> 0; + $thisfile_mpc_header['stream_version_minor'] = ($StreamVersionByte & 0xF0) >> 4; // should always be 0, subversions no longer exist in SV8 + $thisfile_mpc_header['frame_count'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); + $offset += 4; + + if ($thisfile_mpc_header['stream_version_major'] != 7) { + $info['error'][] = 'Only Musepack SV7 supported (this file claims to be v'.$thisfile_mpc_header['stream_version_major'].')'; + return false; + } + + $FlagsDWORD1 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); + $offset += 4; + $thisfile_mpc_header['intensity_stereo'] = (bool) (($FlagsDWORD1 & 0x80000000) >> 31); + $thisfile_mpc_header['mid_side_stereo'] = (bool) (($FlagsDWORD1 & 0x40000000) >> 30); + $thisfile_mpc_header['max_subband'] = ($FlagsDWORD1 & 0x3F000000) >> 24; + $thisfile_mpc_header['raw']['profile'] = ($FlagsDWORD1 & 0x00F00000) >> 20; + $thisfile_mpc_header['begin_loud'] = (bool) (($FlagsDWORD1 & 0x00080000) >> 19); + $thisfile_mpc_header['end_loud'] = (bool) (($FlagsDWORD1 & 0x00040000) >> 18); + $thisfile_mpc_header['raw']['sample_rate'] = ($FlagsDWORD1 & 0x00030000) >> 16; + $thisfile_mpc_header['max_level'] = ($FlagsDWORD1 & 0x0000FFFF); + + $thisfile_mpc_header['raw']['title_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2)); + $offset += 2; + $thisfile_mpc_header['raw']['title_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true); + $offset += 2; + + $thisfile_mpc_header['raw']['album_peak'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2)); + $offset += 2; + $thisfile_mpc_header['raw']['album_gain'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 2), true); + $offset += 2; + + $FlagsDWORD2 = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 4)); + $offset += 4; + $thisfile_mpc_header['true_gapless'] = (bool) (($FlagsDWORD2 & 0x80000000) >> 31); + $thisfile_mpc_header['last_frame_length'] = ($FlagsDWORD2 & 0x7FF00000) >> 20; + + + $thisfile_mpc_header['raw']['not_sure_what'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 3)); + $offset += 3; + $thisfile_mpc_header['raw']['encoder_version'] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, $offset, 1)); + $offset += 1; + + $thisfile_mpc_header['profile'] = $this->MPCprofileNameLookup($thisfile_mpc_header['raw']['profile']); + $thisfile_mpc_header['sample_rate'] = $this->MPCfrequencyLookup($thisfile_mpc_header['raw']['sample_rate']); + if ($thisfile_mpc_header['sample_rate'] == 0) { + $info['error'][] = 'Corrupt MPC file: frequency == zero'; + return false; + } + $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; + $thisfile_mpc_header['samples'] = ((($thisfile_mpc_header['frame_count'] - 1) * 1152) + $thisfile_mpc_header['last_frame_length']) * $info['audio']['channels']; + + $info['playtime_seconds'] = ($thisfile_mpc_header['samples'] / $info['audio']['channels']) / $info['audio']['sample_rate']; + if ($info['playtime_seconds'] == 0) { + $info['error'][] = 'Corrupt MPC file: playtime_seconds == zero'; + return false; + } + + // add size of file header to avdataoffset - calc bitrate correctly + MD5 data + $info['avdataoffset'] += $thisfile_mpc_header['size']; + + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + $thisfile_mpc_header['title_peak'] = $thisfile_mpc_header['raw']['title_peak']; + $thisfile_mpc_header['title_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['title_peak']); + if ($thisfile_mpc_header['raw']['title_gain'] < 0) { + $thisfile_mpc_header['title_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['title_gain']) / -100; + } else { + $thisfile_mpc_header['title_gain_db'] = (float) $thisfile_mpc_header['raw']['title_gain'] / 100; + } + + $thisfile_mpc_header['album_peak'] = $thisfile_mpc_header['raw']['album_peak']; + $thisfile_mpc_header['album_peak_db'] = $this->MPCpeakDBLookup($thisfile_mpc_header['album_peak']); + if ($thisfile_mpc_header['raw']['album_gain'] < 0) { + $thisfile_mpc_header['album_gain_db'] = (float) (32768 + $thisfile_mpc_header['raw']['album_gain']) / -100; + } else { + $thisfile_mpc_header['album_gain_db'] = (float) $thisfile_mpc_header['raw']['album_gain'] / 100;; + } + $thisfile_mpc_header['encoder_version'] = $this->MPCencoderVersionLookup($thisfile_mpc_header['raw']['encoder_version']); + + $info['replay_gain']['track']['adjustment'] = $thisfile_mpc_header['title_gain_db']; + $info['replay_gain']['album']['adjustment'] = $thisfile_mpc_header['album_gain_db']; + + if ($thisfile_mpc_header['title_peak'] > 0) { + $info['replay_gain']['track']['peak'] = $thisfile_mpc_header['title_peak']; + } elseif (round($thisfile_mpc_header['max_level'] * 1.18) > 0) { + $info['replay_gain']['track']['peak'] = getid3_lib::CastAsInt(round($thisfile_mpc_header['max_level'] * 1.18)); // why? I don't know - see mppdec.c + } + if ($thisfile_mpc_header['album_peak'] > 0) { + $info['replay_gain']['album']['peak'] = $thisfile_mpc_header['album_peak']; + } + + //$info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major'].'.'.$thisfile_mpc_header['stream_version_minor'].', '.$thisfile_mpc_header['encoder_version']; + $info['audio']['encoder'] = $thisfile_mpc_header['encoder_version']; + $info['audio']['encoder_options'] = $thisfile_mpc_header['profile']; + $thisfile_mpc_header['quality'] = (float) ($thisfile_mpc_header['raw']['profile'] - 5); // values can range from 0 to 15, of which 0..4 are "reserved/experimental", and 5..15 are mapped to qualities of 0.0 to 10.0 + + return true; + } + + public function ParseMPCsv6() { + // this is SV4 - SV6 + + $info = &$this->getid3->info; + $thisfile_mpc_header = &$info['mpc']['header']; + $offset = 0; + + $thisfile_mpc_header['size'] = 8; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $MPCheaderData = fread($this->getid3->fp, $thisfile_mpc_header['size']); + + // add size of file header to avdataoffset - calc bitrate correctly + MD5 data + $info['avdataoffset'] += $thisfile_mpc_header['size']; + + // Most of this code adapted from Jurgen Faul's MPEGplus source code - thanks Jurgen! :) + $HeaderDWORD[0] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 0, 4)); + $HeaderDWORD[1] = getid3_lib::LittleEndian2Int(substr($MPCheaderData, 4, 4)); + + + // DDDD DDDD CCCC CCCC BBBB BBBB AAAA AAAA + // aaaa aaaa abcd dddd dddd deee eeff ffff + // + // a = bitrate = anything + // b = IS = anything + // c = MS = anything + // d = streamversion = 0000000004 or 0000000005 or 0000000006 + // e = maxband = anything + // f = blocksize = 000001 for SV5+, anything(?) for SV4 + + $thisfile_mpc_header['target_bitrate'] = (($HeaderDWORD[0] & 0xFF800000) >> 23); + $thisfile_mpc_header['intensity_stereo'] = (bool) (($HeaderDWORD[0] & 0x00400000) >> 22); + $thisfile_mpc_header['mid_side_stereo'] = (bool) (($HeaderDWORD[0] & 0x00200000) >> 21); + $thisfile_mpc_header['stream_version_major'] = ($HeaderDWORD[0] & 0x001FF800) >> 11; + $thisfile_mpc_header['stream_version_minor'] = 0; // no sub-version numbers before SV7 + $thisfile_mpc_header['max_band'] = ($HeaderDWORD[0] & 0x000007C0) >> 6; // related to lowpass frequency, not sure how it translates exactly + $thisfile_mpc_header['block_size'] = ($HeaderDWORD[0] & 0x0000003F); + + switch ($thisfile_mpc_header['stream_version_major']) { + case 4: + $thisfile_mpc_header['frame_count'] = ($HeaderDWORD[1] >> 16); + break; + + case 5: + case 6: + $thisfile_mpc_header['frame_count'] = $HeaderDWORD[1]; + break; + + default: + $info['error'] = 'Expecting 4, 5 or 6 in version field, found '.$thisfile_mpc_header['stream_version_major'].' instead'; + unset($info['mpc']); + return false; + break; + } + + if (($thisfile_mpc_header['stream_version_major'] > 4) && ($thisfile_mpc_header['block_size'] != 1)) { + $info['warning'][] = 'Block size expected to be 1, actual value found: '.$thisfile_mpc_header['block_size']; + } + + $thisfile_mpc_header['sample_rate'] = 44100; // AB: used by all files up to SV7 + $info['audio']['sample_rate'] = $thisfile_mpc_header['sample_rate']; + $thisfile_mpc_header['samples'] = $thisfile_mpc_header['frame_count'] * 1152 * $info['audio']['channels']; + + if ($thisfile_mpc_header['target_bitrate'] == 0) { + $info['audio']['bitrate_mode'] = 'vbr'; + } else { + $info['audio']['bitrate_mode'] = 'cbr'; + } + + $info['mpc']['bitrate'] = ($info['avdataend'] - $info['avdataoffset']) * 8 * 44100 / $thisfile_mpc_header['frame_count'] / 1152; + $info['audio']['bitrate'] = $info['mpc']['bitrate']; + $info['audio']['encoder'] = 'SV'.$thisfile_mpc_header['stream_version_major']; + + return true; + } + + + public function MPCprofileNameLookup($profileid) { + static $MPCprofileNameLookup = array( + 0 => 'no profile', + 1 => 'Experimental', + 2 => 'unused', + 3 => 'unused', + 4 => 'unused', + 5 => 'below Telephone (q = 0.0)', + 6 => 'below Telephone (q = 1.0)', + 7 => 'Telephone (q = 2.0)', + 8 => 'Thumb (q = 3.0)', + 9 => 'Radio (q = 4.0)', + 10 => 'Standard (q = 5.0)', + 11 => 'Extreme (q = 6.0)', + 12 => 'Insane (q = 7.0)', + 13 => 'BrainDead (q = 8.0)', + 14 => 'above BrainDead (q = 9.0)', + 15 => 'above BrainDead (q = 10.0)' + ); + return (isset($MPCprofileNameLookup[$profileid]) ? $MPCprofileNameLookup[$profileid] : 'invalid'); + } + + public function MPCfrequencyLookup($frequencyid) { + static $MPCfrequencyLookup = array( + 0 => 44100, + 1 => 48000, + 2 => 37800, + 3 => 32000 + ); + return (isset($MPCfrequencyLookup[$frequencyid]) ? $MPCfrequencyLookup[$frequencyid] : 'invalid'); + } + + public function MPCpeakDBLookup($intvalue) { + if ($intvalue > 0) { + return ((log10($intvalue) / log10(2)) - 15) * 6; + } + return false; + } + + public function MPCencoderVersionLookup($encoderversion) { + //Encoder version * 100 (106 = 1.06) + //EncoderVersion % 10 == 0 Release (1.0) + //EncoderVersion % 2 == 0 Beta (1.06) + //EncoderVersion % 2 == 1 Alpha (1.05a...z) + + if ($encoderversion == 0) { + // very old version, not known exactly which + return 'Buschmann v1.7.0-v1.7.9 or Klemm v0.90-v1.05'; + } + + if (($encoderversion % 10) == 0) { + + // release version + return number_format($encoderversion / 100, 2); + + } elseif (($encoderversion % 2) == 0) { + + // beta version + return number_format($encoderversion / 100, 2).' beta'; + + } + + // alpha version + return number_format($encoderversion / 100, 2).' alpha'; + } + + public function SV8variableLengthInteger($data, &$packetLength, $maxHandledPacketLength=9) { + $packet_size = 0; + for ($packetLength = 1; $packetLength <= $maxHandledPacketLength; $packetLength++) { + // variable-length size field: + // bits, big-endian + // 0xxx xxxx - value 0 to 2^7-1 + // 1xxx xxxx 0xxx xxxx - value 0 to 2^14-1 + // 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^21-1 + // 1xxx xxxx 1xxx xxxx 1xxx xxxx 0xxx xxxx - value 0 to 2^28-1 + // ... + $thisbyte = ord(substr($data, ($packetLength - 1), 1)); + // look through bytes until find a byte with MSB==0 + $packet_size = ($packet_size << 7); + $packet_size = ($packet_size | ($thisbyte & 0x7F)); + if (($thisbyte & 0x80) === 0) { + break; + } + if ($packetLength >= $maxHandledPacketLength) { + return false; + } + } + return $packet_size; + } + + public function MPCsv8PacketName($packetKey) { + static $MPCsv8PacketName = array(); + if (empty($MPCsv8PacketName)) { + $MPCsv8PacketName = array( + 'AP' => 'Audio Packet', + 'CT' => 'Chapter Tag', + 'EI' => 'Encoder Info', + 'RG' => 'Replay Gain', + 'SE' => 'Stream End', + 'SH' => 'Stream Header', + 'SO' => 'Seek Table Offset', + 'ST' => 'Seek Table', + ); + } + return (isset($MPCsv8PacketName[$packetKey]) ? $MPCsv8PacketName[$packetKey] : $packetKey); + } +} diff --git a/app/libs/vendor/getid3/module.audio.ogg.php b/app/libs/vendor/getid3/module.audio.ogg.php index adc6d86e..a2a35aad 100644 --- a/app/libs/vendor/getid3/module.audio.ogg.php +++ b/app/libs/vendor/getid3/module.audio.ogg.php @@ -1,671 +1,671 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.ogg.php // -// module for analyzing Ogg Vorbis, OggFLAC and Speex files // -// dependencies: module.audio.flac.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true); - -class getid3_ogg extends getid3_handler -{ - // http://xiph.org/vorbis/doc/Vorbis_I_spec.html - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'ogg'; - - // Warn about illegal tags - only vorbiscomments are allowed - if (isset($info['id3v2'])) { - $info['warning'][] = 'Illegal ID3v2 tag present.'; - } - if (isset($info['id3v1'])) { - $info['warning'][] = 'Illegal ID3v1 tag present.'; - } - if (isset($info['ape'])) { - $info['warning'][] = 'Illegal APE tag present.'; - } - - - // Page 1 - Stream Header - - $this->fseek($info['avdataoffset']); - - $oggpageinfo = $this->ParseOggPageHeader(); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; - - if ($this->ftell() >= $this->getid3->fread_buffer_size()) { - $info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)'; - unset($info['fileformat']); - unset($info['ogg']); - return false; - } - - $filedata = $this->fread($oggpageinfo['page_length']); - $filedataoffset = 0; - - if (substr($filedata, 0, 4) == 'fLaC') { - - $info['audio']['dataformat'] = 'flac'; - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['lossless'] = true; - - } elseif (substr($filedata, 1, 6) == 'vorbis') { - - $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo); - - } elseif (substr($filedata, 0, 8) == 'Speex ') { - - // http://www.speex.org/manual/node10.html - - $info['audio']['dataformat'] = 'speex'; - $info['mime_type'] = 'audio/speex'; - $info['audio']['bitrate_mode'] = 'abr'; - $info['audio']['lossless'] = false; - - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex ' - $filedataoffset += 8; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20); - $filedataoffset += 20; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - - $info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']); - $info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate']; - $info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels']; - $info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr']; - $info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']); - - $info['audio']['sample_rate'] = $info['speex']['sample_rate']; - $info['audio']['channels'] = $info['speex']['channels']; - if ($info['speex']['vbr']) { - $info['audio']['bitrate_mode'] = 'vbr'; - } - - - } elseif (substr($filedata, 0, 8) == "fishead\x00") { - - // Ogg Skeleton version 3.0 Format Specification - // http://xiph.org/ogg/doc/skeleton.html - $filedataoffset += 8; - $info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); - $filedataoffset += 2; - $info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); - $filedataoffset += 2; - $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20)); - $filedataoffset += 20; - - $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor']; - $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']; - $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']; - $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc']; - - - $counter = 0; - do { - $oggpageinfo = $this->ParseOggPageHeader(); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo; - $filedata = $this->fread($oggpageinfo['page_length']); - $this->fseek($oggpageinfo['page_end_offset']); - - if (substr($filedata, 0, 8) == "fisbone\x00") { - - $filedataoffset = 8; - $info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3); - $filedataoffset += 3; - - } elseif (substr($filedata, 1, 6) == 'theora') { - - $info['video']['dataformat'] = 'theora'; - $info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']'; - //break; - - } elseif (substr($filedata, 1, 6) == 'vorbis') { - - $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo); - - } else { - $info['error'][] = 'unexpected'; - //break; - } - //} while ($oggpageinfo['page_seqno'] == 0); - } while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00")); - - $this->fseek($oggpageinfo['page_start_offset']); - - $info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']'; - //return false; - - } else { - - $info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"'; - unset($info['ogg']); - unset($info['mime_type']); - return false; - - } - - // Page 2 - Comment Header - $oggpageinfo = $this->ParseOggPageHeader(); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; - - switch ($info['audio']['dataformat']) { - case 'vorbis': - $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1)); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis' - - $this->ParseVorbisComments(); - break; - - case 'flac': - $flac = new getid3_flac($this->getid3); - if (!$flac->parseMETAdata()) { - $info['error'][] = 'Failed to parse FLAC headers'; - return false; - } - unset($flac); - break; - - case 'speex': - $this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR); - $this->ParseVorbisComments(); - break; - } - - - // Last Page - Number of Samples - if (!getid3_lib::intValueSupported($info['avdataend'])) { - - $info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)'; - - } else { - - $this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0)); - $LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size())); - if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) { - $this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO'))); - $info['avdataend'] = $this->ftell(); - $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader(); - $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position']; - if ($info['ogg']['samples'] == 0) { - $info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero'; - return false; - } - if (!empty($info['audio']['sample_rate'])) { - $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']); - } - } - - } - - if (!empty($info['ogg']['bitrate_average'])) { - $info['audio']['bitrate'] = $info['ogg']['bitrate_average']; - } elseif (!empty($info['ogg']['bitrate_nominal'])) { - $info['audio']['bitrate'] = $info['ogg']['bitrate_nominal']; - } elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) { - $info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2; - } - if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) { - if ($info['audio']['bitrate'] == 0) { - $info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero'; - return false; - } - $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']); - } - - if (isset($info['ogg']['vendor'])) { - $info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']); - - // Vorbis only - if ($info['audio']['dataformat'] == 'vorbis') { - - // Vorbis 1.0 starts with Xiph.Org - if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) { - - if ($info['audio']['bitrate_mode'] == 'abr') { - - // Set -b 128 on abr files - $info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000); - - } elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) { - // Set -q N on vbr files - $info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']); - - } - } - - if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) { - $info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps'; - } - } - } - - return true; - } - - public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) { - $info = &$this->getid3->info; - $info['audio']['dataformat'] = 'vorbis'; - $info['audio']['lossless'] = false; - - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis' - $filedataoffset += 6; - $info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $info['audio']['channels'] = $info['ogg']['numberofchannels']; - $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - if ($info['ogg']['samplerate'] == 0) { - $info['error'][] = 'Corrupt Ogg file: sample rate == zero'; - return false; - } - $info['audio']['sample_rate'] = $info['ogg']['samplerate']; - $info['ogg']['samples'] = 0; // filled in later - $info['ogg']['bitrate_average'] = 0; // filled in later - $info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F); - $info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4); - $info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet - - $info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr - if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) { - unset($info['ogg']['bitrate_max']); - $info['audio']['bitrate_mode'] = 'abr'; - } - if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) { - unset($info['ogg']['bitrate_nominal']); - } - if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) { - unset($info['ogg']['bitrate_min']); - $info['audio']['bitrate_mode'] = 'abr'; - } - return true; - } - - public function ParseOggPageHeader() { - // http://xiph.org/ogg/vorbis/doc/framing.html - $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file - - $filedata = $this->fread($this->getid3->fread_buffer_size()); - $filedataoffset = 0; - while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { - if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) { - // should be found before here - return false; - } - if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { - if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) { - // get some more data, unless eof, in which case fail - return false; - } - } - } - $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS' - - $oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet - $oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos) - $oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos) - - $oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); - $filedataoffset += 8; - $oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); - $filedataoffset += 4; - $oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $oggheader['page_length'] = 0; - for ($i = 0; $i < $oggheader['page_segments']; $i++) { - $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); - $filedataoffset += 1; - $oggheader['page_length'] += $oggheader['segment_table'][$i]; - } - $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset; - $oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length']; - $this->fseek($oggheader['header_end_offset']); - - return $oggheader; - } - - // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005 - public function ParseVorbisComments() { - $info = &$this->getid3->info; - - $OriginalOffset = $this->ftell(); - $commentdataoffset = 0; - $VorbisCommentPage = 1; - - switch ($info['audio']['dataformat']) { - case 'vorbis': - case 'speex': - $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block - $this->fseek($CommentStartOffset); - $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments']; - $commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset); - - if ($info['audio']['dataformat'] == 'vorbis') { - $commentdataoffset += (strlen('vorbis') + 1); - } - break; - - case 'flac': - $CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4; - $this->fseek($CommentStartOffset); - $commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']); - break; - - default: - return false; - } - - $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); - $commentdataoffset += 4; - - $info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize); - $commentdataoffset += $VendorSize; - - $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); - $commentdataoffset += 4; - $info['avdataoffset'] = $CommentStartOffset + $commentdataoffset; - - $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT'); - $ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw']; - for ($i = 0; $i < $CommentsCount; $i++) { - - $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset; - - if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) { - if ($oggpageinfo = $this->ParseOggPageHeader()) { - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; - - $VorbisCommentPage++; - - // First, save what we haven't read yet - $AsYetUnusedData = substr($commentdata, $commentdataoffset); - - // Then take that data off the end - $commentdata = substr($commentdata, 0, $commentdataoffset); - - // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct - $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); - $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); - - // Finally, stick the unused data back on the end - $commentdata .= $AsYetUnusedData; - - //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); - $commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1)); - } - - } - $ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); - - // replace avdataoffset with position just after the last vorbiscomment - $info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4; - - $commentdataoffset += 4; - while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) { - if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) { - $info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments'; - break 2; - } - - $VorbisCommentPage++; - - $oggpageinfo = $this->ParseOggPageHeader(); - $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; - - // First, save what we haven't read yet - $AsYetUnusedData = substr($commentdata, $commentdataoffset); - - // Then take that data off the end - $commentdata = substr($commentdata, 0, $commentdataoffset); - - // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct - $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); - $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); - - // Finally, stick the unused data back on the end - $commentdata .= $AsYetUnusedData; - - //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); - if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { - $info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell(); - break; - } - $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1); - if ($readlength <= 0) { - $info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell(); - break; - } - $commentdata .= $this->fread($readlength); - - //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset']; - } - $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset; - $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']); - $commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size']; - - if (!$commentstring) { - - // no comment? - $info['warning'][] = 'Blank Ogg comment ['.$i.']'; - - } elseif (strstr($commentstring, '=')) { - - $commentexploded = explode('=', $commentstring, 2); - $ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]); - $ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : ''); - - if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') { - - // http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE - // The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard. - // http://flac.sourceforge.net/format.html#metadata_block_picture - $flac = new getid3_flac($this->getid3); - $flac->setStringMode(base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value'])); - $flac->parsePICTURE(); - $info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0]; - unset($flac); - - } elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') { - - $data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']); - $this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure'); - /** @todo use 'coverartmime' where available */ - $imageinfo = getid3_lib::GetDataImageSize($data); - if ($imageinfo === false || !isset($imageinfo['mime'])) { - $this->warning('COVERART vorbiscomment tag contains invalid image'); - continue; - } - - $ogg = new self($this->getid3); - $ogg->setStringMode($data); - $info['ogg']['comments']['picture'][] = array( - 'image_mime' => $imageinfo['mime'], - 'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']), - ); - unset($ogg); - - } else { - - $info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value']; - - } - - } else { - - $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring; - - } - unset($ThisFileInfo_ogg_comments_raw[$i]); - } - unset($ThisFileInfo_ogg_comments_raw); - - - // Replay Gain Adjustment - // http://privatewww.essex.ac.uk/~djmrob/replaygain/ - if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) { - foreach ($info['ogg']['comments'] as $index => $commentvalue) { - switch ($index) { - case 'rg_audiophile': - case 'replaygain_album_gain': - $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0]; - unset($info['ogg']['comments'][$index]); - break; - - case 'rg_radio': - case 'replaygain_track_gain': - $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0]; - unset($info['ogg']['comments'][$index]); - break; - - case 'replaygain_album_peak': - $info['replay_gain']['album']['peak'] = (double) $commentvalue[0]; - unset($info['ogg']['comments'][$index]); - break; - - case 'rg_peak': - case 'replaygain_track_peak': - $info['replay_gain']['track']['peak'] = (double) $commentvalue[0]; - unset($info['ogg']['comments'][$index]); - break; - - case 'replaygain_reference_loudness': - $info['replay_gain']['reference_volume'] = (double) $commentvalue[0]; - unset($info['ogg']['comments'][$index]); - break; - - default: - // do nothing - break; - } - } - } - - $this->fseek($OriginalOffset); - - return true; - } - - public static function SpeexBandModeLookup($mode) { - static $SpeexBandModeLookup = array(); - if (empty($SpeexBandModeLookup)) { - $SpeexBandModeLookup[0] = 'narrow'; - $SpeexBandModeLookup[1] = 'wide'; - $SpeexBandModeLookup[2] = 'ultra-wide'; - } - return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null); - } - - - public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) { - for ($i = 0; $i < $SegmentNumber; $i++) { - $segmentlength = 0; - foreach ($OggInfoArray['segment_table'] as $key => $value) { - $segmentlength += $value; - if ($value < 255) { - break; - } - } - } - return $segmentlength; - } - - - public static function get_quality_from_nominal_bitrate($nominal_bitrate) { - - // decrease precision - $nominal_bitrate = $nominal_bitrate / 1000; - - if ($nominal_bitrate < 128) { - // q-1 to q4 - $qval = ($nominal_bitrate - 64) / 16; - } elseif ($nominal_bitrate < 256) { - // q4 to q8 - $qval = $nominal_bitrate / 32; - } elseif ($nominal_bitrate < 320) { - // q8 to q9 - $qval = ($nominal_bitrate + 256) / 64; - } else { - // q9 to q10 - $qval = ($nominal_bitrate + 1300) / 180; - } - //return $qval; // 5.031324 - //return intval($qval); // 5 - return round($qval, 1); // 5 or 4.9 - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.ogg.php // +// module for analyzing Ogg Vorbis, OggFLAC and Speex files // +// dependencies: module.audio.flac.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.flac.php', __FILE__, true); + +class getid3_ogg extends getid3_handler +{ + // http://xiph.org/vorbis/doc/Vorbis_I_spec.html + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'ogg'; + + // Warn about illegal tags - only vorbiscomments are allowed + if (isset($info['id3v2'])) { + $info['warning'][] = 'Illegal ID3v2 tag present.'; + } + if (isset($info['id3v1'])) { + $info['warning'][] = 'Illegal ID3v1 tag present.'; + } + if (isset($info['ape'])) { + $info['warning'][] = 'Illegal APE tag present.'; + } + + + // Page 1 - Stream Header + + $this->fseek($info['avdataoffset']); + + $oggpageinfo = $this->ParseOggPageHeader(); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + if ($this->ftell() >= $this->getid3->fread_buffer_size()) { + $info['error'][] = 'Could not find start of Ogg page in the first '.$this->getid3->fread_buffer_size().' bytes (this might not be an Ogg-Vorbis file?)'; + unset($info['fileformat']); + unset($info['ogg']); + return false; + } + + $filedata = $this->fread($oggpageinfo['page_length']); + $filedataoffset = 0; + + if (substr($filedata, 0, 4) == 'fLaC') { + + $info['audio']['dataformat'] = 'flac'; + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['lossless'] = true; + + } elseif (substr($filedata, 1, 6) == 'vorbis') { + + $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo); + + } elseif (substr($filedata, 0, 8) == 'Speex ') { + + // http://www.speex.org/manual/node10.html + + $info['audio']['dataformat'] = 'speex'; + $info['mime_type'] = 'audio/speex'; + $info['audio']['bitrate_mode'] = 'abr'; + $info['audio']['lossless'] = false; + + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_string'] = substr($filedata, $filedataoffset, 8); // hard-coded to 'Speex ' + $filedataoffset += 8; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version'] = substr($filedata, $filedataoffset, 20); + $filedataoffset += 20; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version_id'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['header_size'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode_bitstream_version'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['bitrate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['framesize'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['frames_per_packet'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['extra_headers'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved1'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['reserved2'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + + $info['speex']['speex_version'] = trim($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['speex_version']); + $info['speex']['sample_rate'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['rate']; + $info['speex']['channels'] = $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['nb_channels']; + $info['speex']['vbr'] = (bool) $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['vbr']; + $info['speex']['band_type'] = $this->SpeexBandModeLookup($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['mode']); + + $info['audio']['sample_rate'] = $info['speex']['sample_rate']; + $info['audio']['channels'] = $info['speex']['channels']; + if ($info['speex']['vbr']) { + $info['audio']['bitrate_mode'] = 'vbr'; + } + + + } elseif (substr($filedata, 0, 8) == "fishead\x00") { + + // Ogg Skeleton version 3.0 Format Specification + // http://xiph.org/ogg/doc/skeleton.html + $filedataoffset += 8; + $info['ogg']['skeleton']['fishead']['raw']['version_major'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); + $filedataoffset += 2; + $info['ogg']['skeleton']['fishead']['raw']['version_minor'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 2)); + $filedataoffset += 2; + $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fishead']['raw']['utc'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 20)); + $filedataoffset += 20; + + $info['ogg']['skeleton']['fishead']['version'] = $info['ogg']['skeleton']['fishead']['raw']['version_major'].'.'.$info['ogg']['skeleton']['fishead']['raw']['version_minor']; + $info['ogg']['skeleton']['fishead']['presentationtime'] = $info['ogg']['skeleton']['fishead']['raw']['presentationtime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['presentationtime_denominator']; + $info['ogg']['skeleton']['fishead']['basetime'] = $info['ogg']['skeleton']['fishead']['raw']['basetime_numerator'] / $info['ogg']['skeleton']['fishead']['raw']['basetime_denominator']; + $info['ogg']['skeleton']['fishead']['utc'] = $info['ogg']['skeleton']['fishead']['raw']['utc']; + + + $counter = 0; + do { + $oggpageinfo = $this->ParseOggPageHeader(); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno'].'.'.$counter++] = $oggpageinfo; + $filedata = $this->fread($oggpageinfo['page_length']); + $this->fseek($oggpageinfo['page_end_offset']); + + if (substr($filedata, 0, 8) == "fisbone\x00") { + + $filedataoffset = 8; + $info['ogg']['skeleton']['fisbone']['raw']['message_header_offset'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['skeleton']['fisbone']['raw']['serial_number'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['skeleton']['fisbone']['raw']['number_header_packets'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['skeleton']['fisbone']['raw']['granulerate_numerator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fisbone']['raw']['granulerate_denominator'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fisbone']['raw']['basegranule'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $info['ogg']['skeleton']['fisbone']['raw']['preroll'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['skeleton']['fisbone']['raw']['granuleshift'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $info['ogg']['skeleton']['fisbone']['raw']['padding'] = substr($filedata, $filedataoffset, 3); + $filedataoffset += 3; + + } elseif (substr($filedata, 1, 6) == 'theora') { + + $info['video']['dataformat'] = 'theora'; + $info['error'][] = 'Ogg Theora not correctly handled in this version of getID3 ['.$this->getid3->version().']'; + //break; + + } elseif (substr($filedata, 1, 6) == 'vorbis') { + + $this->ParseVorbisPageHeader($filedata, $filedataoffset, $oggpageinfo); + + } else { + $info['error'][] = 'unexpected'; + //break; + } + //} while ($oggpageinfo['page_seqno'] == 0); + } while (($oggpageinfo['page_seqno'] == 0) && (substr($filedata, 0, 8) != "fisbone\x00")); + + $this->fseek($oggpageinfo['page_start_offset']); + + $info['error'][] = 'Ogg Skeleton not correctly handled in this version of getID3 ['.$this->getid3->version().']'; + //return false; + + } else { + + $info['error'][] = 'Expecting either "Speex " or "vorbis" identifier strings, found "'.substr($filedata, 0, 8).'"'; + unset($info['ogg']); + unset($info['mime_type']); + return false; + + } + + // Page 2 - Comment Header + $oggpageinfo = $this->ParseOggPageHeader(); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + switch ($info['audio']['dataformat']) { + case 'vorbis': + $filedata = $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, 0, 1)); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, 1, 6); // hard-coded to 'vorbis' + + $this->ParseVorbisComments(); + break; + + case 'flac': + $flac = new getid3_flac($this->getid3); + if (!$flac->parseMETAdata()) { + $info['error'][] = 'Failed to parse FLAC headers'; + return false; + } + unset($flac); + break; + + case 'speex': + $this->fseek($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length'], SEEK_CUR); + $this->ParseVorbisComments(); + break; + } + + + // Last Page - Number of Samples + if (!getid3_lib::intValueSupported($info['avdataend'])) { + + $info['warning'][] = 'Unable to parse Ogg end chunk file (PHP does not support file operations beyond '.round(PHP_INT_MAX / 1073741824).'GB)'; + + } else { + + $this->fseek(max($info['avdataend'] - $this->getid3->fread_buffer_size(), 0)); + $LastChunkOfOgg = strrev($this->fread($this->getid3->fread_buffer_size())); + if ($LastOggSpostion = strpos($LastChunkOfOgg, 'SggO')) { + $this->fseek($info['avdataend'] - ($LastOggSpostion + strlen('SggO'))); + $info['avdataend'] = $this->ftell(); + $info['ogg']['pageheader']['eos'] = $this->ParseOggPageHeader(); + $info['ogg']['samples'] = $info['ogg']['pageheader']['eos']['pcm_abs_position']; + if ($info['ogg']['samples'] == 0) { + $info['error'][] = 'Corrupt Ogg file: eos.number of samples == zero'; + return false; + } + if (!empty($info['audio']['sample_rate'])) { + $info['ogg']['bitrate_average'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($info['ogg']['samples'] / $info['audio']['sample_rate']); + } + } + + } + + if (!empty($info['ogg']['bitrate_average'])) { + $info['audio']['bitrate'] = $info['ogg']['bitrate_average']; + } elseif (!empty($info['ogg']['bitrate_nominal'])) { + $info['audio']['bitrate'] = $info['ogg']['bitrate_nominal']; + } elseif (!empty($info['ogg']['bitrate_min']) && !empty($info['ogg']['bitrate_max'])) { + $info['audio']['bitrate'] = ($info['ogg']['bitrate_min'] + $info['ogg']['bitrate_max']) / 2; + } + if (isset($info['audio']['bitrate']) && !isset($info['playtime_seconds'])) { + if ($info['audio']['bitrate'] == 0) { + $info['error'][] = 'Corrupt Ogg file: bitrate_audio == zero'; + return false; + } + $info['playtime_seconds'] = (float) ((($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']); + } + + if (isset($info['ogg']['vendor'])) { + $info['audio']['encoder'] = preg_replace('/^Encoded with /', '', $info['ogg']['vendor']); + + // Vorbis only + if ($info['audio']['dataformat'] == 'vorbis') { + + // Vorbis 1.0 starts with Xiph.Org + if (preg_match('/^Xiph.Org/', $info['audio']['encoder'])) { + + if ($info['audio']['bitrate_mode'] == 'abr') { + + // Set -b 128 on abr files + $info['audio']['encoder_options'] = '-b '.round($info['ogg']['bitrate_nominal'] / 1000); + + } elseif (($info['audio']['bitrate_mode'] == 'vbr') && ($info['audio']['channels'] == 2) && ($info['audio']['sample_rate'] >= 44100) && ($info['audio']['sample_rate'] <= 48000)) { + // Set -q N on vbr files + $info['audio']['encoder_options'] = '-q '.$this->get_quality_from_nominal_bitrate($info['ogg']['bitrate_nominal']); + + } + } + + if (empty($info['audio']['encoder_options']) && !empty($info['ogg']['bitrate_nominal'])) { + $info['audio']['encoder_options'] = 'Nominal bitrate: '.intval(round($info['ogg']['bitrate_nominal'] / 1000)).'kbps'; + } + } + } + + return true; + } + + public function ParseVorbisPageHeader(&$filedata, &$filedataoffset, &$oggpageinfo) { + $info = &$this->getid3->info; + $info['audio']['dataformat'] = 'vorbis'; + $info['audio']['lossless'] = false; + + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['packet_type'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['stream_type'] = substr($filedata, $filedataoffset, 6); // hard-coded to 'vorbis' + $filedataoffset += 6; + $info['ogg']['bitstreamversion'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['numberofchannels'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $info['audio']['channels'] = $info['ogg']['numberofchannels']; + $info['ogg']['samplerate'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + if ($info['ogg']['samplerate'] == 0) { + $info['error'][] = 'Corrupt Ogg file: sample rate == zero'; + return false; + } + $info['audio']['sample_rate'] = $info['ogg']['samplerate']; + $info['ogg']['samples'] = 0; // filled in later + $info['ogg']['bitrate_average'] = 0; // filled in later + $info['ogg']['bitrate_max'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['bitrate_nominal'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['bitrate_min'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $info['ogg']['blocksize_small'] = pow(2, getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0x0F); + $info['ogg']['blocksize_large'] = pow(2, (getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)) & 0xF0) >> 4); + $info['ogg']['stop_bit'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); // must be 1, marks end of packet + + $info['audio']['bitrate_mode'] = 'vbr'; // overridden if actually abr + if ($info['ogg']['bitrate_max'] == 0xFFFFFFFF) { + unset($info['ogg']['bitrate_max']); + $info['audio']['bitrate_mode'] = 'abr'; + } + if ($info['ogg']['bitrate_nominal'] == 0xFFFFFFFF) { + unset($info['ogg']['bitrate_nominal']); + } + if ($info['ogg']['bitrate_min'] == 0xFFFFFFFF) { + unset($info['ogg']['bitrate_min']); + $info['audio']['bitrate_mode'] = 'abr'; + } + return true; + } + + public function ParseOggPageHeader() { + // http://xiph.org/ogg/vorbis/doc/framing.html + $oggheader['page_start_offset'] = $this->ftell(); // where we started from in the file + + $filedata = $this->fread($this->getid3->fread_buffer_size()); + $filedataoffset = 0; + while ((substr($filedata, $filedataoffset++, 4) != 'OggS')) { + if (($this->ftell() - $oggheader['page_start_offset']) >= $this->getid3->fread_buffer_size()) { + // should be found before here + return false; + } + if ((($filedataoffset + 28) > strlen($filedata)) || (strlen($filedata) < 28)) { + if ($this->feof() || (($filedata .= $this->fread($this->getid3->fread_buffer_size())) === false)) { + // get some more data, unless eof, in which case fail + return false; + } + } + } + $filedataoffset += strlen('OggS') - 1; // page, delimited by 'OggS' + + $oggheader['stream_structver'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['flags_raw'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['flags']['fresh'] = (bool) ($oggheader['flags_raw'] & 0x01); // fresh packet + $oggheader['flags']['bos'] = (bool) ($oggheader['flags_raw'] & 0x02); // first page of logical bitstream (bos) + $oggheader['flags']['eos'] = (bool) ($oggheader['flags_raw'] & 0x04); // last page of logical bitstream (eos) + + $oggheader['pcm_abs_position'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 8)); + $filedataoffset += 8; + $oggheader['stream_serialno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_seqno'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_checksum'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 4)); + $filedataoffset += 4; + $oggheader['page_segments'] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['page_length'] = 0; + for ($i = 0; $i < $oggheader['page_segments']; $i++) { + $oggheader['segment_table'][$i] = getid3_lib::LittleEndian2Int(substr($filedata, $filedataoffset, 1)); + $filedataoffset += 1; + $oggheader['page_length'] += $oggheader['segment_table'][$i]; + } + $oggheader['header_end_offset'] = $oggheader['page_start_offset'] + $filedataoffset; + $oggheader['page_end_offset'] = $oggheader['header_end_offset'] + $oggheader['page_length']; + $this->fseek($oggheader['header_end_offset']); + + return $oggheader; + } + + // http://xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-810005 + public function ParseVorbisComments() { + $info = &$this->getid3->info; + + $OriginalOffset = $this->ftell(); + $commentdataoffset = 0; + $VorbisCommentPage = 1; + + switch ($info['audio']['dataformat']) { + case 'vorbis': + case 'speex': + $CommentStartOffset = $info['ogg']['pageheader'][$VorbisCommentPage]['page_start_offset']; // Second Ogg page, after header block + $this->fseek($CommentStartOffset); + $commentdataoffset = 27 + $info['ogg']['pageheader'][$VorbisCommentPage]['page_segments']; + $commentdata = $this->fread(self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1) + $commentdataoffset); + + if ($info['audio']['dataformat'] == 'vorbis') { + $commentdataoffset += (strlen('vorbis') + 1); + } + break; + + case 'flac': + $CommentStartOffset = $info['flac']['VORBIS_COMMENT']['raw']['offset'] + 4; + $this->fseek($CommentStartOffset); + $commentdata = $this->fread($info['flac']['VORBIS_COMMENT']['raw']['block_length']); + break; + + default: + return false; + } + + $VendorSize = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + $commentdataoffset += 4; + + $info['ogg']['vendor'] = substr($commentdata, $commentdataoffset, $VendorSize); + $commentdataoffset += $VendorSize; + + $CommentsCount = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + $commentdataoffset += 4; + $info['avdataoffset'] = $CommentStartOffset + $commentdataoffset; + + $basicfields = array('TITLE', 'ARTIST', 'ALBUM', 'TRACKNUMBER', 'GENRE', 'DATE', 'DESCRIPTION', 'COMMENT'); + $ThisFileInfo_ogg_comments_raw = &$info['ogg']['comments_raw']; + for ($i = 0; $i < $CommentsCount; $i++) { + + $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] = $CommentStartOffset + $commentdataoffset; + + if ($this->ftell() < ($ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + 4)) { + if ($oggpageinfo = $this->ParseOggPageHeader()) { + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + $VorbisCommentPage++; + + // First, save what we haven't read yet + $AsYetUnusedData = substr($commentdata, $commentdataoffset); + + // Then take that data off the end + $commentdata = substr($commentdata, 0, $commentdataoffset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $commentdata .= $AsYetUnusedData; + + //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + $commentdata .= $this->fread($this->OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1)); + } + + } + $ThisFileInfo_ogg_comments_raw[$i]['size'] = getid3_lib::LittleEndian2Int(substr($commentdata, $commentdataoffset, 4)); + + // replace avdataoffset with position just after the last vorbiscomment + $info['avdataoffset'] = $ThisFileInfo_ogg_comments_raw[$i]['dataoffset'] + $ThisFileInfo_ogg_comments_raw[$i]['size'] + 4; + + $commentdataoffset += 4; + while ((strlen($commentdata) - $commentdataoffset) < $ThisFileInfo_ogg_comments_raw[$i]['size']) { + if (($ThisFileInfo_ogg_comments_raw[$i]['size'] > $info['avdataend']) || ($ThisFileInfo_ogg_comments_raw[$i]['size'] < 0)) { + $info['warning'][] = 'Invalid Ogg comment size (comment #'.$i.', claims to be '.number_format($ThisFileInfo_ogg_comments_raw[$i]['size']).' bytes) - aborting reading comments'; + break 2; + } + + $VorbisCommentPage++; + + $oggpageinfo = $this->ParseOggPageHeader(); + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']] = $oggpageinfo; + + // First, save what we haven't read yet + $AsYetUnusedData = substr($commentdata, $commentdataoffset); + + // Then take that data off the end + $commentdata = substr($commentdata, 0, $commentdataoffset); + + // Add [headerlength] bytes of dummy data for the Ogg Page Header, just to keep absolute offsets correct + $commentdata .= str_repeat("\x00", 27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + $commentdataoffset += (27 + $info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_segments']); + + // Finally, stick the unused data back on the end + $commentdata .= $AsYetUnusedData; + + //$commentdata .= $this->fread($info['ogg']['pageheader'][$oggpageinfo['page_seqno']]['page_length']); + if (!isset($info['ogg']['pageheader'][$VorbisCommentPage])) { + $info['warning'][] = 'undefined Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell(); + break; + } + $readlength = self::OggPageSegmentLength($info['ogg']['pageheader'][$VorbisCommentPage], 1); + if ($readlength <= 0) { + $info['warning'][] = 'invalid length Vorbis Comment page "'.$VorbisCommentPage.'" at offset '.$this->ftell(); + break; + } + $commentdata .= $this->fread($readlength); + + //$filebaseoffset += $oggpageinfo['header_end_offset'] - $oggpageinfo['page_start_offset']; + } + $ThisFileInfo_ogg_comments_raw[$i]['offset'] = $commentdataoffset; + $commentstring = substr($commentdata, $commentdataoffset, $ThisFileInfo_ogg_comments_raw[$i]['size']); + $commentdataoffset += $ThisFileInfo_ogg_comments_raw[$i]['size']; + + if (!$commentstring) { + + // no comment? + $info['warning'][] = 'Blank Ogg comment ['.$i.']'; + + } elseif (strstr($commentstring, '=')) { + + $commentexploded = explode('=', $commentstring, 2); + $ThisFileInfo_ogg_comments_raw[$i]['key'] = strtoupper($commentexploded[0]); + $ThisFileInfo_ogg_comments_raw[$i]['value'] = (isset($commentexploded[1]) ? $commentexploded[1] : ''); + + if ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'METADATA_BLOCK_PICTURE') { + + // http://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE + // The unencoded format is that of the FLAC picture block. The fields are stored in big endian order as in FLAC, picture data is stored according to the relevant standard. + // http://flac.sourceforge.net/format.html#metadata_block_picture + $flac = new getid3_flac($this->getid3); + $flac->setStringMode(base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value'])); + $flac->parsePICTURE(); + $info['ogg']['comments']['picture'][] = $flac->getid3->info['flac']['PICTURE'][0]; + unset($flac); + + } elseif ($ThisFileInfo_ogg_comments_raw[$i]['key'] == 'COVERART') { + + $data = base64_decode($ThisFileInfo_ogg_comments_raw[$i]['value']); + $this->notice('Found deprecated COVERART tag, it should be replaced in honor of METADATA_BLOCK_PICTURE structure'); + /** @todo use 'coverartmime' where available */ + $imageinfo = getid3_lib::GetDataImageSize($data); + if ($imageinfo === false || !isset($imageinfo['mime'])) { + $this->warning('COVERART vorbiscomment tag contains invalid image'); + continue; + } + + $ogg = new self($this->getid3); + $ogg->setStringMode($data); + $info['ogg']['comments']['picture'][] = array( + 'image_mime' => $imageinfo['mime'], + 'data' => $ogg->saveAttachment('coverart', 0, strlen($data), $imageinfo['mime']), + ); + unset($ogg); + + } else { + + $info['ogg']['comments'][strtolower($ThisFileInfo_ogg_comments_raw[$i]['key'])][] = $ThisFileInfo_ogg_comments_raw[$i]['value']; + + } + + } else { + + $info['warning'][] = '[known problem with CDex >= v1.40, < v1.50b7] Invalid Ogg comment name/value pair ['.$i.']: '.$commentstring; + + } + unset($ThisFileInfo_ogg_comments_raw[$i]); + } + unset($ThisFileInfo_ogg_comments_raw); + + + // Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + if (isset($info['ogg']['comments']) && is_array($info['ogg']['comments'])) { + foreach ($info['ogg']['comments'] as $index => $commentvalue) { + switch ($index) { + case 'rg_audiophile': + case 'replaygain_album_gain': + $info['replay_gain']['album']['adjustment'] = (double) $commentvalue[0]; + unset($info['ogg']['comments'][$index]); + break; + + case 'rg_radio': + case 'replaygain_track_gain': + $info['replay_gain']['track']['adjustment'] = (double) $commentvalue[0]; + unset($info['ogg']['comments'][$index]); + break; + + case 'replaygain_album_peak': + $info['replay_gain']['album']['peak'] = (double) $commentvalue[0]; + unset($info['ogg']['comments'][$index]); + break; + + case 'rg_peak': + case 'replaygain_track_peak': + $info['replay_gain']['track']['peak'] = (double) $commentvalue[0]; + unset($info['ogg']['comments'][$index]); + break; + + case 'replaygain_reference_loudness': + $info['replay_gain']['reference_volume'] = (double) $commentvalue[0]; + unset($info['ogg']['comments'][$index]); + break; + + default: + // do nothing + break; + } + } + } + + $this->fseek($OriginalOffset); + + return true; + } + + public static function SpeexBandModeLookup($mode) { + static $SpeexBandModeLookup = array(); + if (empty($SpeexBandModeLookup)) { + $SpeexBandModeLookup[0] = 'narrow'; + $SpeexBandModeLookup[1] = 'wide'; + $SpeexBandModeLookup[2] = 'ultra-wide'; + } + return (isset($SpeexBandModeLookup[$mode]) ? $SpeexBandModeLookup[$mode] : null); + } + + + public static function OggPageSegmentLength($OggInfoArray, $SegmentNumber=1) { + for ($i = 0; $i < $SegmentNumber; $i++) { + $segmentlength = 0; + foreach ($OggInfoArray['segment_table'] as $key => $value) { + $segmentlength += $value; + if ($value < 255) { + break; + } + } + } + return $segmentlength; + } + + + public static function get_quality_from_nominal_bitrate($nominal_bitrate) { + + // decrease precision + $nominal_bitrate = $nominal_bitrate / 1000; + + if ($nominal_bitrate < 128) { + // q-1 to q4 + $qval = ($nominal_bitrate - 64) / 16; + } elseif ($nominal_bitrate < 256) { + // q4 to q8 + $qval = $nominal_bitrate / 32; + } elseif ($nominal_bitrate < 320) { + // q8 to q9 + $qval = ($nominal_bitrate + 256) / 64; + } else { + // q9 to q10 + $qval = ($nominal_bitrate + 1300) / 180; + } + //return $qval; // 5.031324 + //return intval($qval); // 5 + return round($qval, 1); // 5 or 4.9 + } + +} diff --git a/app/libs/vendor/getid3/module.audio.optimfrog.php b/app/libs/vendor/getid3/module.audio.optimfrog.php index 25442d2a..5df74b7b 100644 --- a/app/libs/vendor/getid3/module.audio.optimfrog.php +++ b/app/libs/vendor/getid3/module.audio.optimfrog.php @@ -1,426 +1,426 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.optimfrog.php // -// module for analyzing OptimFROG audio files // -// dependencies: module.audio.riff.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - -class getid3_optimfrog extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'ofr'; - $info['audio']['dataformat'] = 'ofr'; - $info['audio']['bitrate_mode'] = 'vbr'; - $info['audio']['lossless'] = true; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $OFRheader = fread($this->getid3->fp, 8); - if (substr($OFRheader, 0, 5) == '*RIFF') { - - return $this->ParseOptimFROGheader42(); - - } elseif (substr($OFRheader, 0, 3) == 'OFR') { - - return $this->ParseOptimFROGheader45(); - - } - - $info['error'][] = 'Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"'; - unset($info['fileformat']); - return false; - } - - - public function ParseOptimFROGheader42() { - // for fileformat of v4.21 and older - - $info = &$this->getid3->info; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $OptimFROGheaderData = fread($this->getid3->fp, 45); - $info['avdataoffset'] = 45; - - $OptimFROGencoderVersion_raw = getid3_lib::LittleEndian2Int(substr($OptimFROGheaderData, 0, 1)); - $OptimFROGencoderVersion_major = floor($OptimFROGencoderVersion_raw / 10); - $OptimFROGencoderVersion_minor = $OptimFROGencoderVersion_raw - ($OptimFROGencoderVersion_major * 10); - $RIFFdata = substr($OptimFROGheaderData, 1, 44); - $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; - $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; - - if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) { - $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize); - fseek($this->getid3->fp, $info['avdataend'], SEEK_SET); - $RIFFdata .= fread($this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize); - } - - // move the data chunk after all other chunks (if any) - // so that the RIFF parser doesn't see EOF when trying - // to skip over the data chunk - $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_temp->info['avdataend'] = $info['avdataend']; - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->ParseRIFFdata($RIFFdata); - $info['riff'] = $getid3_temp->info['riff']; - - $info['audio']['encoder'] = 'OptimFROG '.$OptimFROGencoderVersion_major.'.'.$OptimFROGencoderVersion_minor; - $info['audio']['channels'] = $info['riff']['audio'][0]['channels']; - $info['audio']['sample_rate'] = $info['riff']['audio'][0]['sample_rate']; - $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample']; - $info['playtime_seconds'] = $OrignalRIFFdataSize / ($info['audio']['channels'] * $info['audio']['sample_rate'] * ($info['audio']['bits_per_sample'] / 8)); - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - unset($getid3_riff, $getid3_temp, $RIFFdata); - - return true; - } - - - public function ParseOptimFROGheader45() { - // for fileformat of v4.50a and higher - - $info = &$this->getid3->info; - $RIFFdata = ''; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < $info['avdataend'])) { - $BlockOffset = ftell($this->getid3->fp); - $BlockData = fread($this->getid3->fp, 8); - $offset = 8; - $BlockName = substr($BlockData, 0, 4); - $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4)); - - if ($BlockName == 'OFRX') { - $BlockName = 'OFR '; - } - if (!isset($info['ofr'][$BlockName])) { - $info['ofr'][$BlockName] = array(); - } - $thisfile_ofr_thisblock = &$info['ofr'][$BlockName]; - - switch ($BlockName) { - case 'OFR ': - - // shortcut - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - $info['audio']['encoder'] = 'OptimFROG 4.50 alpha'; - switch ($BlockSize) { - case 12: - case 15: - // good - break; - - default: - $info['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)'; - break; - } - $BlockData .= fread($this->getid3->fp, $BlockSize); - - $thisfile_ofr_thisblock['total_samples'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 6)); - $offset += 6; - $thisfile_ofr_thisblock['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); - $thisfile_ofr_thisblock['sample_type'] = $this->OptimFROGsampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']); - $offset += 1; - $thisfile_ofr_thisblock['channel_config'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); - $thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config']; - $offset += 1; - $thisfile_ofr_thisblock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); - $offset += 4; - - if ($BlockSize > 12) { - - // OFR 4.504b or higher - $thisfile_ofr_thisblock['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($thisfile_ofr_thisblock['channel_config']); - $thisfile_ofr_thisblock['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); - $thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']); - $offset += 2; - $thisfile_ofr_thisblock['raw']['compression'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); - $thisfile_ofr_thisblock['compression'] = $this->OptimFROGcompressionLookup($thisfile_ofr_thisblock['raw']['compression']); - $thisfile_ofr_thisblock['speedup'] = $this->OptimFROGspeedupLookup($thisfile_ofr_thisblock['raw']['compression']); - $offset += 1; - - $info['audio']['encoder'] = 'OptimFROG '.$thisfile_ofr_thisblock['encoder']; - $info['audio']['encoder_options'] = '--mode '.$thisfile_ofr_thisblock['compression']; - - if ((($thisfile_ofr_thisblock['raw']['encoder_id'] & 0xF0) >> 4) == 7) { // v4.507 - if (strtolower(getid3_lib::fileextension($info['filename'])) == 'ofs') { - // OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference - // between lossless and lossy other than the file extension. - $info['audio']['dataformat'] = 'ofs'; - $info['audio']['lossless'] = true; - } - } - - } - - $info['audio']['channels'] = $thisfile_ofr_thisblock['channels']; - $info['audio']['sample_rate'] = $thisfile_ofr_thisblock['sample_rate']; - $info['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']); - break; - - - case 'COMP': - // unlike other block types, there CAN be multiple COMP blocks - - $COMPdata['offset'] = $BlockOffset; - $COMPdata['size'] = $BlockSize; - - if ($info['avdataoffset'] == 0) { - $info['avdataoffset'] = $BlockOffset; - } - - // Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data - $BlockData .= fread($this->getid3->fp, 14); - fseek($this->getid3->fp, $BlockSize - 14, SEEK_CUR); - - $COMPdata['crc_32'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); - $offset += 4; - $COMPdata['sample_count'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); - $offset += 4; - $COMPdata['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); - $COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']); - $offset += 1; - $COMPdata['raw']['channel_configuration'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); - $COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']); - $offset += 1; - $COMPdata['raw']['algorithm_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); - //$COMPdata['algorithm'] = OptimFROGalgorithmNameLookup($COMPdata['raw']['algorithm_id']); - $offset += 2; - - if ($info['ofr']['OFR ']['size'] > 12) { - - // OFR 4.504b or higher - $COMPdata['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); - $COMPdata['encoder'] = $this->OptimFROGencoderNameLookup($COMPdata['raw']['encoder_id']); - $offset += 2; - - } - - if ($COMPdata['crc_32'] == 0x454E4F4E) { - // ASCII value of 'NONE' - placeholder value in v4.50a - $COMPdata['crc_32'] = false; - } - - $thisfile_ofr_thisblock[] = $COMPdata; - break; - - case 'HEAD': - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - $RIFFdata .= fread($this->getid3->fp, $BlockSize); - break; - - case 'TAIL': - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - if ($BlockSize > 0) { - $RIFFdata .= fread($this->getid3->fp, $BlockSize); - } - break; - - case 'RECV': - // block contains no useful meta data - simply note and skip - - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - break; - - - case 'APET': - // APEtag v2 - - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - $info['warning'][] = 'APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()'; - - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - break; - - - case 'MD5 ': - // APEtag v2 - - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - if ($BlockSize == 16) { - - $thisfile_ofr_thisblock['md5_binary'] = fread($this->getid3->fp, $BlockSize); - $thisfile_ofr_thisblock['md5_string'] = getid3_lib::PrintHexBytes($thisfile_ofr_thisblock['md5_binary'], true, false, false); - $info['md5_data_source'] = $thisfile_ofr_thisblock['md5_string']; - - } else { - - $info['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead'; - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - - } - break; - - - default: - $thisfile_ofr_thisblock['offset'] = $BlockOffset; - $thisfile_ofr_thisblock['size'] = $BlockSize; - - $info['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset']; - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - break; - } - } - if (isset($info['ofr']['TAIL']['offset'])) { - $info['avdataend'] = $info['ofr']['TAIL']['offset']; - } - - $info['playtime_seconds'] = (float) $info['ofr']['OFR ']['total_samples'] / ($info['audio']['channels'] * $info['audio']['sample_rate']); - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - // move the data chunk after all other chunks (if any) - // so that the RIFF parser doesn't see EOF when trying - // to skip over the data chunk - $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; - $getid3_temp->info['avdataend'] = $info['avdataend']; - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->ParseRIFFdata($RIFFdata); - $info['riff'] = $getid3_temp->info['riff']; - - unset($getid3_riff, $getid3_temp, $RIFFdata); - - return true; - } - - - public static function OptimFROGsampleTypeLookup($SampleType) { - static $OptimFROGsampleTypeLookup = array( - 0 => 'unsigned int (8-bit)', - 1 => 'signed int (8-bit)', - 2 => 'unsigned int (16-bit)', - 3 => 'signed int (16-bit)', - 4 => 'unsigned int (24-bit)', - 5 => 'signed int (24-bit)', - 6 => 'unsigned int (32-bit)', - 7 => 'signed int (32-bit)', - 8 => 'float 0.24 (32-bit)', - 9 => 'float 16.8 (32-bit)', - 10 => 'float 24.0 (32-bit)' - ); - return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false); - } - - public static function OptimFROGbitsPerSampleTypeLookup($SampleType) { - static $OptimFROGbitsPerSampleTypeLookup = array( - 0 => 8, - 1 => 8, - 2 => 16, - 3 => 16, - 4 => 24, - 5 => 24, - 6 => 32, - 7 => 32, - 8 => 32, - 9 => 32, - 10 => 32 - ); - return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false); - } - - public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) { - static $OptimFROGchannelConfigurationLookup = array( - 0 => 'mono', - 1 => 'stereo' - ); - return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false); - } - - public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) { - static $OptimFROGchannelConfigNumChannelsLookup = array( - 0 => 1, - 1 => 2 - ); - return (isset($OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration] : false); - } - - - - // static function OptimFROGalgorithmNameLookup($AlgorithID) { - // static $OptimFROGalgorithmNameLookup = array(); - // return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false); - // } - - - public static function OptimFROGencoderNameLookup($EncoderID) { - // version = (encoderID >> 4) + 4500 - // system = encoderID & 0xF - - $EncoderVersion = number_format(((($EncoderID & 0xF0) >> 4) + 4500) / 1000, 3); - $EncoderSystemID = ($EncoderID & 0x0F); - - static $OptimFROGencoderSystemLookup = array( - 0x00 => 'Windows console', - 0x01 => 'Linux console', - 0x0F => 'unknown' - ); - return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')'; - } - - public static function OptimFROGcompressionLookup($CompressionID) { - // mode = compression >> 3 - // speedup = compression & 0x07 - - $CompressionModeID = ($CompressionID & 0xF8) >> 3; - //$CompressionSpeedupID = ($CompressionID & 0x07); - - static $OptimFROGencoderModeLookup = array( - 0x00 => 'fast', - 0x01 => 'normal', - 0x02 => 'high', - 0x03 => 'extra', // extranew (some versions) - 0x04 => 'best', // bestnew (some versions) - 0x05 => 'ultra', - 0x06 => 'insane', - 0x07 => 'highnew', - 0x08 => 'extranew', - 0x09 => 'bestnew' - ); - return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')'); - } - - public static function OptimFROGspeedupLookup($CompressionID) { - // mode = compression >> 3 - // speedup = compression & 0x07 - - //$CompressionModeID = ($CompressionID & 0xF8) >> 3; - $CompressionSpeedupID = ($CompressionID & 0x07); - - static $OptimFROGencoderSpeedupLookup = array( - 0x00 => '1x', - 0x01 => '2x', - 0x02 => '4x' - ); - return (isset($OptimFROGencoderSpeedupLookup[$CompressionSpeedupID]) ? $OptimFROGencoderSpeedupLookup[$CompressionSpeedupID] : 'undefined mode (0x'.dechex($CompressionSpeedupID)); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.optimfrog.php // +// module for analyzing OptimFROG audio files // +// dependencies: module.audio.riff.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + +class getid3_optimfrog extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'ofr'; + $info['audio']['dataformat'] = 'ofr'; + $info['audio']['bitrate_mode'] = 'vbr'; + $info['audio']['lossless'] = true; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $OFRheader = fread($this->getid3->fp, 8); + if (substr($OFRheader, 0, 5) == '*RIFF') { + + return $this->ParseOptimFROGheader42(); + + } elseif (substr($OFRheader, 0, 3) == 'OFR') { + + return $this->ParseOptimFROGheader45(); + + } + + $info['error'][] = 'Expecting "*RIFF" or "OFR " at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($OFRheader).'"'; + unset($info['fileformat']); + return false; + } + + + public function ParseOptimFROGheader42() { + // for fileformat of v4.21 and older + + $info = &$this->getid3->info; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $OptimFROGheaderData = fread($this->getid3->fp, 45); + $info['avdataoffset'] = 45; + + $OptimFROGencoderVersion_raw = getid3_lib::LittleEndian2Int(substr($OptimFROGheaderData, 0, 1)); + $OptimFROGencoderVersion_major = floor($OptimFROGencoderVersion_raw / 10); + $OptimFROGencoderVersion_minor = $OptimFROGencoderVersion_raw - ($OptimFROGencoderVersion_major * 10); + $RIFFdata = substr($OptimFROGheaderData, 1, 44); + $OrignalRIFFheaderSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 4, 4)) + 8; + $OrignalRIFFdataSize = getid3_lib::LittleEndian2Int(substr($RIFFdata, 40, 4)) + 44; + + if ($OrignalRIFFheaderSize > $OrignalRIFFdataSize) { + $info['avdataend'] -= ($OrignalRIFFheaderSize - $OrignalRIFFdataSize); + fseek($this->getid3->fp, $info['avdataend'], SEEK_SET); + $RIFFdata .= fread($this->getid3->fp, $OrignalRIFFheaderSize - $OrignalRIFFdataSize); + } + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_temp->info['avdataend'] = $info['avdataend']; + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->ParseRIFFdata($RIFFdata); + $info['riff'] = $getid3_temp->info['riff']; + + $info['audio']['encoder'] = 'OptimFROG '.$OptimFROGencoderVersion_major.'.'.$OptimFROGencoderVersion_minor; + $info['audio']['channels'] = $info['riff']['audio'][0]['channels']; + $info['audio']['sample_rate'] = $info['riff']['audio'][0]['sample_rate']; + $info['audio']['bits_per_sample'] = $info['riff']['audio'][0]['bits_per_sample']; + $info['playtime_seconds'] = $OrignalRIFFdataSize / ($info['audio']['channels'] * $info['audio']['sample_rate'] * ($info['audio']['bits_per_sample'] / 8)); + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + unset($getid3_riff, $getid3_temp, $RIFFdata); + + return true; + } + + + public function ParseOptimFROGheader45() { + // for fileformat of v4.50a and higher + + $info = &$this->getid3->info; + $RIFFdata = ''; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < $info['avdataend'])) { + $BlockOffset = ftell($this->getid3->fp); + $BlockData = fread($this->getid3->fp, 8); + $offset = 8; + $BlockName = substr($BlockData, 0, 4); + $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4)); + + if ($BlockName == 'OFRX') { + $BlockName = 'OFR '; + } + if (!isset($info['ofr'][$BlockName])) { + $info['ofr'][$BlockName] = array(); + } + $thisfile_ofr_thisblock = &$info['ofr'][$BlockName]; + + switch ($BlockName) { + case 'OFR ': + + // shortcut + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + $info['audio']['encoder'] = 'OptimFROG 4.50 alpha'; + switch ($BlockSize) { + case 12: + case 15: + // good + break; + + default: + $info['warning'][] = '"'.$BlockName.'" contains more data than expected (expected 12 or 15 bytes, found '.$BlockSize.' bytes)'; + break; + } + $BlockData .= fread($this->getid3->fp, $BlockSize); + + $thisfile_ofr_thisblock['total_samples'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 6)); + $offset += 6; + $thisfile_ofr_thisblock['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); + $thisfile_ofr_thisblock['sample_type'] = $this->OptimFROGsampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']); + $offset += 1; + $thisfile_ofr_thisblock['channel_config'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); + $thisfile_ofr_thisblock['channels'] = $thisfile_ofr_thisblock['channel_config']; + $offset += 1; + $thisfile_ofr_thisblock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); + $offset += 4; + + if ($BlockSize > 12) { + + // OFR 4.504b or higher + $thisfile_ofr_thisblock['channels'] = $this->OptimFROGchannelConfigNumChannelsLookup($thisfile_ofr_thisblock['channel_config']); + $thisfile_ofr_thisblock['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); + $thisfile_ofr_thisblock['encoder'] = $this->OptimFROGencoderNameLookup($thisfile_ofr_thisblock['raw']['encoder_id']); + $offset += 2; + $thisfile_ofr_thisblock['raw']['compression'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); + $thisfile_ofr_thisblock['compression'] = $this->OptimFROGcompressionLookup($thisfile_ofr_thisblock['raw']['compression']); + $thisfile_ofr_thisblock['speedup'] = $this->OptimFROGspeedupLookup($thisfile_ofr_thisblock['raw']['compression']); + $offset += 1; + + $info['audio']['encoder'] = 'OptimFROG '.$thisfile_ofr_thisblock['encoder']; + $info['audio']['encoder_options'] = '--mode '.$thisfile_ofr_thisblock['compression']; + + if ((($thisfile_ofr_thisblock['raw']['encoder_id'] & 0xF0) >> 4) == 7) { // v4.507 + if (strtolower(getid3_lib::fileextension($info['filename'])) == 'ofs') { + // OptimFROG DualStream format is lossy, but as of v4.507 there is no way to tell the difference + // between lossless and lossy other than the file extension. + $info['audio']['dataformat'] = 'ofs'; + $info['audio']['lossless'] = true; + } + } + + } + + $info['audio']['channels'] = $thisfile_ofr_thisblock['channels']; + $info['audio']['sample_rate'] = $thisfile_ofr_thisblock['sample_rate']; + $info['audio']['bits_per_sample'] = $this->OptimFROGbitsPerSampleTypeLookup($thisfile_ofr_thisblock['raw']['sample_type']); + break; + + + case 'COMP': + // unlike other block types, there CAN be multiple COMP blocks + + $COMPdata['offset'] = $BlockOffset; + $COMPdata['size'] = $BlockSize; + + if ($info['avdataoffset'] == 0) { + $info['avdataoffset'] = $BlockOffset; + } + + // Only interested in first 14 bytes (only first 12 needed for v4.50 alpha), not actual audio data + $BlockData .= fread($this->getid3->fp, 14); + fseek($this->getid3->fp, $BlockSize - 14, SEEK_CUR); + + $COMPdata['crc_32'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); + $offset += 4; + $COMPdata['sample_count'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 4)); + $offset += 4; + $COMPdata['raw']['sample_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); + $COMPdata['sample_type'] = $this->OptimFROGsampleTypeLookup($COMPdata['raw']['sample_type']); + $offset += 1; + $COMPdata['raw']['channel_configuration'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 1)); + $COMPdata['channel_configuration'] = $this->OptimFROGchannelConfigurationLookup($COMPdata['raw']['channel_configuration']); + $offset += 1; + $COMPdata['raw']['algorithm_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); + //$COMPdata['algorithm'] = OptimFROGalgorithmNameLookup($COMPdata['raw']['algorithm_id']); + $offset += 2; + + if ($info['ofr']['OFR ']['size'] > 12) { + + // OFR 4.504b or higher + $COMPdata['raw']['encoder_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, $offset, 2)); + $COMPdata['encoder'] = $this->OptimFROGencoderNameLookup($COMPdata['raw']['encoder_id']); + $offset += 2; + + } + + if ($COMPdata['crc_32'] == 0x454E4F4E) { + // ASCII value of 'NONE' - placeholder value in v4.50a + $COMPdata['crc_32'] = false; + } + + $thisfile_ofr_thisblock[] = $COMPdata; + break; + + case 'HEAD': + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + $RIFFdata .= fread($this->getid3->fp, $BlockSize); + break; + + case 'TAIL': + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + if ($BlockSize > 0) { + $RIFFdata .= fread($this->getid3->fp, $BlockSize); + } + break; + + case 'RECV': + // block contains no useful meta data - simply note and skip + + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + break; + + + case 'APET': + // APEtag v2 + + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + $info['warning'][] = 'APEtag processing inside OptimFROG not supported in this version ('.$this->getid3->version().') of getID3()'; + + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + break; + + + case 'MD5 ': + // APEtag v2 + + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + if ($BlockSize == 16) { + + $thisfile_ofr_thisblock['md5_binary'] = fread($this->getid3->fp, $BlockSize); + $thisfile_ofr_thisblock['md5_string'] = getid3_lib::PrintHexBytes($thisfile_ofr_thisblock['md5_binary'], true, false, false); + $info['md5_data_source'] = $thisfile_ofr_thisblock['md5_string']; + + } else { + + $info['warning'][] = 'Expecting block size of 16 in "MD5 " chunk, found '.$BlockSize.' instead'; + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + + } + break; + + + default: + $thisfile_ofr_thisblock['offset'] = $BlockOffset; + $thisfile_ofr_thisblock['size'] = $BlockSize; + + $info['warning'][] = 'Unhandled OptimFROG block type "'.$BlockName.'" at offset '.$thisfile_ofr_thisblock['offset']; + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + break; + } + } + if (isset($info['ofr']['TAIL']['offset'])) { + $info['avdataend'] = $info['ofr']['TAIL']['offset']; + } + + $info['playtime_seconds'] = (float) $info['ofr']['OFR ']['total_samples'] / ($info['audio']['channels'] * $info['audio']['sample_rate']); + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + // move the data chunk after all other chunks (if any) + // so that the RIFF parser doesn't see EOF when trying + // to skip over the data chunk + $RIFFdata = substr($RIFFdata, 0, 36).substr($RIFFdata, 44).substr($RIFFdata, 36, 8); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataoffset'] = $info['avdataoffset']; + $getid3_temp->info['avdataend'] = $info['avdataend']; + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->ParseRIFFdata($RIFFdata); + $info['riff'] = $getid3_temp->info['riff']; + + unset($getid3_riff, $getid3_temp, $RIFFdata); + + return true; + } + + + public static function OptimFROGsampleTypeLookup($SampleType) { + static $OptimFROGsampleTypeLookup = array( + 0 => 'unsigned int (8-bit)', + 1 => 'signed int (8-bit)', + 2 => 'unsigned int (16-bit)', + 3 => 'signed int (16-bit)', + 4 => 'unsigned int (24-bit)', + 5 => 'signed int (24-bit)', + 6 => 'unsigned int (32-bit)', + 7 => 'signed int (32-bit)', + 8 => 'float 0.24 (32-bit)', + 9 => 'float 16.8 (32-bit)', + 10 => 'float 24.0 (32-bit)' + ); + return (isset($OptimFROGsampleTypeLookup[$SampleType]) ? $OptimFROGsampleTypeLookup[$SampleType] : false); + } + + public static function OptimFROGbitsPerSampleTypeLookup($SampleType) { + static $OptimFROGbitsPerSampleTypeLookup = array( + 0 => 8, + 1 => 8, + 2 => 16, + 3 => 16, + 4 => 24, + 5 => 24, + 6 => 32, + 7 => 32, + 8 => 32, + 9 => 32, + 10 => 32 + ); + return (isset($OptimFROGbitsPerSampleTypeLookup[$SampleType]) ? $OptimFROGbitsPerSampleTypeLookup[$SampleType] : false); + } + + public static function OptimFROGchannelConfigurationLookup($ChannelConfiguration) { + static $OptimFROGchannelConfigurationLookup = array( + 0 => 'mono', + 1 => 'stereo' + ); + return (isset($OptimFROGchannelConfigurationLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigurationLookup[$ChannelConfiguration] : false); + } + + public static function OptimFROGchannelConfigNumChannelsLookup($ChannelConfiguration) { + static $OptimFROGchannelConfigNumChannelsLookup = array( + 0 => 1, + 1 => 2 + ); + return (isset($OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration]) ? $OptimFROGchannelConfigNumChannelsLookup[$ChannelConfiguration] : false); + } + + + + // static function OptimFROGalgorithmNameLookup($AlgorithID) { + // static $OptimFROGalgorithmNameLookup = array(); + // return (isset($OptimFROGalgorithmNameLookup[$AlgorithID]) ? $OptimFROGalgorithmNameLookup[$AlgorithID] : false); + // } + + + public static function OptimFROGencoderNameLookup($EncoderID) { + // version = (encoderID >> 4) + 4500 + // system = encoderID & 0xF + + $EncoderVersion = number_format(((($EncoderID & 0xF0) >> 4) + 4500) / 1000, 3); + $EncoderSystemID = ($EncoderID & 0x0F); + + static $OptimFROGencoderSystemLookup = array( + 0x00 => 'Windows console', + 0x01 => 'Linux console', + 0x0F => 'unknown' + ); + return $EncoderVersion.' ('.(isset($OptimFROGencoderSystemLookup[$EncoderSystemID]) ? $OptimFROGencoderSystemLookup[$EncoderSystemID] : 'undefined encoder type (0x'.dechex($EncoderSystemID).')').')'; + } + + public static function OptimFROGcompressionLookup($CompressionID) { + // mode = compression >> 3 + // speedup = compression & 0x07 + + $CompressionModeID = ($CompressionID & 0xF8) >> 3; + //$CompressionSpeedupID = ($CompressionID & 0x07); + + static $OptimFROGencoderModeLookup = array( + 0x00 => 'fast', + 0x01 => 'normal', + 0x02 => 'high', + 0x03 => 'extra', // extranew (some versions) + 0x04 => 'best', // bestnew (some versions) + 0x05 => 'ultra', + 0x06 => 'insane', + 0x07 => 'highnew', + 0x08 => 'extranew', + 0x09 => 'bestnew' + ); + return (isset($OptimFROGencoderModeLookup[$CompressionModeID]) ? $OptimFROGencoderModeLookup[$CompressionModeID] : 'undefined mode (0x'.str_pad(dechex($CompressionModeID), 2, '0', STR_PAD_LEFT).')'); + } + + public static function OptimFROGspeedupLookup($CompressionID) { + // mode = compression >> 3 + // speedup = compression & 0x07 + + //$CompressionModeID = ($CompressionID & 0xF8) >> 3; + $CompressionSpeedupID = ($CompressionID & 0x07); + + static $OptimFROGencoderSpeedupLookup = array( + 0x00 => '1x', + 0x01 => '2x', + 0x02 => '4x' + ); + return (isset($OptimFROGencoderSpeedupLookup[$CompressionSpeedupID]) ? $OptimFROGencoderSpeedupLookup[$CompressionSpeedupID] : 'undefined mode (0x'.dechex($CompressionSpeedupID)); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.rkau.php b/app/libs/vendor/getid3/module.audio.rkau.php index 34ad5575..0ea051bc 100644 --- a/app/libs/vendor/getid3/module.audio.rkau.php +++ b/app/libs/vendor/getid3/module.audio.rkau.php @@ -1,92 +1,92 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.shorten.php // -// module for analyzing Shorten Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_rkau extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $RKAUHeader = fread($this->getid3->fp, 20); - $magic = 'RKA'; - if (substr($RKAUHeader, 0, 3) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"'; - return false; - } - - $info['fileformat'] = 'rkau'; - $info['audio']['dataformat'] = 'rkau'; - $info['audio']['bitrate_mode'] = 'vbr'; - - $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1)); - $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT); - if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) { - $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')'; - unset($info['rkau']); - return false; - } - - $info['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4)); - $info['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4)); - $info['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1)); - $info['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1)); - - $info['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1)); - $this->RKAUqualityLookup($info['rkau']); - - $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1)); - $info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x01)); - $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02); - $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04); - - if ($info['rkau']['flags']['streaming']) { - $info['avdataoffset'] += 20; - $info['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4)); - } else { - $info['avdataoffset'] += 16; - $info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['avdataoffset'] - 1; - } - // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes, - // sometimes it's more, sometimes less. No idea why(?) - - $info['audio']['lossless'] = $info['rkau']['lossless']; - $info['audio']['channels'] = $info['rkau']['channels']; - $info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample']; - $info['audio']['sample_rate'] = $info['rkau']['sample_rate']; - - $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8)); - $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds']; - - return true; - - } - - - public function RKAUqualityLookup(&$RKAUdata) { - $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4; - $quality = $RKAUdata['raw']['quality'] & 0x0F; - - $RKAUdata['lossless'] = (($quality == 0) ? true : false); - $RKAUdata['compression_level'] = $level + 1; - if (!$RKAUdata['lossless']) { - $RKAUdata['quality_setting'] = $quality; - } - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.shorten.php // +// module for analyzing Shorten Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_rkau extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $RKAUHeader = fread($this->getid3->fp, 20); + $magic = 'RKA'; + if (substr($RKAUHeader, 0, 3) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($RKAUHeader, 0, 3)).'"'; + return false; + } + + $info['fileformat'] = 'rkau'; + $info['audio']['dataformat'] = 'rkau'; + $info['audio']['bitrate_mode'] = 'vbr'; + + $info['rkau']['raw']['version'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 3, 1)); + $info['rkau']['version'] = '1.'.str_pad($info['rkau']['raw']['version'] & 0x0F, 2, '0', STR_PAD_LEFT); + if (($info['rkau']['version'] > 1.07) || ($info['rkau']['version'] < 1.06)) { + $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] can only parse RKAU files v1.06 and 1.07 (this file is v'.$info['rkau']['version'].')'; + unset($info['rkau']); + return false; + } + + $info['rkau']['source_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 4, 4)); + $info['rkau']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 8, 4)); + $info['rkau']['channels'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 12, 1)); + $info['rkau']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 13, 1)); + + $info['rkau']['raw']['quality'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 14, 1)); + $this->RKAUqualityLookup($info['rkau']); + + $info['rkau']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 15, 1)); + $info['rkau']['flags']['joint_stereo'] = (bool) (!($info['rkau']['raw']['flags'] & 0x01)); + $info['rkau']['flags']['streaming'] = (bool) ($info['rkau']['raw']['flags'] & 0x02); + $info['rkau']['flags']['vrq_lossy_mode'] = (bool) ($info['rkau']['raw']['flags'] & 0x04); + + if ($info['rkau']['flags']['streaming']) { + $info['avdataoffset'] += 20; + $info['rkau']['compressed_bytes'] = getid3_lib::LittleEndian2Int(substr($RKAUHeader, 16, 4)); + } else { + $info['avdataoffset'] += 16; + $info['rkau']['compressed_bytes'] = $info['avdataend'] - $info['avdataoffset'] - 1; + } + // Note: compressed_bytes does not always equal what appears to be the actual number of compressed bytes, + // sometimes it's more, sometimes less. No idea why(?) + + $info['audio']['lossless'] = $info['rkau']['lossless']; + $info['audio']['channels'] = $info['rkau']['channels']; + $info['audio']['bits_per_sample'] = $info['rkau']['bits_per_sample']; + $info['audio']['sample_rate'] = $info['rkau']['sample_rate']; + + $info['playtime_seconds'] = $info['rkau']['source_bytes'] / ($info['rkau']['sample_rate'] * $info['rkau']['channels'] * ($info['rkau']['bits_per_sample'] / 8)); + $info['audio']['bitrate'] = ($info['rkau']['compressed_bytes'] * 8) / $info['playtime_seconds']; + + return true; + + } + + + public function RKAUqualityLookup(&$RKAUdata) { + $level = ($RKAUdata['raw']['quality'] & 0xF0) >> 4; + $quality = $RKAUdata['raw']['quality'] & 0x0F; + + $RKAUdata['lossless'] = (($quality == 0) ? true : false); + $RKAUdata['compression_level'] = $level + 1; + if (!$RKAUdata['lossless']) { + $RKAUdata['quality_setting'] = $quality; + } + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.shorten.php b/app/libs/vendor/getid3/module.audio.shorten.php index cfc1677c..a047f16f 100644 --- a/app/libs/vendor/getid3/module.audio.shorten.php +++ b/app/libs/vendor/getid3/module.audio.shorten.php @@ -1,181 +1,181 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.shorten.php // -// module for analyzing Shorten Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_shorten extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $ShortenHeader = fread($this->getid3->fp, 8); - $magic = 'ajkg'; - if (substr($ShortenHeader, 0, 4) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"'; - return false; - } - $info['fileformat'] = 'shn'; - $info['audio']['dataformat'] = 'shn'; - $info['audio']['lossless'] = true; - $info['audio']['bitrate_mode'] = 'vbr'; - - $info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1)); - - fseek($this->getid3->fp, $info['avdataend'] - 12, SEEK_SET); - $SeekTableSignatureTest = fread($this->getid3->fp, 12); - $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK'); - if ($info['shn']['seektable']['present']) { - $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4)); - $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length']; - fseek($this->getid3->fp, $info['shn']['seektable']['offset'], SEEK_SET); - $SeekTableMagic = fread($this->getid3->fp, 4); - $magic = 'SEEK'; - if ($SeekTableMagic != $magic) { - - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"'; - return false; - - } else { - - // typedef struct tag_TSeekEntry - // { - // unsigned long SampleNumber; - // unsigned long SHNFileByteOffset; - // unsigned long SHNLastBufferReadPosition; - // unsigned short SHNByteGet; - // unsigned short SHNBufferOffset; - // unsigned short SHNFileBitOffset; - // unsigned long SHNGBuffer; - // unsigned short SHNBitShift; - // long CBuf0[3]; - // long CBuf1[3]; - // long Offset0[4]; - // long Offset1[4]; - // }TSeekEntry; - - $SeekTableData = fread($this->getid3->fp, $info['shn']['seektable']['length'] - 16); - $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80); - //$info['shn']['seektable']['entries'] = array(); - //$SeekTableOffset = 0; - //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) { - // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); - // $SeekTableOffset += 2; - // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); - // $SeekTableOffset += 2; - // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); - // $SeekTableOffset += 2; - // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); - // $SeekTableOffset += 2; - // for ($j = 0; $j < 3; $j++) { - // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // } - // for ($j = 0; $j < 3; $j++) { - // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // } - // for ($j = 0; $j < 4; $j++) { - // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // } - // for ($j = 0; $j < 4; $j++) { - // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); - // $SeekTableOffset += 4; - // } - // - // $info['shn']['seektable']['entries'][] = $SeekTableEntry; - //} - - } - - } - - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'; - return false; - } - - if (GETID3_OS_ISWINDOWS) { - - $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe'); - foreach ($RequiredFiles as $required_file) { - if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { - $info['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist'; - return false; - } - } - $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64'; - $commandline = str_replace('/', '\\', $commandline); - - } else { - - static $shorten_present; - if (!isset($shorten_present)) { - $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; - } - if (!$shorten_present) { - $info['error'][] = 'shorten binary was not found in path or /usr/local/bin'; - return false; - } - $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64'; - - } - - $output = `$commandline`; - - if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) { - - getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - - $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4)); - $DecodedWAVFORMATEX = getid3_riff::parseWAVEFORMATex(substr($output, 20, $fmt_size)); - $info['audio']['channels'] = $DecodedWAVFORMATEX['channels']; - $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample']; - $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate']; - - if (substr($output, 20 + $fmt_size, 4) == 'data') { - - $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; - - } else { - - $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime'; - return false; - - } - - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8; - - } else { - - $info['error'][] = 'shorten failed to decode file to WAV for parsing'; - return false; - - } - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.shorten.php // +// module for analyzing Shorten Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_shorten extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $ShortenHeader = fread($this->getid3->fp, 8); + $magic = 'ajkg'; + if (substr($ShortenHeader, 0, 4) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($ShortenHeader, 0, 4)).'"'; + return false; + } + $info['fileformat'] = 'shn'; + $info['audio']['dataformat'] = 'shn'; + $info['audio']['lossless'] = true; + $info['audio']['bitrate_mode'] = 'vbr'; + + $info['shn']['version'] = getid3_lib::LittleEndian2Int(substr($ShortenHeader, 4, 1)); + + fseek($this->getid3->fp, $info['avdataend'] - 12, SEEK_SET); + $SeekTableSignatureTest = fread($this->getid3->fp, 12); + $info['shn']['seektable']['present'] = (bool) (substr($SeekTableSignatureTest, 4, 8) == 'SHNAMPSK'); + if ($info['shn']['seektable']['present']) { + $info['shn']['seektable']['length'] = getid3_lib::LittleEndian2Int(substr($SeekTableSignatureTest, 0, 4)); + $info['shn']['seektable']['offset'] = $info['avdataend'] - $info['shn']['seektable']['length']; + fseek($this->getid3->fp, $info['shn']['seektable']['offset'], SEEK_SET); + $SeekTableMagic = fread($this->getid3->fp, 4); + $magic = 'SEEK'; + if ($SeekTableMagic != $magic) { + + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['shn']['seektable']['offset'].', found "'.getid3_lib::PrintHexBytes($SeekTableMagic).'"'; + return false; + + } else { + + // typedef struct tag_TSeekEntry + // { + // unsigned long SampleNumber; + // unsigned long SHNFileByteOffset; + // unsigned long SHNLastBufferReadPosition; + // unsigned short SHNByteGet; + // unsigned short SHNBufferOffset; + // unsigned short SHNFileBitOffset; + // unsigned long SHNGBuffer; + // unsigned short SHNBitShift; + // long CBuf0[3]; + // long CBuf1[3]; + // long Offset0[4]; + // long Offset1[4]; + // }TSeekEntry; + + $SeekTableData = fread($this->getid3->fp, $info['shn']['seektable']['length'] - 16); + $info['shn']['seektable']['entry_count'] = floor(strlen($SeekTableData) / 80); + //$info['shn']['seektable']['entries'] = array(); + //$SeekTableOffset = 0; + //for ($i = 0; $i < $info['shn']['seektable']['entry_count']; $i++) { + // $SeekTableEntry['sample_number'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_file_byte_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_last_buffer_read_position'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_byte_get'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_buffer_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_file_bit_offset'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // $SeekTableEntry['shn_gbuffer'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // $SeekTableEntry['shn_bit_shift'] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 2)); + // $SeekTableOffset += 2; + // for ($j = 0; $j < 3; $j++) { + // $SeekTableEntry['cbuf0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 3; $j++) { + // $SeekTableEntry['cbuf1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 4; $j++) { + // $SeekTableEntry['offset0'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // for ($j = 0; $j < 4; $j++) { + // $SeekTableEntry['offset1'][$j] = getid3_lib::LittleEndian2Int(substr($SeekTableData, $SeekTableOffset, 4)); + // $SeekTableOffset += 4; + // } + // + // $info['shn']['seektable']['entries'][] = $SeekTableEntry; + //} + + } + + } + + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + $info['error'][] = 'PHP running in Safe Mode - backtick operator not available, cannot run shntool to analyze Shorten files'; + return false; + } + + if (GETID3_OS_ISWINDOWS) { + + $RequiredFiles = array('shorten.exe', 'cygwin1.dll', 'head.exe'); + foreach ($RequiredFiles as $required_file) { + if (!is_readable(GETID3_HELPERAPPSDIR.$required_file)) { + $info['error'][] = GETID3_HELPERAPPSDIR.$required_file.' does not exist'; + return false; + } + } + $commandline = GETID3_HELPERAPPSDIR.'shorten.exe -x "'.$info['filenamepath'].'" - | '.GETID3_HELPERAPPSDIR.'head.exe -c 64'; + $commandline = str_replace('/', '\\', $commandline); + + } else { + + static $shorten_present; + if (!isset($shorten_present)) { + $shorten_present = file_exists('/usr/local/bin/shorten') || `which shorten`; + } + if (!$shorten_present) { + $info['error'][] = 'shorten binary was not found in path or /usr/local/bin'; + return false; + } + $commandline = (file_exists('/usr/local/bin/shorten') ? '/usr/local/bin/' : '' ) . 'shorten -x '.escapeshellarg($info['filenamepath']).' - | head -c 64'; + + } + + $output = `$commandline`; + + if (!empty($output) && (substr($output, 12, 4) == 'fmt ')) { + + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + + $fmt_size = getid3_lib::LittleEndian2Int(substr($output, 16, 4)); + $DecodedWAVFORMATEX = getid3_riff::parseWAVEFORMATex(substr($output, 20, $fmt_size)); + $info['audio']['channels'] = $DecodedWAVFORMATEX['channels']; + $info['audio']['bits_per_sample'] = $DecodedWAVFORMATEX['bits_per_sample']; + $info['audio']['sample_rate'] = $DecodedWAVFORMATEX['sample_rate']; + + if (substr($output, 20 + $fmt_size, 4) == 'data') { + + $info['playtime_seconds'] = getid3_lib::LittleEndian2Int(substr($output, 20 + 4 + $fmt_size, 4)) / $DecodedWAVFORMATEX['raw']['nAvgBytesPerSec']; + + } else { + + $info['error'][] = 'shorten failed to decode DATA chunk to expected location, cannot determine playtime'; + return false; + + } + + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) / $info['playtime_seconds']) * 8; + + } else { + + $info['error'][] = 'shorten failed to decode file to WAV for parsing'; + return false; + + } + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.tta.php b/app/libs/vendor/getid3/module.audio.tta.php index 6d990d8d..a3056db6 100644 --- a/app/libs/vendor/getid3/module.audio.tta.php +++ b/app/libs/vendor/getid3/module.audio.tta.php @@ -1,106 +1,106 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.tta.php // -// module for analyzing TTA Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_tta extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'tta'; - $info['audio']['dataformat'] = 'tta'; - $info['audio']['lossless'] = true; - $info['audio']['bitrate_mode'] = 'vbr'; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $ttaheader = fread($this->getid3->fp, 26); - - $info['tta']['magic'] = substr($ttaheader, 0, 3); - $magic = 'TTA'; - if ($info['tta']['magic'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"'; - unset($info['fileformat']); - unset($info['audio']); - unset($info['tta']); - return false; - } - - switch ($ttaheader{3}) { - case "\x01": // TTA v1.x - case "\x02": // TTA v1.x - case "\x03": // TTA v1.x - // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year." - $info['tta']['major_version'] = 1; - $info['avdataoffset'] += 16; - - $info['tta']['compression_level'] = ord($ttaheader{3}); - $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); - $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); - $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4)); - $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); - - $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate']; - break; - - case '2': // TTA v2.x - // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4." - $info['tta']['major_version'] = 2; - $info['avdataoffset'] += 20; - - $info['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); - $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); - $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); - $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2)); - $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); - $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4)); - - $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; - break; - - case '1': // TTA v3.x - // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher." - $info['tta']['major_version'] = 3; - $info['avdataoffset'] += 26; - - $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::wFormatTagLookup() - $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); - $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); - $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4)); - $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4)); - $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4); - $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4)); - - $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; - break; - - default: - $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3}; - return false; - break; - } - - $info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version']; - $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample']; - $info['audio']['sample_rate'] = $info['tta']['sample_rate']; - $info['audio']['channels'] = $info['tta']['channels']; - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.tta.php // +// module for analyzing TTA Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_tta extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'tta'; + $info['audio']['dataformat'] = 'tta'; + $info['audio']['lossless'] = true; + $info['audio']['bitrate_mode'] = 'vbr'; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $ttaheader = fread($this->getid3->fp, 26); + + $info['tta']['magic'] = substr($ttaheader, 0, 3); + $magic = 'TTA'; + if ($info['tta']['magic'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['tta']['magic']).'"'; + unset($info['fileformat']); + unset($info['audio']); + unset($info['tta']); + return false; + } + + switch ($ttaheader{3}) { + case "\x01": // TTA v1.x + case "\x02": // TTA v1.x + case "\x03": // TTA v1.x + // "It was the demo-version of the TTA encoder. There is no released format with such header. TTA encoder v1 is not supported about a year." + $info['tta']['major_version'] = 1; + $info['avdataoffset'] += 16; + + $info['tta']['compression_level'] = ord($ttaheader{3}); + $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); + $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); + $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 4)); + $info['tta']['samples_per_channel'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); + + $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; + $info['playtime_seconds'] = $info['tta']['samples_per_channel'] / $info['tta']['sample_rate']; + break; + + case '2': // TTA v2.x + // "I have hurried to release the TTA 2.0 encoder. Format documentation is removed from our site. This format still in development. Please wait the TTA2 format, encoder v4." + $info['tta']['major_version'] = 2; + $info['avdataoffset'] += 20; + + $info['tta']['compression_level'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); + $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); + $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); + $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 2)); + $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 12, 4)); + $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 16, 4)); + + $info['audio']['encoder_options'] = '-e'.$info['tta']['compression_level']; + $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + break; + + case '1': // TTA v3.x + // "This is a first stable release of the TTA format. It will be supported by the encoders v3 or higher." + $info['tta']['major_version'] = 3; + $info['avdataoffset'] += 26; + + $info['tta']['audio_format'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 4, 2)); // getid3_riff::wFormatTagLookup() + $info['tta']['channels'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 6, 2)); + $info['tta']['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 8, 2)); + $info['tta']['sample_rate'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 10, 4)); + $info['tta']['data_length'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 14, 4)); + $info['tta']['crc32_footer'] = substr($ttaheader, 18, 4); + $info['tta']['seek_point'] = getid3_lib::LittleEndian2Int(substr($ttaheader, 22, 4)); + + $info['playtime_seconds'] = $info['tta']['data_length'] / $info['tta']['sample_rate']; + break; + + default: + $info['error'][] = 'This version of getID3() ['.$this->getid3->version().'] only knows how to handle TTA v1 and v2 - it may not work correctly with this file which appears to be TTA v'.$ttaheader{3}; + return false; + break; + } + + $info['audio']['encoder'] = 'TTA v'.$info['tta']['major_version']; + $info['audio']['bits_per_sample'] = $info['tta']['bits_per_sample']; + $info['audio']['sample_rate'] = $info['tta']['sample_rate']; + $info['audio']['channels'] = $info['tta']['channels']; + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.audio.voc.php b/app/libs/vendor/getid3/module.audio.voc.php index 0220d049..e38fa482 100644 --- a/app/libs/vendor/getid3/module.audio.voc.php +++ b/app/libs/vendor/getid3/module.audio.voc.php @@ -1,204 +1,204 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.voc.php // -// module for analyzing Creative VOC Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_voc extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $OriginalAVdataOffset = $info['avdataoffset']; - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $VOCheader = fread($this->getid3->fp, 26); - - $magic = 'Creative Voice File'; - if (substr($VOCheader, 0, 19) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"'; - return false; - } - - // shortcuts - $thisfile_audio = &$info['audio']; - $info['voc'] = array(); - $thisfile_voc = &$info['voc']; - - $info['fileformat'] = 'voc'; - $thisfile_audio['dataformat'] = 'voc'; - $thisfile_audio['bitrate_mode'] = 'cbr'; - $thisfile_audio['lossless'] = true; - $thisfile_audio['channels'] = 1; // might be overriden below - $thisfile_audio['bits_per_sample'] = 8; // might be overriden below - - // byte # Description - // ------ ------------------------------------------ - // 00-12 'Creative Voice File' - // 13 1A (eof to abort printing of file) - // 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) - // 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) - // 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) - - $thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2)); - $thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1)); - $thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1)); - - do { - - $BlockOffset = ftell($this->getid3->fp); - $BlockData = fread($this->getid3->fp, 4); - $BlockType = ord($BlockData{0}); - $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3)); - $ThisBlock = array(); - - getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1); - switch ($BlockType) { - case 0: // Terminator - // do nothing, we'll break out of the loop down below - break; - - case 1: // Sound data - $BlockData .= fread($this->getid3->fp, 2); - if ($info['avdataoffset'] <= $OriginalAVdataOffset) { - $info['avdataoffset'] = ftell($this->getid3->fp); - } - fseek($this->getid3->fp, $BlockSize - 2, SEEK_CUR); - - $ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1)); - $ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1)); - - $ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']); - if ($ThisBlock['compression_type'] <= 3) { - $thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name'])); - } - - // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available) - if (empty($thisfile_audio['sample_rate'])) { - // SR byte = 256 - (1000000 / sample_rate) - $thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']); - } - break; - - case 2: // Sound continue - case 3: // Silence - case 4: // Marker - case 6: // Repeat - case 7: // End repeat - // nothing useful, just skip - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - break; - - case 8: // Extended - $BlockData .= fread($this->getid3->fp, 4); - - //00-01 Time Constant: - // Mono: 65536 - (256000000 / sample_rate) - // Stereo: 65536 - (256000000 / (sample_rate * 2)) - $ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2)); - $ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1)); - $ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1)); - - $thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1); - $thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']); - break; - - case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit - $BlockData .= fread($this->getid3->fp, 12); - if ($info['avdataoffset'] <= $OriginalAVdataOffset) { - $info['avdataoffset'] = ftell($this->getid3->fp); - } - fseek($this->getid3->fp, $BlockSize - 12, SEEK_CUR); - - $ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4)); - $ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1)); - $ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1)); - $ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2)); - - $ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']); - if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) { - $thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']); - } - - $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate']; - $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample']; - $thisfile_audio['channels'] = $ThisBlock['channels']; - break; - - default: - $info['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset; - fseek($this->getid3->fp, $BlockSize, SEEK_CUR); - break; - } - - if (!empty($ThisBlock)) { - $ThisBlock['block_offset'] = $BlockOffset; - $ThisBlock['block_size'] = $BlockSize; - $ThisBlock['block_type_id'] = $BlockType; - $thisfile_voc['blocks'][] = $ThisBlock; - } - - } while (!feof($this->getid3->fp) && ($BlockType != 0)); - - // Terminator block doesn't have size field, so seek back 3 spaces - fseek($this->getid3->fp, -3, SEEK_CUR); - - ksort($thisfile_voc['blocktypes']); - - if (!empty($thisfile_voc['compressed_bits_per_sample'])) { - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); - $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - } - - return true; - } - - public function VOCcompressionTypeLookup($index) { - static $VOCcompressionTypeLookup = array( - 0 => '8-bit', - 1 => '4-bit', - 2 => '2.6-bit', - 3 => '2-bit' - ); - return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels'); - } - - public function VOCwFormatLookup($index) { - static $VOCwFormatLookup = array( - 0x0000 => '8-bit unsigned PCM', - 0x0001 => 'Creative 8-bit to 4-bit ADPCM', - 0x0002 => 'Creative 8-bit to 3-bit ADPCM', - 0x0003 => 'Creative 8-bit to 2-bit ADPCM', - 0x0004 => '16-bit signed PCM', - 0x0006 => 'CCITT a-Law', - 0x0007 => 'CCITT u-Law', - 0x2000 => 'Creative 16-bit to 4-bit ADPCM' - ); - return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); - } - - public function VOCwFormatActualBitsPerSampleLookup($index) { - static $VOCwFormatLookup = array( - 0x0000 => 8, - 0x0001 => 4, - 0x0002 => 3, - 0x0003 => 2, - 0x0004 => 16, - 0x0006 => 8, - 0x0007 => 8, - 0x2000 => 4 - ); - return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.voc.php // +// module for analyzing Creative VOC Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_voc extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $OriginalAVdataOffset = $info['avdataoffset']; + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $VOCheader = fread($this->getid3->fp, 26); + + $magic = 'Creative Voice File'; + if (substr($VOCheader, 0, 19) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($VOCheader, 0, 19)).'"'; + return false; + } + + // shortcuts + $thisfile_audio = &$info['audio']; + $info['voc'] = array(); + $thisfile_voc = &$info['voc']; + + $info['fileformat'] = 'voc'; + $thisfile_audio['dataformat'] = 'voc'; + $thisfile_audio['bitrate_mode'] = 'cbr'; + $thisfile_audio['lossless'] = true; + $thisfile_audio['channels'] = 1; // might be overriden below + $thisfile_audio['bits_per_sample'] = 8; // might be overriden below + + // byte # Description + // ------ ------------------------------------------ + // 00-12 'Creative Voice File' + // 13 1A (eof to abort printing of file) + // 14-15 Offset of first datablock in .voc file (std 1A 00 in Intel Notation) + // 16-17 Version number (minor,major) (VOC-HDR puts 0A 01) + // 18-19 2's Comp of Ver. # + 1234h (VOC-HDR puts 29 11) + + $thisfile_voc['header']['datablock_offset'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 20, 2)); + $thisfile_voc['header']['minor_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 22, 1)); + $thisfile_voc['header']['major_version'] = getid3_lib::LittleEndian2Int(substr($VOCheader, 23, 1)); + + do { + + $BlockOffset = ftell($this->getid3->fp); + $BlockData = fread($this->getid3->fp, 4); + $BlockType = ord($BlockData{0}); + $BlockSize = getid3_lib::LittleEndian2Int(substr($BlockData, 1, 3)); + $ThisBlock = array(); + + getid3_lib::safe_inc($thisfile_voc['blocktypes'][$BlockType], 1); + switch ($BlockType) { + case 0: // Terminator + // do nothing, we'll break out of the loop down below + break; + + case 1: // Sound data + $BlockData .= fread($this->getid3->fp, 2); + if ($info['avdataoffset'] <= $OriginalAVdataOffset) { + $info['avdataoffset'] = ftell($this->getid3->fp); + } + fseek($this->getid3->fp, $BlockSize - 2, SEEK_CUR); + + $ThisBlock['sample_rate_id'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 1)); + $ThisBlock['compression_type'] = getid3_lib::LittleEndian2Int(substr($BlockData, 5, 1)); + + $ThisBlock['compression_name'] = $this->VOCcompressionTypeLookup($ThisBlock['compression_type']); + if ($ThisBlock['compression_type'] <= 3) { + $thisfile_voc['compressed_bits_per_sample'] = getid3_lib::CastAsInt(str_replace('-bit', '', $ThisBlock['compression_name'])); + } + + // Less accurate sample_rate calculation than the Extended block (#8) data (but better than nothing if Extended Block is not available) + if (empty($thisfile_audio['sample_rate'])) { + // SR byte = 256 - (1000000 / sample_rate) + $thisfile_audio['sample_rate'] = getid3_lib::trunc((1000000 / (256 - $ThisBlock['sample_rate_id'])) / $thisfile_audio['channels']); + } + break; + + case 2: // Sound continue + case 3: // Silence + case 4: // Marker + case 6: // Repeat + case 7: // End repeat + // nothing useful, just skip + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + break; + + case 8: // Extended + $BlockData .= fread($this->getid3->fp, 4); + + //00-01 Time Constant: + // Mono: 65536 - (256000000 / sample_rate) + // Stereo: 65536 - (256000000 / (sample_rate * 2)) + $ThisBlock['time_constant'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 2)); + $ThisBlock['pack_method'] = getid3_lib::LittleEndian2Int(substr($BlockData, 6, 1)); + $ThisBlock['stereo'] = (bool) getid3_lib::LittleEndian2Int(substr($BlockData, 7, 1)); + + $thisfile_audio['channels'] = ($ThisBlock['stereo'] ? 2 : 1); + $thisfile_audio['sample_rate'] = getid3_lib::trunc((256000000 / (65536 - $ThisBlock['time_constant'])) / $thisfile_audio['channels']); + break; + + case 9: // data block that supersedes blocks 1 and 8. Used for stereo, 16 bit + $BlockData .= fread($this->getid3->fp, 12); + if ($info['avdataoffset'] <= $OriginalAVdataOffset) { + $info['avdataoffset'] = ftell($this->getid3->fp); + } + fseek($this->getid3->fp, $BlockSize - 12, SEEK_CUR); + + $ThisBlock['sample_rate'] = getid3_lib::LittleEndian2Int(substr($BlockData, 4, 4)); + $ThisBlock['bits_per_sample'] = getid3_lib::LittleEndian2Int(substr($BlockData, 8, 1)); + $ThisBlock['channels'] = getid3_lib::LittleEndian2Int(substr($BlockData, 9, 1)); + $ThisBlock['wFormat'] = getid3_lib::LittleEndian2Int(substr($BlockData, 10, 2)); + + $ThisBlock['compression_name'] = $this->VOCwFormatLookup($ThisBlock['wFormat']); + if ($this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat'])) { + $thisfile_voc['compressed_bits_per_sample'] = $this->VOCwFormatActualBitsPerSampleLookup($ThisBlock['wFormat']); + } + + $thisfile_audio['sample_rate'] = $ThisBlock['sample_rate']; + $thisfile_audio['bits_per_sample'] = $ThisBlock['bits_per_sample']; + $thisfile_audio['channels'] = $ThisBlock['channels']; + break; + + default: + $info['warning'][] = 'Unhandled block type "'.$BlockType.'" at offset '.$BlockOffset; + fseek($this->getid3->fp, $BlockSize, SEEK_CUR); + break; + } + + if (!empty($ThisBlock)) { + $ThisBlock['block_offset'] = $BlockOffset; + $ThisBlock['block_size'] = $BlockSize; + $ThisBlock['block_type_id'] = $BlockType; + $thisfile_voc['blocks'][] = $ThisBlock; + } + + } while (!feof($this->getid3->fp) && ($BlockType != 0)); + + // Terminator block doesn't have size field, so seek back 3 spaces + fseek($this->getid3->fp, -3, SEEK_CUR); + + ksort($thisfile_voc['blocktypes']); + + if (!empty($thisfile_voc['compressed_bits_per_sample'])) { + $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / ($thisfile_voc['compressed_bits_per_sample'] * $thisfile_audio['channels'] * $thisfile_audio['sample_rate']); + $thisfile_audio['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + } + + return true; + } + + public function VOCcompressionTypeLookup($index) { + static $VOCcompressionTypeLookup = array( + 0 => '8-bit', + 1 => '4-bit', + 2 => '2.6-bit', + 3 => '2-bit' + ); + return (isset($VOCcompressionTypeLookup[$index]) ? $VOCcompressionTypeLookup[$index] : 'Multi DAC ('.($index - 3).') channels'); + } + + public function VOCwFormatLookup($index) { + static $VOCwFormatLookup = array( + 0x0000 => '8-bit unsigned PCM', + 0x0001 => 'Creative 8-bit to 4-bit ADPCM', + 0x0002 => 'Creative 8-bit to 3-bit ADPCM', + 0x0003 => 'Creative 8-bit to 2-bit ADPCM', + 0x0004 => '16-bit signed PCM', + 0x0006 => 'CCITT a-Law', + 0x0007 => 'CCITT u-Law', + 0x2000 => 'Creative 16-bit to 4-bit ADPCM' + ); + return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); + } + + public function VOCwFormatActualBitsPerSampleLookup($index) { + static $VOCwFormatLookup = array( + 0x0000 => 8, + 0x0001 => 4, + 0x0002 => 3, + 0x0003 => 2, + 0x0004 => 16, + 0x0006 => 8, + 0x0007 => 8, + 0x2000 => 4 + ); + return (isset($VOCwFormatLookup[$index]) ? $VOCwFormatLookup[$index] : false); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.vqf.php b/app/libs/vendor/getid3/module.audio.vqf.php index cd2b2703..40c77d05 100644 --- a/app/libs/vendor/getid3/module.audio.vqf.php +++ b/app/libs/vendor/getid3/module.audio.vqf.php @@ -1,159 +1,159 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.vqf.php // -// module for analyzing VQF audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_vqf extends getid3_handler -{ - public function Analyze() { - $info = &$this->getid3->info; - - // based loosely on code from TTwinVQ by Jurgen Faul - // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html - - $info['fileformat'] = 'vqf'; - $info['audio']['dataformat'] = 'vqf'; - $info['audio']['bitrate_mode'] = 'cbr'; - $info['audio']['lossless'] = false; - - // shortcut - $info['vqf']['raw'] = array(); - $thisfile_vqf = &$info['vqf']; - $thisfile_vqf_raw = &$thisfile_vqf['raw']; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $VQFheaderData = fread($this->getid3->fp, 16); - - $offset = 0; - $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4); - $magic = 'TWIN'; - if ($thisfile_vqf_raw['header_tag'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"'; - unset($info['vqf']); - unset($info['fileformat']); - return false; - } - $offset += 4; - $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8); - $offset += 8; - $thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4)); - $offset += 4; - - while (ftell($this->getid3->fp) < $info['avdataend']) { - - $ChunkBaseOffset = ftell($this->getid3->fp); - $chunkoffset = 0; - $ChunkData = fread($this->getid3->fp, 8); - $ChunkName = substr($ChunkData, $chunkoffset, 4); - if ($ChunkName == 'DATA') { - $info['avdataoffset'] = $ChunkBaseOffset; - break; - } - $chunkoffset += 4; - $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); - $chunkoffset += 4; - if ($ChunkSize > ($info['avdataend'] - ftell($this->getid3->fp))) { - $info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset; - break; - } - if ($ChunkSize > 0) { - $ChunkData .= fread($this->getid3->fp, $ChunkSize); - } - - switch ($ChunkName) { - case 'COMM': - // shortcut - $thisfile_vqf['COMM'] = array(); - $thisfile_vqf_COMM = &$thisfile_vqf['COMM']; - - $thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); - $chunkoffset += 4; - $thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); - $chunkoffset += 4; - $thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); - $chunkoffset += 4; - $thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); - $chunkoffset += 4; - - $info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1; - $info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']); - $info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000; - $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000); - - if ($info['audio']['bitrate'] == 0) { - $info['error'][] = 'Corrupt VQF file: bitrate_audio == zero'; - return false; - } - break; - - case 'NAME': - case 'AUTH': - case '(c) ': - case 'FILE': - case 'COMT': - case 'ALBM': - $thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8)); - break; - - case 'DSIZ': - $thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4)); - break; - - default: - $info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset; - break; - } - } - - $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']; - - if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) { - switch ($thisfile_vqf['DSIZ']) { - case 0: - case 1: - $info['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0'; - $info['audio']['encoder'] = 'Ahead Nero'; - break; - - default: - $info['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA')); - break; - } - } - - return true; - } - - public function VQFchannelFrequencyLookup($frequencyid) { - static $VQFchannelFrequencyLookup = array( - 11 => 11025, - 22 => 22050, - 44 => 44100 - ); - return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000); - } - - public function VQFcommentNiceNameLookup($shortname) { - static $VQFcommentNiceNameLookup = array( - 'NAME' => 'title', - 'AUTH' => 'artist', - '(c) ' => 'copyright', - 'FILE' => 'filename', - 'COMT' => 'comment', - 'ALBM' => 'album' - ); - return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.vqf.php // +// module for analyzing VQF audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_vqf extends getid3_handler +{ + public function Analyze() { + $info = &$this->getid3->info; + + // based loosely on code from TTwinVQ by Jurgen Faul + // http://jfaul.de/atl or http://j-faul.virtualave.net/atl/atl.html + + $info['fileformat'] = 'vqf'; + $info['audio']['dataformat'] = 'vqf'; + $info['audio']['bitrate_mode'] = 'cbr'; + $info['audio']['lossless'] = false; + + // shortcut + $info['vqf']['raw'] = array(); + $thisfile_vqf = &$info['vqf']; + $thisfile_vqf_raw = &$thisfile_vqf['raw']; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $VQFheaderData = fread($this->getid3->fp, 16); + + $offset = 0; + $thisfile_vqf_raw['header_tag'] = substr($VQFheaderData, $offset, 4); + $magic = 'TWIN'; + if ($thisfile_vqf_raw['header_tag'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_vqf_raw['header_tag']).'"'; + unset($info['vqf']); + unset($info['fileformat']); + return false; + } + $offset += 4; + $thisfile_vqf_raw['version'] = substr($VQFheaderData, $offset, 8); + $offset += 8; + $thisfile_vqf_raw['size'] = getid3_lib::BigEndian2Int(substr($VQFheaderData, $offset, 4)); + $offset += 4; + + while (ftell($this->getid3->fp) < $info['avdataend']) { + + $ChunkBaseOffset = ftell($this->getid3->fp); + $chunkoffset = 0; + $ChunkData = fread($this->getid3->fp, 8); + $ChunkName = substr($ChunkData, $chunkoffset, 4); + if ($ChunkName == 'DATA') { + $info['avdataoffset'] = $ChunkBaseOffset; + break; + } + $chunkoffset += 4; + $ChunkSize = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + if ($ChunkSize > ($info['avdataend'] - ftell($this->getid3->fp))) { + $info['error'][] = 'Invalid chunk size ('.$ChunkSize.') for chunk "'.$ChunkName.'" at offset '.$ChunkBaseOffset; + break; + } + if ($ChunkSize > 0) { + $ChunkData .= fread($this->getid3->fp, $ChunkSize); + } + + switch ($ChunkName) { + case 'COMM': + // shortcut + $thisfile_vqf['COMM'] = array(); + $thisfile_vqf_COMM = &$thisfile_vqf['COMM']; + + $thisfile_vqf_COMM['channel_mode'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $thisfile_vqf_COMM['bitrate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $thisfile_vqf_COMM['sample_rate'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + $thisfile_vqf_COMM['security_level'] = getid3_lib::BigEndian2Int(substr($ChunkData, $chunkoffset, 4)); + $chunkoffset += 4; + + $info['audio']['channels'] = $thisfile_vqf_COMM['channel_mode'] + 1; + $info['audio']['sample_rate'] = $this->VQFchannelFrequencyLookup($thisfile_vqf_COMM['sample_rate']); + $info['audio']['bitrate'] = $thisfile_vqf_COMM['bitrate'] * 1000; + $info['audio']['encoder_options'] = 'CBR' . ceil($info['audio']['bitrate']/1000); + + if ($info['audio']['bitrate'] == 0) { + $info['error'][] = 'Corrupt VQF file: bitrate_audio == zero'; + return false; + } + break; + + case 'NAME': + case 'AUTH': + case '(c) ': + case 'FILE': + case 'COMT': + case 'ALBM': + $thisfile_vqf['comments'][$this->VQFcommentNiceNameLookup($ChunkName)][] = trim(substr($ChunkData, 8)); + break; + + case 'DSIZ': + $thisfile_vqf['DSIZ'] = getid3_lib::BigEndian2Int(substr($ChunkData, 8, 4)); + break; + + default: + $info['warning'][] = 'Unhandled chunk type "'.$ChunkName.'" at offset '.$ChunkBaseOffset; + break; + } + } + + $info['playtime_seconds'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['audio']['bitrate']; + + if (isset($thisfile_vqf['DSIZ']) && (($thisfile_vqf['DSIZ'] != ($info['avdataend'] - $info['avdataoffset'] - strlen('DATA'))))) { + switch ($thisfile_vqf['DSIZ']) { + case 0: + case 1: + $info['warning'][] = 'Invalid DSIZ value "'.$thisfile_vqf['DSIZ'].'". This is known to happen with VQF files encoded by Ahead Nero, and seems to be its way of saying this is TwinVQF v'.($thisfile_vqf['DSIZ'] + 1).'.0'; + $info['audio']['encoder'] = 'Ahead Nero'; + break; + + default: + $info['warning'][] = 'Probable corrupted file - should be '.$thisfile_vqf['DSIZ'].' bytes, actually '.($info['avdataend'] - $info['avdataoffset'] - strlen('DATA')); + break; + } + } + + return true; + } + + public function VQFchannelFrequencyLookup($frequencyid) { + static $VQFchannelFrequencyLookup = array( + 11 => 11025, + 22 => 22050, + 44 => 44100 + ); + return (isset($VQFchannelFrequencyLookup[$frequencyid]) ? $VQFchannelFrequencyLookup[$frequencyid] : $frequencyid * 1000); + } + + public function VQFcommentNiceNameLookup($shortname) { + static $VQFcommentNiceNameLookup = array( + 'NAME' => 'title', + 'AUTH' => 'artist', + '(c) ' => 'copyright', + 'FILE' => 'filename', + 'COMT' => 'comment', + 'ALBM' => 'album' + ); + return (isset($VQFcommentNiceNameLookup[$shortname]) ? $VQFcommentNiceNameLookup[$shortname] : $shortname); + } + +} diff --git a/app/libs/vendor/getid3/module.audio.wavpack.php b/app/libs/vendor/getid3/module.audio.wavpack.php index 611d1d19..8daf6034 100644 --- a/app/libs/vendor/getid3/module.audio.wavpack.php +++ b/app/libs/vendor/getid3/module.audio.wavpack.php @@ -1,397 +1,397 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.audio.wavpack.php // -// module for analyzing WavPack v4.0+ Audio files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_wavpack extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - while (true) { - - $wavpackheader = fread($this->getid3->fp, 32); - - if (ftell($this->getid3->fp) >= $info['avdataend']) { - break; - } elseif (feof($this->getid3->fp)) { - break; - } elseif ( - isset($info['wavpack']['blockheader']['total_samples']) && - isset($info['wavpack']['blockheader']['block_samples']) && - ($info['wavpack']['blockheader']['total_samples'] > 0) && - ($info['wavpack']['blockheader']['block_samples'] > 0) && - (!isset($info['wavpack']['riff_trailer_size']) || ($info['wavpack']['riff_trailer_size'] <= 0)) && - ((isset($info['wavpack']['config_flags']['md5_checksum']) && ($info['wavpack']['config_flags']['md5_checksum'] === false)) || !empty($info['md5_data_source']))) { - break; - } - - $blockheader_offset = ftell($this->getid3->fp) - 32; - $blockheader_magic = substr($wavpackheader, 0, 4); - $blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4)); - - $magic = 'wvpk'; - if ($blockheader_magic != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"'; - switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { - case 'wavpack': - case 'wvc': - break; - default: - unset($info['fileformat']); - unset($info['audio']); - unset($info['wavpack']); - break; - } - return false; - } - - if (empty($info['wavpack']['blockheader']['block_samples']) || - empty($info['wavpack']['blockheader']['total_samples']) || - ($info['wavpack']['blockheader']['block_samples'] <= 0) || - ($info['wavpack']['blockheader']['total_samples'] <= 0)) { - // Also, it is possible that the first block might not have - // any samples (block_samples == 0) and in this case you should skip blocks - // until you find one with samples because the other information (like - // total_samples) are not guaranteed to be correct until (block_samples > 0) - - // Finally, I have defined a format for files in which the length is not known - // (for example when raw files are created using pipes). In these cases - // total_samples will be -1 and you must seek to the final block to determine - // the total number of samples. - - - $info['audio']['dataformat'] = 'wavpack'; - $info['fileformat'] = 'wavpack'; - $info['audio']['lossless'] = true; - $info['audio']['bitrate_mode'] = 'vbr'; - - $info['wavpack']['blockheader']['offset'] = $blockheader_offset; - $info['wavpack']['blockheader']['magic'] = $blockheader_magic; - $info['wavpack']['blockheader']['size'] = $blockheader_size; - - if ($info['wavpack']['blockheader']['size'] >= 0x100000) { - $info['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['wavpack']['blockheader']['offset']; - switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { - case 'wavpack': - case 'wvc': - break; - default: - unset($info['fileformat']); - unset($info['audio']); - unset($info['wavpack']); - break; - } - return false; - } - - $info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8}); - $info['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9}); - - if (($info['wavpack']['blockheader']['major_version'] != 4) || - (($info['wavpack']['blockheader']['minor_version'] < 4) && - ($info['wavpack']['blockheader']['minor_version'] > 16))) { - $info['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$info['wavpack']['blockheader']['major_version'].'.'.$info['wavpack']['blockheader']['minor_version'].'" at offset '.$info['wavpack']['blockheader']['offset']; - switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { - case 'wavpack': - case 'wvc': - break; - default: - unset($info['fileformat']); - unset($info['audio']); - unset($info['wavpack']); - break; - } - return false; - } - - $info['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused - $info['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused - $info['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4)); - $info['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4)); - $info['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4)); - $info['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4)); - $info['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4)); - - $info['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($info['wavpack']['blockheader']['flags_raw'] & 0x00000003); - $info['wavpack']['blockheader']['flags']['mono'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000004); - $info['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000008); - $info['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000010); - $info['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000020); - $info['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000040); - $info['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000080); - $info['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000100); - $info['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000200); - $info['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000400); - $info['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000800); - $info['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00001000); - - $info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid']; - } - - while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < ($blockheader_offset + $blockheader_size + 8))) { - - $metablock = array('offset'=>ftell($this->getid3->fp)); - $metablockheader = fread($this->getid3->fp, 2); - if (feof($this->getid3->fp)) { - break; - } - $metablock['id'] = ord($metablockheader{0}); - $metablock['function_id'] = ($metablock['id'] & 0x3F); - $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']); - - // The 0x20 bit in the id of the meta subblocks (which is defined as - // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that - // if a decoder encounters an id that it does not know about, it uses - // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set - // then the decoder simply ignores the metadata, but if it is zero - // then the decoder should quit because it means that an understanding - // of the metadata is required to correctly decode the audio. - $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20); - - $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40); - $metablock['large_block'] = (bool) ($metablock['id'] & 0x80); - if ($metablock['large_block']) { - $metablockheader .= fread($this->getid3->fp, 2); - } - $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words - $metablock['data'] = null; - - if ($metablock['size'] > 0) { - - switch ($metablock['function_id']) { - case 0x21: // ID_RIFF_HEADER - case 0x22: // ID_RIFF_TRAILER - case 0x23: // ID_REPLAY_GAIN - case 0x24: // ID_CUESHEET - case 0x25: // ID_CONFIG_BLOCK - case 0x26: // ID_MD5_CHECKSUM - $metablock['data'] = fread($this->getid3->fp, $metablock['size']); - - if ($metablock['padded_data']) { - // padded to the nearest even byte - $metablock['size']--; - $metablock['data'] = substr($metablock['data'], 0, -1); - } - break; - - case 0x00: // ID_DUMMY - case 0x01: // ID_ENCODER_INFO - case 0x02: // ID_DECORR_TERMS - case 0x03: // ID_DECORR_WEIGHTS - case 0x04: // ID_DECORR_SAMPLES - case 0x05: // ID_ENTROPY_VARS - case 0x06: // ID_HYBRID_PROFILE - case 0x07: // ID_SHAPING_WEIGHTS - case 0x08: // ID_FLOAT_INFO - case 0x09: // ID_INT32_INFO - case 0x0A: // ID_WV_BITSTREAM - case 0x0B: // ID_WVC_BITSTREAM - case 0x0C: // ID_WVX_BITSTREAM - case 0x0D: // ID_CHANNEL_INFO - fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); - break; - - default: - $info['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset']; - fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); - break; - } - - switch ($metablock['function_id']) { - case 0x21: // ID_RIFF_HEADER - getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4)); - - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_riff = new getid3_riff($getid3_temp); - $getid3_riff->ParseRIFFdata($metablock['data']); - $metablock['riff'] = $getid3_temp->info['riff']; - $info['audio']['sample_rate'] = $getid3_temp->info['riff']['raw']['fmt ']['nSamplesPerSec']; - unset($getid3_riff, $getid3_temp); - - $metablock['riff']['original_filesize'] = $original_wav_filesize; - $info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; - $info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate']; - - // Safe RIFF header in case there's a RIFF footer later - $metablockRIFFheader = $metablock['data']; - break; - - - case 0x22: // ID_RIFF_TRAILER - $metablockRIFFfooter = $metablockRIFFheader.$metablock['data']; - getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); - - $startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2); - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_temp->info['avdataend'] = $info['avdataend']; - $getid3_temp->info['fileformat'] = 'riff'; - $getid3_riff = new getid3_riff($getid3_temp); - $metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']); - - if (!empty($metablock['riff']['INFO'])) { - getid3_riff::parseComments($metablock['riff']['INFO'], $metablock['comments']); - $info['tags']['riff'] = $metablock['comments']; - } - unset($getid3_temp, $getid3_riff); - break; - - - case 0x23: // ID_REPLAY_GAIN - $info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; - break; - - - case 0x24: // ID_CUESHEET - $info['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; - break; - - - case 0x25: // ID_CONFIG_BLOCK - $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3)); - - $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats - $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode - $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast - $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode - $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet) - $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample - $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping - $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified - $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified - $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source - $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable - $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file - $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression - $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode - $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet) - $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode - $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information) - $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode - $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints - $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature - $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress % - - $info['wavpack']['config_flags'] = $metablock['flags']; - - - $info['audio']['encoder_options'] = ''; - if ($info['wavpack']['blockheader']['flags']['hybrid']) { - $info['audio']['encoder_options'] .= ' -b???'; - } - $info['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : ''); - $info['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : ''); - if (!empty($info['audio']['encoder_options'])) { - $info['audio']['encoder_options'] = trim($info['audio']['encoder_options']); - } elseif (isset($info['audio']['encoder_options'])) { - unset($info['audio']['encoder_options']); - } - break; - - - case 0x26: // ID_MD5_CHECKSUM - if (strlen($metablock['data']) == 16) { - $info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false)); - } else { - $info['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes'; - } - break; - - - case 0x00: // ID_DUMMY - case 0x01: // ID_ENCODER_INFO - case 0x02: // ID_DECORR_TERMS - case 0x03: // ID_DECORR_WEIGHTS - case 0x04: // ID_DECORR_SAMPLES - case 0x05: // ID_ENTROPY_VARS - case 0x06: // ID_HYBRID_PROFILE - case 0x07: // ID_SHAPING_WEIGHTS - case 0x08: // ID_FLOAT_INFO - case 0x09: // ID_INT32_INFO - case 0x0A: // ID_WV_BITSTREAM - case 0x0B: // ID_WVC_BITSTREAM - case 0x0C: // ID_WVX_BITSTREAM - case 0x0D: // ID_CHANNEL_INFO - unset($metablock); - break; - } - - } - if (!empty($metablock)) { - $info['wavpack']['metablocks'][] = $metablock; - } - - } - - } - - $info['audio']['encoder'] = 'WavPack v'.$info['wavpack']['blockheader']['major_version'].'.'.str_pad($info['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT); - $info['audio']['bits_per_sample'] = $info['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8; - $info['audio']['channels'] = ($info['wavpack']['blockheader']['flags']['mono'] ? 1 : 2); - - if (!empty($info['playtime_seconds'])) { - - $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; - - } else { - - $info['audio']['dataformat'] = 'wvc'; - - } - - return true; - } - - - public function WavPackMetablockNameLookup(&$id) { - static $WavPackMetablockNameLookup = array( - 0x00 => 'Dummy', - 0x01 => 'Encoder Info', - 0x02 => 'Decorrelation Terms', - 0x03 => 'Decorrelation Weights', - 0x04 => 'Decorrelation Samples', - 0x05 => 'Entropy Variables', - 0x06 => 'Hybrid Profile', - 0x07 => 'Shaping Weights', - 0x08 => 'Float Info', - 0x09 => 'Int32 Info', - 0x0A => 'WV Bitstream', - 0x0B => 'WVC Bitstream', - 0x0C => 'WVX Bitstream', - 0x0D => 'Channel Info', - 0x21 => 'RIFF header', - 0x22 => 'RIFF trailer', - 0x23 => 'Replay Gain', - 0x24 => 'Cuesheet', - 0x25 => 'Config Block', - 0x26 => 'MD5 Checksum', - ); - return (isset($WavPackMetablockNameLookup[$id]) ? $WavPackMetablockNameLookup[$id] : ''); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.audio.wavpack.php // +// module for analyzing WavPack v4.0+ Audio files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_wavpack extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + while (true) { + + $wavpackheader = fread($this->getid3->fp, 32); + + if (ftell($this->getid3->fp) >= $info['avdataend']) { + break; + } elseif (feof($this->getid3->fp)) { + break; + } elseif ( + isset($info['wavpack']['blockheader']['total_samples']) && + isset($info['wavpack']['blockheader']['block_samples']) && + ($info['wavpack']['blockheader']['total_samples'] > 0) && + ($info['wavpack']['blockheader']['block_samples'] > 0) && + (!isset($info['wavpack']['riff_trailer_size']) || ($info['wavpack']['riff_trailer_size'] <= 0)) && + ((isset($info['wavpack']['config_flags']['md5_checksum']) && ($info['wavpack']['config_flags']['md5_checksum'] === false)) || !empty($info['md5_data_source']))) { + break; + } + + $blockheader_offset = ftell($this->getid3->fp) - 32; + $blockheader_magic = substr($wavpackheader, 0, 4); + $blockheader_size = getid3_lib::LittleEndian2Int(substr($wavpackheader, 4, 4)); + + $magic = 'wvpk'; + if ($blockheader_magic != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$blockheader_offset.', found "'.getid3_lib::PrintHexBytes($blockheader_magic).'"'; + switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { + case 'wavpack': + case 'wvc': + break; + default: + unset($info['fileformat']); + unset($info['audio']); + unset($info['wavpack']); + break; + } + return false; + } + + if (empty($info['wavpack']['blockheader']['block_samples']) || + empty($info['wavpack']['blockheader']['total_samples']) || + ($info['wavpack']['blockheader']['block_samples'] <= 0) || + ($info['wavpack']['blockheader']['total_samples'] <= 0)) { + // Also, it is possible that the first block might not have + // any samples (block_samples == 0) and in this case you should skip blocks + // until you find one with samples because the other information (like + // total_samples) are not guaranteed to be correct until (block_samples > 0) + + // Finally, I have defined a format for files in which the length is not known + // (for example when raw files are created using pipes). In these cases + // total_samples will be -1 and you must seek to the final block to determine + // the total number of samples. + + + $info['audio']['dataformat'] = 'wavpack'; + $info['fileformat'] = 'wavpack'; + $info['audio']['lossless'] = true; + $info['audio']['bitrate_mode'] = 'vbr'; + + $info['wavpack']['blockheader']['offset'] = $blockheader_offset; + $info['wavpack']['blockheader']['magic'] = $blockheader_magic; + $info['wavpack']['blockheader']['size'] = $blockheader_size; + + if ($info['wavpack']['blockheader']['size'] >= 0x100000) { + $info['error'][] = 'Expecting WavPack block size less than "0x100000", found "'.$info['wavpack']['blockheader']['size'].'" at offset '.$info['wavpack']['blockheader']['offset']; + switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { + case 'wavpack': + case 'wvc': + break; + default: + unset($info['fileformat']); + unset($info['audio']); + unset($info['wavpack']); + break; + } + return false; + } + + $info['wavpack']['blockheader']['minor_version'] = ord($wavpackheader{8}); + $info['wavpack']['blockheader']['major_version'] = ord($wavpackheader{9}); + + if (($info['wavpack']['blockheader']['major_version'] != 4) || + (($info['wavpack']['blockheader']['minor_version'] < 4) && + ($info['wavpack']['blockheader']['minor_version'] > 16))) { + $info['error'][] = 'Expecting WavPack version between "4.2" and "4.16", found version "'.$info['wavpack']['blockheader']['major_version'].'.'.$info['wavpack']['blockheader']['minor_version'].'" at offset '.$info['wavpack']['blockheader']['offset']; + switch (isset($info['audio']['dataformat']) ? $info['audio']['dataformat'] : '') { + case 'wavpack': + case 'wvc': + break; + default: + unset($info['fileformat']); + unset($info['audio']); + unset($info['wavpack']); + break; + } + return false; + } + + $info['wavpack']['blockheader']['track_number'] = ord($wavpackheader{10}); // unused + $info['wavpack']['blockheader']['index_number'] = ord($wavpackheader{11}); // unused + $info['wavpack']['blockheader']['total_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 12, 4)); + $info['wavpack']['blockheader']['block_index'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 16, 4)); + $info['wavpack']['blockheader']['block_samples'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 20, 4)); + $info['wavpack']['blockheader']['flags_raw'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 24, 4)); + $info['wavpack']['blockheader']['crc'] = getid3_lib::LittleEndian2Int(substr($wavpackheader, 28, 4)); + + $info['wavpack']['blockheader']['flags']['bytes_per_sample'] = 1 + ($info['wavpack']['blockheader']['flags_raw'] & 0x00000003); + $info['wavpack']['blockheader']['flags']['mono'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000004); + $info['wavpack']['blockheader']['flags']['hybrid'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000008); + $info['wavpack']['blockheader']['flags']['joint_stereo'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000010); + $info['wavpack']['blockheader']['flags']['cross_decorrelation'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000020); + $info['wavpack']['blockheader']['flags']['hybrid_noiseshape'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000040); + $info['wavpack']['blockheader']['flags']['ieee_32bit_float'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000080); + $info['wavpack']['blockheader']['flags']['int_32bit'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000100); + $info['wavpack']['blockheader']['flags']['hybrid_bitrate_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000200); + $info['wavpack']['blockheader']['flags']['hybrid_balance_noise'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000400); + $info['wavpack']['blockheader']['flags']['multichannel_initial'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00000800); + $info['wavpack']['blockheader']['flags']['multichannel_final'] = (bool) ($info['wavpack']['blockheader']['flags_raw'] & 0x00001000); + + $info['audio']['lossless'] = !$info['wavpack']['blockheader']['flags']['hybrid']; + } + + while (!feof($this->getid3->fp) && (ftell($this->getid3->fp) < ($blockheader_offset + $blockheader_size + 8))) { + + $metablock = array('offset'=>ftell($this->getid3->fp)); + $metablockheader = fread($this->getid3->fp, 2); + if (feof($this->getid3->fp)) { + break; + } + $metablock['id'] = ord($metablockheader{0}); + $metablock['function_id'] = ($metablock['id'] & 0x3F); + $metablock['function_name'] = $this->WavPackMetablockNameLookup($metablock['function_id']); + + // The 0x20 bit in the id of the meta subblocks (which is defined as + // ID_OPTIONAL_DATA) is a permanent part of the id. The idea is that + // if a decoder encounters an id that it does not know about, it uses + // that "ID_OPTIONAL_DATA" flag to determine what to do. If it is set + // then the decoder simply ignores the metadata, but if it is zero + // then the decoder should quit because it means that an understanding + // of the metadata is required to correctly decode the audio. + $metablock['non_decoder'] = (bool) ($metablock['id'] & 0x20); + + $metablock['padded_data'] = (bool) ($metablock['id'] & 0x40); + $metablock['large_block'] = (bool) ($metablock['id'] & 0x80); + if ($metablock['large_block']) { + $metablockheader .= fread($this->getid3->fp, 2); + } + $metablock['size'] = getid3_lib::LittleEndian2Int(substr($metablockheader, 1)) * 2; // size is stored in words + $metablock['data'] = null; + + if ($metablock['size'] > 0) { + + switch ($metablock['function_id']) { + case 0x21: // ID_RIFF_HEADER + case 0x22: // ID_RIFF_TRAILER + case 0x23: // ID_REPLAY_GAIN + case 0x24: // ID_CUESHEET + case 0x25: // ID_CONFIG_BLOCK + case 0x26: // ID_MD5_CHECKSUM + $metablock['data'] = fread($this->getid3->fp, $metablock['size']); + + if ($metablock['padded_data']) { + // padded to the nearest even byte + $metablock['size']--; + $metablock['data'] = substr($metablock['data'], 0, -1); + } + break; + + case 0x00: // ID_DUMMY + case 0x01: // ID_ENCODER_INFO + case 0x02: // ID_DECORR_TERMS + case 0x03: // ID_DECORR_WEIGHTS + case 0x04: // ID_DECORR_SAMPLES + case 0x05: // ID_ENTROPY_VARS + case 0x06: // ID_HYBRID_PROFILE + case 0x07: // ID_SHAPING_WEIGHTS + case 0x08: // ID_FLOAT_INFO + case 0x09: // ID_INT32_INFO + case 0x0A: // ID_WV_BITSTREAM + case 0x0B: // ID_WVC_BITSTREAM + case 0x0C: // ID_WVX_BITSTREAM + case 0x0D: // ID_CHANNEL_INFO + fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); + break; + + default: + $info['warning'][] = 'Unexpected metablock type "0x'.str_pad(dechex($metablock['function_id']), 2, '0', STR_PAD_LEFT).'" at offset '.$metablock['offset']; + fseek($this->getid3->fp, $metablock['offset'] + ($metablock['large_block'] ? 4 : 2) + $metablock['size'], SEEK_SET); + break; + } + + switch ($metablock['function_id']) { + case 0x21: // ID_RIFF_HEADER + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + $original_wav_filesize = getid3_lib::LittleEndian2Int(substr($metablock['data'], 4, 4)); + + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_riff = new getid3_riff($getid3_temp); + $getid3_riff->ParseRIFFdata($metablock['data']); + $metablock['riff'] = $getid3_temp->info['riff']; + $info['audio']['sample_rate'] = $getid3_temp->info['riff']['raw']['fmt ']['nSamplesPerSec']; + unset($getid3_riff, $getid3_temp); + + $metablock['riff']['original_filesize'] = $original_wav_filesize; + $info['wavpack']['riff_trailer_size'] = $original_wav_filesize - $metablock['riff']['WAVE']['data'][0]['size'] - $metablock['riff']['header_size']; + $info['playtime_seconds'] = $info['wavpack']['blockheader']['total_samples'] / $info['audio']['sample_rate']; + + // Safe RIFF header in case there's a RIFF footer later + $metablockRIFFheader = $metablock['data']; + break; + + + case 0x22: // ID_RIFF_TRAILER + $metablockRIFFfooter = $metablockRIFFheader.$metablock['data']; + getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio-video.riff.php', __FILE__, true); + + $startoffset = $metablock['offset'] + ($metablock['large_block'] ? 4 : 2); + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_temp->info['avdataend'] = $info['avdataend']; + $getid3_temp->info['fileformat'] = 'riff'; + $getid3_riff = new getid3_riff($getid3_temp); + $metablock['riff'] = $getid3_riff->ParseRIFF($startoffset, $startoffset + $metablock['size']); + + if (!empty($metablock['riff']['INFO'])) { + getid3_riff::parseComments($metablock['riff']['INFO'], $metablock['comments']); + $info['tags']['riff'] = $metablock['comments']; + } + unset($getid3_temp, $getid3_riff); + break; + + + case 0x23: // ID_REPLAY_GAIN + $info['warning'][] = 'WavPack "Replay Gain" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; + break; + + + case 0x24: // ID_CUESHEET + $info['warning'][] = 'WavPack "Cuesheet" contents not yet handled by getID3() in metablock at offset '.$metablock['offset']; + break; + + + case 0x25: // ID_CONFIG_BLOCK + $metablock['flags_raw'] = getid3_lib::LittleEndian2Int(substr($metablock['data'], 0, 3)); + + $metablock['flags']['adobe_mode'] = (bool) ($metablock['flags_raw'] & 0x000001); // "adobe" mode for 32-bit floats + $metablock['flags']['fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000002); // fast mode + $metablock['flags']['very_fast_flag'] = (bool) ($metablock['flags_raw'] & 0x000004); // double fast + $metablock['flags']['high_flag'] = (bool) ($metablock['flags_raw'] & 0x000008); // high quality mode + $metablock['flags']['very_high_flag'] = (bool) ($metablock['flags_raw'] & 0x000010); // double high (not used yet) + $metablock['flags']['bitrate_kbps'] = (bool) ($metablock['flags_raw'] & 0x000020); // bitrate is kbps, not bits / sample + $metablock['flags']['auto_shaping'] = (bool) ($metablock['flags_raw'] & 0x000040); // automatic noise shaping + $metablock['flags']['shape_override'] = (bool) ($metablock['flags_raw'] & 0x000080); // shaping mode specified + $metablock['flags']['joint_override'] = (bool) ($metablock['flags_raw'] & 0x000100); // joint-stereo mode specified + $metablock['flags']['copy_time'] = (bool) ($metablock['flags_raw'] & 0x000200); // copy file-time from source + $metablock['flags']['create_exe'] = (bool) ($metablock['flags_raw'] & 0x000400); // create executable + $metablock['flags']['create_wvc'] = (bool) ($metablock['flags_raw'] & 0x000800); // create correction file + $metablock['flags']['optimize_wvc'] = (bool) ($metablock['flags_raw'] & 0x001000); // maximize bybrid compression + $metablock['flags']['quality_mode'] = (bool) ($metablock['flags_raw'] & 0x002000); // psychoacoustic quality mode + $metablock['flags']['raw_flag'] = (bool) ($metablock['flags_raw'] & 0x004000); // raw mode (not implemented yet) + $metablock['flags']['calc_noise'] = (bool) ($metablock['flags_raw'] & 0x008000); // calc noise in hybrid mode + $metablock['flags']['lossy_mode'] = (bool) ($metablock['flags_raw'] & 0x010000); // obsolete (for information) + $metablock['flags']['extra_mode'] = (bool) ($metablock['flags_raw'] & 0x020000); // extra processing mode + $metablock['flags']['skip_wvx'] = (bool) ($metablock['flags_raw'] & 0x040000); // no wvx stream w/ floats & big ints + $metablock['flags']['md5_checksum'] = (bool) ($metablock['flags_raw'] & 0x080000); // compute & store MD5 signature + $metablock['flags']['quiet_mode'] = (bool) ($metablock['flags_raw'] & 0x100000); // don't report progress % + + $info['wavpack']['config_flags'] = $metablock['flags']; + + + $info['audio']['encoder_options'] = ''; + if ($info['wavpack']['blockheader']['flags']['hybrid']) { + $info['audio']['encoder_options'] .= ' -b???'; + } + $info['audio']['encoder_options'] .= ($metablock['flags']['adobe_mode'] ? ' -a' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['optimize_wvc'] ? ' -cc' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['create_exe'] ? ' -e' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['fast_flag'] ? ' -f' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['joint_override'] ? ' -j?' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['high_flag'] ? ' -h' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['md5_checksum'] ? ' -m' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['calc_noise'] ? ' -n' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['shape_override'] ? ' -s?' : ''); + $info['audio']['encoder_options'] .= ($metablock['flags']['extra_mode'] ? ' -x?' : ''); + if (!empty($info['audio']['encoder_options'])) { + $info['audio']['encoder_options'] = trim($info['audio']['encoder_options']); + } elseif (isset($info['audio']['encoder_options'])) { + unset($info['audio']['encoder_options']); + } + break; + + + case 0x26: // ID_MD5_CHECKSUM + if (strlen($metablock['data']) == 16) { + $info['md5_data_source'] = strtolower(getid3_lib::PrintHexBytes($metablock['data'], true, false, false)); + } else { + $info['warning'][] = 'Expecting 16 bytes of WavPack "MD5 Checksum" in metablock at offset '.$metablock['offset'].', but found '.strlen($metablock['data']).' bytes'; + } + break; + + + case 0x00: // ID_DUMMY + case 0x01: // ID_ENCODER_INFO + case 0x02: // ID_DECORR_TERMS + case 0x03: // ID_DECORR_WEIGHTS + case 0x04: // ID_DECORR_SAMPLES + case 0x05: // ID_ENTROPY_VARS + case 0x06: // ID_HYBRID_PROFILE + case 0x07: // ID_SHAPING_WEIGHTS + case 0x08: // ID_FLOAT_INFO + case 0x09: // ID_INT32_INFO + case 0x0A: // ID_WV_BITSTREAM + case 0x0B: // ID_WVC_BITSTREAM + case 0x0C: // ID_WVX_BITSTREAM + case 0x0D: // ID_CHANNEL_INFO + unset($metablock); + break; + } + + } + if (!empty($metablock)) { + $info['wavpack']['metablocks'][] = $metablock; + } + + } + + } + + $info['audio']['encoder'] = 'WavPack v'.$info['wavpack']['blockheader']['major_version'].'.'.str_pad($info['wavpack']['blockheader']['minor_version'], 2, '0', STR_PAD_LEFT); + $info['audio']['bits_per_sample'] = $info['wavpack']['blockheader']['flags']['bytes_per_sample'] * 8; + $info['audio']['channels'] = ($info['wavpack']['blockheader']['flags']['mono'] ? 1 : 2); + + if (!empty($info['playtime_seconds'])) { + + $info['audio']['bitrate'] = (($info['avdataend'] - $info['avdataoffset']) * 8) / $info['playtime_seconds']; + + } else { + + $info['audio']['dataformat'] = 'wvc'; + + } + + return true; + } + + + public function WavPackMetablockNameLookup(&$id) { + static $WavPackMetablockNameLookup = array( + 0x00 => 'Dummy', + 0x01 => 'Encoder Info', + 0x02 => 'Decorrelation Terms', + 0x03 => 'Decorrelation Weights', + 0x04 => 'Decorrelation Samples', + 0x05 => 'Entropy Variables', + 0x06 => 'Hybrid Profile', + 0x07 => 'Shaping Weights', + 0x08 => 'Float Info', + 0x09 => 'Int32 Info', + 0x0A => 'WV Bitstream', + 0x0B => 'WVC Bitstream', + 0x0C => 'WVX Bitstream', + 0x0D => 'Channel Info', + 0x21 => 'RIFF header', + 0x22 => 'RIFF trailer', + 0x23 => 'Replay Gain', + 0x24 => 'Cuesheet', + 0x25 => 'Config Block', + 0x26 => 'MD5 Checksum', + ); + return (isset($WavPackMetablockNameLookup[$id]) ? $WavPackMetablockNameLookup[$id] : ''); + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.bmp.php b/app/libs/vendor/getid3/module.graphic.bmp.php index 352aae93..5dabd9b0 100644 --- a/app/libs/vendor/getid3/module.graphic.bmp.php +++ b/app/libs/vendor/getid3/module.graphic.bmp.php @@ -1,687 +1,687 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.bmp.php // -// module for analyzing BMP Image files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_bmp extends getid3_handler -{ - public $ExtractPalette = false; - public $ExtractData = false; - - public function Analyze() { - $info = &$this->getid3->info; - - // shortcuts - $info['bmp']['header']['raw'] = array(); - $thisfile_bmp = &$info['bmp']; - $thisfile_bmp_header = &$thisfile_bmp['header']; - $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw']; - - // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp - // all versions - // WORD bfType; - // DWORD bfSize; - // WORD bfReserved1; - // WORD bfReserved2; - // DWORD bfOffBits; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $offset = 0; - $BMPheader = fread($this->getid3->fp, 14 + 40); - - $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2); - $offset += 2; - - $magic = 'BM'; - if ($thisfile_bmp_header_raw['identifier'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_bmp_header_raw['identifier']).'"'; - unset($info['fileformat']); - unset($info['bmp']); - return false; - } - - $thisfile_bmp_header_raw['filesize'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['reserved2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['header_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - - - // check if the hardcoded-to-1 "planes" is at offset 22 or 26 - $planes22 = getid3_lib::LittleEndian2Int(substr($BMPheader, 22, 2)); - $planes26 = getid3_lib::LittleEndian2Int(substr($BMPheader, 26, 2)); - if (($planes22 == 1) && ($planes26 != 1)) { - $thisfile_bmp['type_os'] = 'OS/2'; - $thisfile_bmp['type_version'] = 1; - } elseif (($planes26 == 1) && ($planes22 != 1)) { - $thisfile_bmp['type_os'] = 'Windows'; - $thisfile_bmp['type_version'] = 1; - } elseif ($thisfile_bmp_header_raw['header_size'] == 12) { - $thisfile_bmp['type_os'] = 'OS/2'; - $thisfile_bmp['type_version'] = 1; - } elseif ($thisfile_bmp_header_raw['header_size'] == 40) { - $thisfile_bmp['type_os'] = 'Windows'; - $thisfile_bmp['type_version'] = 1; - } elseif ($thisfile_bmp_header_raw['header_size'] == 84) { - $thisfile_bmp['type_os'] = 'Windows'; - $thisfile_bmp['type_version'] = 4; - } elseif ($thisfile_bmp_header_raw['header_size'] == 100) { - $thisfile_bmp['type_os'] = 'Windows'; - $thisfile_bmp['type_version'] = 5; - } else { - $info['error'][] = 'Unknown BMP subtype (or not a BMP file)'; - unset($info['fileformat']); - unset($info['bmp']); - return false; - } - - $info['fileformat'] = 'bmp'; - $info['video']['dataformat'] = 'bmp'; - $info['video']['lossless'] = true; - $info['video']['pixel_aspect_ratio'] = (float) 1; - - if ($thisfile_bmp['type_os'] == 'OS/2') { - - // OS/2-format BMP - // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm - - // DWORD Size; /* Size of this structure in bytes */ - // DWORD Width; /* Bitmap width in pixels */ - // DWORD Height; /* Bitmap height in pixel */ - // WORD NumPlanes; /* Number of bit planes (color depth) */ - // WORD BitsPerPixel; /* Number of bits per pixel per plane */ - - $thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - - $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width']; - $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height']; - $info['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; - $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel']; - - if ($thisfile_bmp['type_version'] >= 2) { - // DWORD Compression; /* Bitmap compression scheme */ - // DWORD ImageDataSize; /* Size of bitmap data in bytes */ - // DWORD XResolution; /* X resolution of display device */ - // DWORD YResolution; /* Y resolution of display device */ - // DWORD ColorsUsed; /* Number of color table indices used */ - // DWORD ColorsImportant; /* Number of important color indices */ - // WORD Units; /* Type of units used to measure resolution */ - // WORD Reserved; /* Pad structure to 4-byte boundary */ - // WORD Recording; /* Recording algorithm */ - // WORD Rendering; /* Halftoning algorithm used */ - // DWORD Size1; /* Reserved for halftoning algorithm use */ - // DWORD Size2; /* Reserved for halftoning algorithm use */ - // DWORD ColorEncoding; /* Color model used in bitmap */ - // DWORD Identifier; /* Reserved for application use */ - - $thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['resolution_units'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['recording'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['rendering'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['size1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['size2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['color_encoding'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['identifier'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - - $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']); - - $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; - } - - } elseif ($thisfile_bmp['type_os'] == 'Windows') { - - // Windows-format BMP - - // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp - // all versions - // DWORD biSize; - // LONG biWidth; - // LONG biHeight; - // WORD biPlanes; - // WORD biBitCount; - // DWORD biCompression; - // DWORD biSizeImage; - // LONG biXPelsPerMeter; - // LONG biYPelsPerMeter; - // DWORD biClrUsed; - // DWORD biClrImportant; - - // possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ? - - $thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); - $offset += 4; - $thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); - $offset += 4; - $thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); - $offset += 2; - $thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); - $offset += 4; - $thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); - $offset += 4; - $thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - - $thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']); - $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width']; - $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height']; - $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; - $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel']; - - if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) { - // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen - $BMPheader .= fread($this->getid3->fp, 44); - - // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp - // Win95+, WinNT4.0+ - // DWORD bV4RedMask; - // DWORD bV4GreenMask; - // DWORD bV4BlueMask; - // DWORD bV4AlphaMask; - // DWORD bV4CSType; - // CIEXYZTRIPLE bV4Endpoints; - // DWORD bV4GammaRed; - // DWORD bV4GammaGreen; - // DWORD bV4GammaBlue; - $thisfile_bmp_header_raw['red_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['green_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['blue_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['alpha_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['cs_type'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4); - $offset += 4; - $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4); - $offset += 4; - $thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4); - $offset += 4; - $thisfile_bmp_header_raw['gamma_red'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['gamma_green'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['gamma_blue'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - - $thisfile_bmp_header['ciexyz_red'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red'])); - $thisfile_bmp_header['ciexyz_green'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green'])); - $thisfile_bmp_header['ciexyz_blue'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue'])); - } - - if ($thisfile_bmp['type_version'] >= 5) { - $BMPheader .= fread($this->getid3->fp, 16); - - // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp - // Win98+, Win2000+ - // DWORD bV5Intent; - // DWORD bV5ProfileData; - // DWORD bV5ProfileSize; - // DWORD bV5Reserved; - $thisfile_bmp_header_raw['intent'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['profile_data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['profile_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - $thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); - $offset += 4; - } - - } else { - - $info['error'][] = 'Unknown BMP format in header.'; - return false; - - } - - - if ($this->ExtractPalette || $this->ExtractData) { - $PaletteEntries = 0; - if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) { - $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']); - } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) { - $PaletteEntries = $thisfile_bmp_header_raw['colors_used']; - } - if ($PaletteEntries > 0) { - $BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries); - $paletteoffset = 0; - for ($i = 0; $i < $PaletteEntries; $i++) { - // RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp - // BYTE rgbBlue; - // BYTE rgbGreen; - // BYTE rgbRed; - // BYTE rgbReserved; - $blue = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); - $green = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); - $red = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); - if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) { - // no padding byte - } else { - $paletteoffset++; // padding byte - } - $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue); - } - } - } - - if ($this->ExtractData) { - fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET); - $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry - $BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength); - $pixeldataoffset = 0; - $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); - switch ($thisfile_bmp_header_raw['compression']) { - - case 0: // BI_RGB - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 1: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { - $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++}); - for ($i = 7; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; - } - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 4: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { - $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++}); - for ($i = 1; $i >= 0; $i--) { - $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $col++; - } - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 8: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $paletteindex = ord($BMPpixelData{$pixeldataoffset++}); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 24: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset}); - $pixeldataoffset += 3; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 32: - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset}); - $pixeldataoffset += 4; - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - case 16: - // ? - break; - - default: - $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; - break; - } - break; - - - case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 8: - $pixelcounter = 0; - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero and the second byte is a - // value in the range 03H through FFH. The second byte represents the - // number of bytes that follow, each of which contains the color index - // of a single pixel. Each run must be aligned on a word boundary. - for ($i = 0; $i < $secondbyte; $i++) { - $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - break; - } - - } else { - - // encoded mode - the first byte specifies the number of consecutive pixels - // to be drawn using the color index contained in the second byte. - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; - $pixelcounter++; - } - - } - } - break; - - default: - $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; - break; - } - break; - - - - case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 4: - $pixelcounter = 0; - while ($pixeldataoffset < strlen($BMPpixelData)) { - $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - if ($firstbyte == 0) { - - // escaped/absolute mode - the first byte of the pair can be set to zero to - // indicate an escape character that denotes the end of a line, the end of - // a bitmap, or a delta, depending on the value of the second byte. - switch ($secondbyte) { - case 0: - // end of line - // no need for special processing, just ignore - break; - - case 1: - // end of bitmap - $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case - break; - - case 2: - // delta - The 2 bytes following the escape contain unsigned values - // indicating the horizontal and vertical offsets of the next pixel - // from the current position. - $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; - $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; - $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; - break; - - default: - // In absolute mode, the first byte is zero. The second byte contains the number - // of color indexes that follow. Subsequent bytes contain color indexes in their - // high- and low-order 4 bits, one color index for each pixel. In absolute mode, - // each run must be aligned on a word boundary. - unset($paletteindexes); - for ($i = 0; $i < ceil($secondbyte / 2); $i++) { - $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); - $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; - $paletteindexes[] = ($paletteindexbyte & 0x0F); - } - while (($pixeldataoffset % 2) != 0) { - // Each run must be aligned on a word boundary. - $pixeldataoffset++; - } - - foreach ($paletteindexes as $paletteindex) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; - $pixelcounter++; - } - break; - } - - } else { - - // encoded mode - the first byte of the pair contains the number of pixels to be - // drawn using the color indexes in the second byte. The second byte contains two - // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. - // The first of the pixels is drawn using the color specified by the high-order - // 4 bits, the second is drawn using the color in the low-order 4 bits, the third - // is drawn using the color in the high-order 4 bits, and so on, until all the - // pixels specified by the first byte have been drawn. - $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; - $paletteindexes[1] = ($secondbyte & 0x0F); - for ($i = 0; $i < $firstbyte; $i++) { - $col = $pixelcounter % $thisfile_bmp_header_raw['width']; - $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); - $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; - $pixelcounter++; - } - - } - } - break; - - default: - $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; - break; - } - break; - - - case 3: // BI_BITFIELDS - switch ($thisfile_bmp_header_raw['bits_per_pixel']) { - case 16: - case 32: - $redshift = 0; - $greenshift = 0; - $blueshift = 0; - while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { - $redshift++; - } - while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { - $greenshift++; - } - while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { - $blueshift++; - } - for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { - for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { - $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); - $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; - - $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); - $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); - $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); - $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); - } - while (($pixeldataoffset % 4) != 0) { - // lines are padded to nearest DWORD - $pixeldataoffset++; - } - } - break; - - default: - $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; - break; - } - break; - - - default: // unhandled compression type - $info['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'; - break; - } - } - - return true; - } - - - public function PlotBMP(&$BMPinfo) { - $starttime = time(); - if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) { - echo 'ERROR: no pixel data
    '; - return false; - } - set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000))); - if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) { - for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) { - for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) { - if (isset($BMPinfo['bmp']['data'][$row][$col])) { - $red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16; - $green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8; - $blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF); - $pixelcolor = ImageColorAllocate($im, $red, $green, $blue); - ImageSetPixel($im, $col, $row, $pixelcolor); - } else { - //echo 'ERROR: no data for pixel '.$row.' x '.$col.'
    '; - //return false; - } - } - } - if (headers_sent()) { - echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds
    '; - ImageDestroy($im); - exit; - } else { - header('Content-type: image/png'); - ImagePNG($im); - ImageDestroy($im); - return true; - } - } - return false; - } - - public function BMPcompressionWindowsLookup($compressionid) { - static $BMPcompressionWindowsLookup = array( - 0 => 'BI_RGB', - 1 => 'BI_RLE8', - 2 => 'BI_RLE4', - 3 => 'BI_BITFIELDS', - 4 => 'BI_JPEG', - 5 => 'BI_PNG' - ); - return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid'); - } - - public function BMPcompressionOS2Lookup($compressionid) { - static $BMPcompressionOS2Lookup = array( - 0 => 'BI_RGB', - 1 => 'BI_RLE8', - 2 => 'BI_RLE4', - 3 => 'Huffman 1D', - 4 => 'BI_RLE24', - ); - return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid'); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.bmp.php // +// module for analyzing BMP Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_bmp extends getid3_handler +{ + public $ExtractPalette = false; + public $ExtractData = false; + + public function Analyze() { + $info = &$this->getid3->info; + + // shortcuts + $info['bmp']['header']['raw'] = array(); + $thisfile_bmp = &$info['bmp']; + $thisfile_bmp_header = &$thisfile_bmp['header']; + $thisfile_bmp_header_raw = &$thisfile_bmp_header['raw']; + + // BITMAPFILEHEADER [14 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_62uq.asp + // all versions + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $offset = 0; + $BMPheader = fread($this->getid3->fp, 14 + 40); + + $thisfile_bmp_header_raw['identifier'] = substr($BMPheader, $offset, 2); + $offset += 2; + + $magic = 'BM'; + if ($thisfile_bmp_header_raw['identifier'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($thisfile_bmp_header_raw['identifier']).'"'; + unset($info['fileformat']); + unset($info['bmp']); + return false; + } + + $thisfile_bmp_header_raw['filesize'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['reserved2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['header_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + + // check if the hardcoded-to-1 "planes" is at offset 22 or 26 + $planes22 = getid3_lib::LittleEndian2Int(substr($BMPheader, 22, 2)); + $planes26 = getid3_lib::LittleEndian2Int(substr($BMPheader, 26, 2)); + if (($planes22 == 1) && ($planes26 != 1)) { + $thisfile_bmp['type_os'] = 'OS/2'; + $thisfile_bmp['type_version'] = 1; + } elseif (($planes26 == 1) && ($planes22 != 1)) { + $thisfile_bmp['type_os'] = 'Windows'; + $thisfile_bmp['type_version'] = 1; + } elseif ($thisfile_bmp_header_raw['header_size'] == 12) { + $thisfile_bmp['type_os'] = 'OS/2'; + $thisfile_bmp['type_version'] = 1; + } elseif ($thisfile_bmp_header_raw['header_size'] == 40) { + $thisfile_bmp['type_os'] = 'Windows'; + $thisfile_bmp['type_version'] = 1; + } elseif ($thisfile_bmp_header_raw['header_size'] == 84) { + $thisfile_bmp['type_os'] = 'Windows'; + $thisfile_bmp['type_version'] = 4; + } elseif ($thisfile_bmp_header_raw['header_size'] == 100) { + $thisfile_bmp['type_os'] = 'Windows'; + $thisfile_bmp['type_version'] = 5; + } else { + $info['error'][] = 'Unknown BMP subtype (or not a BMP file)'; + unset($info['fileformat']); + unset($info['bmp']); + return false; + } + + $info['fileformat'] = 'bmp'; + $info['video']['dataformat'] = 'bmp'; + $info['video']['lossless'] = true; + $info['video']['pixel_aspect_ratio'] = (float) 1; + + if ($thisfile_bmp['type_os'] == 'OS/2') { + + // OS/2-format BMP + // http://netghost.narod.ru/gff/graphics/summary/os2bmp.htm + + // DWORD Size; /* Size of this structure in bytes */ + // DWORD Width; /* Bitmap width in pixels */ + // DWORD Height; /* Bitmap height in pixel */ + // WORD NumPlanes; /* Number of bit planes (color depth) */ + // WORD BitsPerPixel; /* Number of bits per pixel per plane */ + + $thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + + $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width']; + $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height']; + $info['video']['codec'] = 'BI_RGB '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; + $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel']; + + if ($thisfile_bmp['type_version'] >= 2) { + // DWORD Compression; /* Bitmap compression scheme */ + // DWORD ImageDataSize; /* Size of bitmap data in bytes */ + // DWORD XResolution; /* X resolution of display device */ + // DWORD YResolution; /* Y resolution of display device */ + // DWORD ColorsUsed; /* Number of color table indices used */ + // DWORD ColorsImportant; /* Number of important color indices */ + // WORD Units; /* Type of units used to measure resolution */ + // WORD Reserved; /* Pad structure to 4-byte boundary */ + // WORD Recording; /* Recording algorithm */ + // WORD Rendering; /* Halftoning algorithm used */ + // DWORD Size1; /* Reserved for halftoning algorithm use */ + // DWORD Size2; /* Reserved for halftoning algorithm use */ + // DWORD ColorEncoding; /* Color model used in bitmap */ + // DWORD Identifier; /* Reserved for application use */ + + $thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['resolution_units'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['reserved1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['recording'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['rendering'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['size1'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['size2'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['color_encoding'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['identifier'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $thisfile_bmp_header['compression'] = $this->BMPcompressionOS2Lookup($thisfile_bmp_header_raw['compression']); + + $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; + } + + } elseif ($thisfile_bmp['type_os'] == 'Windows') { + + // Windows-format BMP + + // BITMAPINFOHEADER - [40 bytes] http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp + // all versions + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + + // possibly integrate this section and module.audio-video.riff.php::ParseBITMAPINFOHEADER() ? + + $thisfile_bmp_header_raw['width'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $thisfile_bmp_header_raw['height'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $thisfile_bmp_header_raw['planes'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['bits_per_pixel'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 2)); + $offset += 2; + $thisfile_bmp_header_raw['compression'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['bmp_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['resolution_h'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $thisfile_bmp_header_raw['resolution_v'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4), true); + $offset += 4; + $thisfile_bmp_header_raw['colors_used'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['colors_important'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $thisfile_bmp_header['compression'] = $this->BMPcompressionWindowsLookup($thisfile_bmp_header_raw['compression']); + $info['video']['resolution_x'] = $thisfile_bmp_header_raw['width']; + $info['video']['resolution_y'] = $thisfile_bmp_header_raw['height']; + $info['video']['codec'] = $thisfile_bmp_header['compression'].' '.$thisfile_bmp_header_raw['bits_per_pixel'].'-bit'; + $info['video']['bits_per_sample'] = $thisfile_bmp_header_raw['bits_per_pixel']; + + if (($thisfile_bmp['type_version'] >= 4) || ($thisfile_bmp_header_raw['compression'] == 3)) { + // should only be v4+, but BMPs with type_version==1 and BI_BITFIELDS compression have been seen + $BMPheader .= fread($this->getid3->fp, 44); + + // BITMAPV4HEADER - [44 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_2k1e.asp + // Win95+, WinNT4.0+ + // DWORD bV4RedMask; + // DWORD bV4GreenMask; + // DWORD bV4BlueMask; + // DWORD bV4AlphaMask; + // DWORD bV4CSType; + // CIEXYZTRIPLE bV4Endpoints; + // DWORD bV4GammaRed; + // DWORD bV4GammaGreen; + // DWORD bV4GammaBlue; + $thisfile_bmp_header_raw['red_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['green_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['blue_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['alpha_mask'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['cs_type'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['ciexyz_red'] = substr($BMPheader, $offset, 4); + $offset += 4; + $thisfile_bmp_header_raw['ciexyz_green'] = substr($BMPheader, $offset, 4); + $offset += 4; + $thisfile_bmp_header_raw['ciexyz_blue'] = substr($BMPheader, $offset, 4); + $offset += 4; + $thisfile_bmp_header_raw['gamma_red'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['gamma_green'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['gamma_blue'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + + $thisfile_bmp_header['ciexyz_red'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_red'])); + $thisfile_bmp_header['ciexyz_green'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_green'])); + $thisfile_bmp_header['ciexyz_blue'] = getid3_lib::FixedPoint2_30(strrev($thisfile_bmp_header_raw['ciexyz_blue'])); + } + + if ($thisfile_bmp['type_version'] >= 5) { + $BMPheader .= fread($this->getid3->fp, 16); + + // BITMAPV5HEADER - [16 bytes] - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_7c36.asp + // Win98+, Win2000+ + // DWORD bV5Intent; + // DWORD bV5ProfileData; + // DWORD bV5ProfileSize; + // DWORD bV5Reserved; + $thisfile_bmp_header_raw['intent'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['profile_data_offset'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['profile_data_size'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + $thisfile_bmp_header_raw['reserved3'] = getid3_lib::LittleEndian2Int(substr($BMPheader, $offset, 4)); + $offset += 4; + } + + } else { + + $info['error'][] = 'Unknown BMP format in header.'; + return false; + + } + + + if ($this->ExtractPalette || $this->ExtractData) { + $PaletteEntries = 0; + if ($thisfile_bmp_header_raw['bits_per_pixel'] < 16) { + $PaletteEntries = pow(2, $thisfile_bmp_header_raw['bits_per_pixel']); + } elseif (isset($thisfile_bmp_header_raw['colors_used']) && ($thisfile_bmp_header_raw['colors_used'] > 0) && ($thisfile_bmp_header_raw['colors_used'] <= 256)) { + $PaletteEntries = $thisfile_bmp_header_raw['colors_used']; + } + if ($PaletteEntries > 0) { + $BMPpalette = fread($this->getid3->fp, 4 * $PaletteEntries); + $paletteoffset = 0; + for ($i = 0; $i < $PaletteEntries; $i++) { + // RGBQUAD - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_5f8y.asp + // BYTE rgbBlue; + // BYTE rgbGreen; + // BYTE rgbRed; + // BYTE rgbReserved; + $blue = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $green = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + $red = getid3_lib::LittleEndian2Int(substr($BMPpalette, $paletteoffset++, 1)); + if (($thisfile_bmp['type_os'] == 'OS/2') && ($thisfile_bmp['type_version'] == 1)) { + // no padding byte + } else { + $paletteoffset++; // padding byte + } + $thisfile_bmp['palette'][$i] = (($red << 16) | ($green << 8) | $blue); + } + } + } + + if ($this->ExtractData) { + fseek($this->getid3->fp, $thisfile_bmp_header_raw['data_offset'], SEEK_SET); + $RowByteLength = ceil(($thisfile_bmp_header_raw['width'] * ($thisfile_bmp_header_raw['bits_per_pixel'] / 8)) / 4) * 4; // round up to nearest DWORD boundry + $BMPpixelData = fread($this->getid3->fp, $thisfile_bmp_header_raw['height'] * $RowByteLength); + $pixeldataoffset = 0; + $thisfile_bmp_header_raw['compression'] = (isset($thisfile_bmp_header_raw['compression']) ? $thisfile_bmp_header_raw['compression'] : ''); + switch ($thisfile_bmp_header_raw['compression']) { + + case 0: // BI_RGB + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 1: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { + $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++}); + for ($i = 7; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x01 << $i)) >> $i; + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 4: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col = $col) { + $paletteindexbyte = ord($BMPpixelData{$pixeldataoffset++}); + for ($i = 1; $i >= 0; $i--) { + $paletteindex = ($paletteindexbyte & (0x0F << (4 * $i))) >> (4 * $i); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $col++; + } + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 8: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $paletteindex = ord($BMPpixelData{$pixeldataoffset++}); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 24: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset}); + $pixeldataoffset += 3; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 32: + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $thisfile_bmp['data'][$row][$col] = (ord($BMPpixelData{$pixeldataoffset+3}) << 24) | (ord($BMPpixelData{$pixeldataoffset+2}) << 16) | (ord($BMPpixelData{$pixeldataoffset+1}) << 8) | ord($BMPpixelData{$pixeldataoffset}); + $pixeldataoffset += 4; + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + case 16: + // ? + break; + + default: + $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + case 1: // BI_RLE8 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 8: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero and the second byte is a + // value in the range 03H through FFH. The second byte represents the + // number of bytes that follow, each of which contains the color index + // of a single pixel. Each run must be aligned on a word boundary. + for ($i = 0; $i < $secondbyte; $i++) { + $paletteindex = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + break; + } + + } else { + + // encoded mode - the first byte specifies the number of consecutive pixels + // to be drawn using the color index contained in the second byte. + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$secondbyte]; + $pixelcounter++; + } + + } + } + break; + + default: + $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + + case 2: // BI_RLE4 - http://msdn.microsoft.com/library/en-us/gdi/bitmaps_6x0u.asp + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 4: + $pixelcounter = 0; + while ($pixeldataoffset < strlen($BMPpixelData)) { + $firstbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $secondbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + if ($firstbyte == 0) { + + // escaped/absolute mode - the first byte of the pair can be set to zero to + // indicate an escape character that denotes the end of a line, the end of + // a bitmap, or a delta, depending on the value of the second byte. + switch ($secondbyte) { + case 0: + // end of line + // no need for special processing, just ignore + break; + + case 1: + // end of bitmap + $pixeldataoffset = strlen($BMPpixelData); // force to exit loop just in case + break; + + case 2: + // delta - The 2 bytes following the escape contain unsigned values + // indicating the horizontal and vertical offsets of the next pixel + // from the current position. + $colincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $rowincrement = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $col = ($pixelcounter % $thisfile_bmp_header_raw['width']) + $colincrement; + $row = ($thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width'])) - $rowincrement; + $pixelcounter = ($row * $thisfile_bmp_header_raw['width']) + $col; + break; + + default: + // In absolute mode, the first byte is zero. The second byte contains the number + // of color indexes that follow. Subsequent bytes contain color indexes in their + // high- and low-order 4 bits, one color index for each pixel. In absolute mode, + // each run must be aligned on a word boundary. + unset($paletteindexes); + for ($i = 0; $i < ceil($secondbyte / 2); $i++) { + $paletteindexbyte = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset++, 1)); + $paletteindexes[] = ($paletteindexbyte & 0xF0) >> 4; + $paletteindexes[] = ($paletteindexbyte & 0x0F); + } + while (($pixeldataoffset % 2) != 0) { + // Each run must be aligned on a word boundary. + $pixeldataoffset++; + } + + foreach ($paletteindexes as $paletteindex) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindex]; + $pixelcounter++; + } + break; + } + + } else { + + // encoded mode - the first byte of the pair contains the number of pixels to be + // drawn using the color indexes in the second byte. The second byte contains two + // color indexes, one in its high-order 4 bits and one in its low-order 4 bits. + // The first of the pixels is drawn using the color specified by the high-order + // 4 bits, the second is drawn using the color in the low-order 4 bits, the third + // is drawn using the color in the high-order 4 bits, and so on, until all the + // pixels specified by the first byte have been drawn. + $paletteindexes[0] = ($secondbyte & 0xF0) >> 4; + $paletteindexes[1] = ($secondbyte & 0x0F); + for ($i = 0; $i < $firstbyte; $i++) { + $col = $pixelcounter % $thisfile_bmp_header_raw['width']; + $row = $thisfile_bmp_header_raw['height'] - 1 - (($pixelcounter - $col) / $thisfile_bmp_header_raw['width']); + $thisfile_bmp['data'][$row][$col] = $thisfile_bmp['palette'][$paletteindexes[($i % 2)]]; + $pixelcounter++; + } + + } + } + break; + + default: + $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + case 3: // BI_BITFIELDS + switch ($thisfile_bmp_header_raw['bits_per_pixel']) { + case 16: + case 32: + $redshift = 0; + $greenshift = 0; + $blueshift = 0; + while ((($thisfile_bmp_header_raw['red_mask'] >> $redshift) & 0x01) == 0) { + $redshift++; + } + while ((($thisfile_bmp_header_raw['green_mask'] >> $greenshift) & 0x01) == 0) { + $greenshift++; + } + while ((($thisfile_bmp_header_raw['blue_mask'] >> $blueshift) & 0x01) == 0) { + $blueshift++; + } + for ($row = ($thisfile_bmp_header_raw['height'] - 1); $row >= 0; $row--) { + for ($col = 0; $col < $thisfile_bmp_header_raw['width']; $col++) { + $pixelvalue = getid3_lib::LittleEndian2Int(substr($BMPpixelData, $pixeldataoffset, $thisfile_bmp_header_raw['bits_per_pixel'] / 8)); + $pixeldataoffset += $thisfile_bmp_header_raw['bits_per_pixel'] / 8; + + $red = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['red_mask']) >> $redshift) / ($thisfile_bmp_header_raw['red_mask'] >> $redshift)) * 255)); + $green = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['green_mask']) >> $greenshift) / ($thisfile_bmp_header_raw['green_mask'] >> $greenshift)) * 255)); + $blue = intval(round(((($pixelvalue & $thisfile_bmp_header_raw['blue_mask']) >> $blueshift) / ($thisfile_bmp_header_raw['blue_mask'] >> $blueshift)) * 255)); + $thisfile_bmp['data'][$row][$col] = (($red << 16) | ($green << 8) | ($blue)); + } + while (($pixeldataoffset % 4) != 0) { + // lines are padded to nearest DWORD + $pixeldataoffset++; + } + } + break; + + default: + $info['error'][] = 'Unknown bits-per-pixel value ('.$thisfile_bmp_header_raw['bits_per_pixel'].') - cannot read pixel data'; + break; + } + break; + + + default: // unhandled compression type + $info['error'][] = 'Unknown/unhandled compression type value ('.$thisfile_bmp_header_raw['compression'].') - cannot decompress pixel data'; + break; + } + } + + return true; + } + + + public function PlotBMP(&$BMPinfo) { + $starttime = time(); + if (!isset($BMPinfo['bmp']['data']) || !is_array($BMPinfo['bmp']['data'])) { + echo 'ERROR: no pixel data
    '; + return false; + } + set_time_limit(intval(round($BMPinfo['resolution_x'] * $BMPinfo['resolution_y'] / 10000))); + if ($im = ImageCreateTrueColor($BMPinfo['resolution_x'], $BMPinfo['resolution_y'])) { + for ($row = 0; $row < $BMPinfo['resolution_y']; $row++) { + for ($col = 0; $col < $BMPinfo['resolution_x']; $col++) { + if (isset($BMPinfo['bmp']['data'][$row][$col])) { + $red = ($BMPinfo['bmp']['data'][$row][$col] & 0x00FF0000) >> 16; + $green = ($BMPinfo['bmp']['data'][$row][$col] & 0x0000FF00) >> 8; + $blue = ($BMPinfo['bmp']['data'][$row][$col] & 0x000000FF); + $pixelcolor = ImageColorAllocate($im, $red, $green, $blue); + ImageSetPixel($im, $col, $row, $pixelcolor); + } else { + //echo 'ERROR: no data for pixel '.$row.' x '.$col.'
    '; + //return false; + } + } + } + if (headers_sent()) { + echo 'plotted '.($BMPinfo['resolution_x'] * $BMPinfo['resolution_y']).' pixels in '.(time() - $starttime).' seconds
    '; + ImageDestroy($im); + exit; + } else { + header('Content-type: image/png'); + ImagePNG($im); + ImageDestroy($im); + return true; + } + } + return false; + } + + public function BMPcompressionWindowsLookup($compressionid) { + static $BMPcompressionWindowsLookup = array( + 0 => 'BI_RGB', + 1 => 'BI_RLE8', + 2 => 'BI_RLE4', + 3 => 'BI_BITFIELDS', + 4 => 'BI_JPEG', + 5 => 'BI_PNG' + ); + return (isset($BMPcompressionWindowsLookup[$compressionid]) ? $BMPcompressionWindowsLookup[$compressionid] : 'invalid'); + } + + public function BMPcompressionOS2Lookup($compressionid) { + static $BMPcompressionOS2Lookup = array( + 0 => 'BI_RGB', + 1 => 'BI_RLE8', + 2 => 'BI_RLE4', + 3 => 'Huffman 1D', + 4 => 'BI_RLE24', + ); + return (isset($BMPcompressionOS2Lookup[$compressionid]) ? $BMPcompressionOS2Lookup[$compressionid] : 'invalid'); + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.efax.php b/app/libs/vendor/getid3/module.graphic.efax.php index 5c20c60d..dfedf6e6 100644 --- a/app/libs/vendor/getid3/module.graphic.efax.php +++ b/app/libs/vendor/getid3/module.graphic.efax.php @@ -1,50 +1,50 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.efax.php // -// module for analyzing eFax files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_efax extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $efaxheader = fread($this->getid3->fp, 1024); - - $info['efax']['header']['magic'] = substr($efaxheader, 0, 2); - if ($info['efax']['header']['magic'] != "\xDC\xFE") { - $info['error'][] = 'Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset']; - return false; - } - $info['fileformat'] = 'efax'; - - $info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4)); - if ($info['efax']['header']['filesize'] != $info['filesize']) { - $info['error'][] = 'Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes'; - } - $info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00"); - $info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00"); - $info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00"); - - $info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2)); - $info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4)); - -$info['error'][] = 'eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.efax.php // +// module for analyzing eFax files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_efax extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $efaxheader = fread($this->getid3->fp, 1024); + + $info['efax']['header']['magic'] = substr($efaxheader, 0, 2); + if ($info['efax']['header']['magic'] != "\xDC\xFE") { + $info['error'][] = 'Invalid eFax byte order identifier (expecting DC FE, found '.getid3_lib::PrintHexBytes($info['efax']['header']['magic']).') at offset '.$info['avdataoffset']; + return false; + } + $info['fileformat'] = 'efax'; + + $info['efax']['header']['filesize'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 2, 4)); + if ($info['efax']['header']['filesize'] != $info['filesize']) { + $info['error'][] = 'Probable '.(($info['efax']['header']['filesize'] > $info['filesize']) ? 'truncated' : 'corrupt').' file, expecting '.$info['efax']['header']['filesize'].' bytes, found '.$info['filesize'].' bytes'; + } + $info['efax']['header']['software1'] = rtrim(substr($efaxheader, 26, 32), "\x00"); + $info['efax']['header']['software2'] = rtrim(substr($efaxheader, 58, 32), "\x00"); + $info['efax']['header']['software3'] = rtrim(substr($efaxheader, 90, 32), "\x00"); + + $info['efax']['header']['pages'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 198, 2)); + $info['efax']['header']['data_bytes'] = getid3_lib::LittleEndian2Int(substr($efaxheader, 202, 4)); + +$info['error'][] = 'eFax parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + + return true; + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.gif.php b/app/libs/vendor/getid3/module.graphic.gif.php index fb2f114d..cd8457e3 100644 --- a/app/libs/vendor/getid3/module.graphic.gif.php +++ b/app/libs/vendor/getid3/module.graphic.gif.php @@ -1,181 +1,181 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.gif.php // -// module for analyzing GIF Image files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_gif extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'gif'; - $info['video']['dataformat'] = 'gif'; - $info['video']['lossless'] = true; - $info['video']['pixel_aspect_ratio'] = (float) 1; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $GIFheader = fread($this->getid3->fp, 13); - $offset = 0; - - $info['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3); - $offset += 3; - - $magic = 'GIF'; - if ($info['gif']['header']['raw']['identifier'] != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['gif']['header']['raw']['identifier']).'"'; - unset($info['fileformat']); - unset($info['gif']); - return false; - } - - $info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3); - $offset += 3; - $info['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2)); - $offset += 2; - $info['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2)); - $offset += 2; - $info['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); - $offset += 1; - $info['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); - $offset += 1; - $info['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); - $offset += 1; - - $info['video']['resolution_x'] = $info['gif']['header']['raw']['width']; - $info['video']['resolution_y'] = $info['gif']['header']['raw']['height']; - $info['gif']['version'] = $info['gif']['header']['raw']['version']; - $info['gif']['header']['flags']['global_color_table'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x80); - if ($info['gif']['header']['raw']['flags'] & 0x80) { - // Number of bits per primary color available to the original image, minus 1 - $info['gif']['header']['bits_per_pixel'] = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1); - } else { - $info['gif']['header']['bits_per_pixel'] = 0; - } - $info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40); - if ($info['gif']['header']['flags']['global_color_table']) { - // the number of bytes contained in the Global Color Table. To determine that - // actual size of the color table, raise 2 to [the value of the field + 1] - $info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x07) + 1); - $info['video']['bits_per_sample'] = ($info['gif']['header']['raw']['flags'] & 0x07) + 1; - } else { - $info['gif']['header']['global_color_size'] = 0; - } - if ($info['gif']['header']['raw']['aspect_ratio'] != 0) { - // Aspect Ratio = (Pixel Aspect Ratio + 15) / 64 - $info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64; - } - -// if ($info['gif']['header']['flags']['global_color_table']) { -// $GIFcolorTable = fread($this->getid3->fp, 3 * $info['gif']['header']['global_color_size']); -// $offset = 0; -// for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) { -// $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); -// $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); -// $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); -// $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue)); -// } -// } -// -// // Image Descriptor -// while (!feof($this->getid3->fp)) { -// $NextBlockTest = fread($this->getid3->fp, 1); -// switch ($NextBlockTest) { -// -// case ',': // ',' - Image separator character -// -// $ImageDescriptorData = $NextBlockTest.fread($this->getid3->fp, 9); -// $ImageDescriptor = array(); -// $ImageDescriptor['image_left'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2)); -// $ImageDescriptor['image_top'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2)); -// $ImageDescriptor['image_width'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2)); -// $ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2)); -// $ImageDescriptor['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1)); -// $ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80); -// $ImageDescriptor['flags']['image_interlaced'] = (bool) ($ImageDescriptor['flags_raw'] & 0x40); -// $info['gif']['image_descriptor'][] = $ImageDescriptor; -// -// if ($ImageDescriptor['flags']['use_local_color_map']) { -// -// $info['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs'; -// return true; -// -// } -//echo 'Start of raster data: '.ftell($this->getid3->fp).'
    '; -// $RasterData = array(); -// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); -// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); -// $info['gif']['raster_data'][count($info['gif']['image_descriptor']) - 1] = $RasterData; -// -// $CurrentCodeSize = $RasterData['code_size'] + 1; -// for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) { -// $DefaultDataLookupTable[$i] = chr($i); -// } -// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code -// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code -// -// -// $NextValue = $this->GetLSBits($CurrentCodeSize); -// echo 'Clear Code: '.$NextValue.'
    '; -// -// $NextValue = $this->GetLSBits($CurrentCodeSize); -// echo 'First Color: '.$NextValue.'
    '; -// -// $Prefix = $NextValue; -//$i = 0; -// while ($i++ < 20) { -// $NextValue = $this->GetLSBits($CurrentCodeSize); -// echo $NextValue.'
    '; -// } -//return true; -// break; -// -// case '!': -// // GIF Extension Block -// $ExtensionBlockData = $NextBlockTest.fread($this->getid3->fp, 2); -// $ExtensionBlock = array(); -// $ExtensionBlock['function_code'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1)); -// $ExtensionBlock['byte_length'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1)); -// $ExtensionBlock['data'] = fread($this->getid3->fp, $ExtensionBlock['byte_length']); -// $info['gif']['extension_blocks'][] = $ExtensionBlock; -// break; -// -// case ';': -// $info['gif']['terminator_offset'] = ftell($this->getid3->fp) - 1; -// // GIF Terminator -// break; -// -// default: -// break; -// -// -// } -// } - - return true; - } - - - public function GetLSBits($bits) { - static $bitbuffer = ''; - while (strlen($bitbuffer) < $bits) { - $bitbuffer = str_pad(decbin(ord(fread($this->getid3->fp, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer; - } - $value = bindec(substr($bitbuffer, 0 - $bits)); - $bitbuffer = substr($bitbuffer, 0, 0 - $bits); - - return $value; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.gif.php // +// module for analyzing GIF Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_gif extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'gif'; + $info['video']['dataformat'] = 'gif'; + $info['video']['lossless'] = true; + $info['video']['pixel_aspect_ratio'] = (float) 1; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $GIFheader = fread($this->getid3->fp, 13); + $offset = 0; + + $info['gif']['header']['raw']['identifier'] = substr($GIFheader, $offset, 3); + $offset += 3; + + $magic = 'GIF'; + if ($info['gif']['header']['raw']['identifier'] != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes($info['gif']['header']['raw']['identifier']).'"'; + unset($info['fileformat']); + unset($info['gif']); + return false; + } + + $info['gif']['header']['raw']['version'] = substr($GIFheader, $offset, 3); + $offset += 3; + $info['gif']['header']['raw']['width'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2)); + $offset += 2; + $info['gif']['header']['raw']['height'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 2)); + $offset += 2; + $info['gif']['header']['raw']['flags'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); + $offset += 1; + $info['gif']['header']['raw']['bg_color_index'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); + $offset += 1; + $info['gif']['header']['raw']['aspect_ratio'] = getid3_lib::LittleEndian2Int(substr($GIFheader, $offset, 1)); + $offset += 1; + + $info['video']['resolution_x'] = $info['gif']['header']['raw']['width']; + $info['video']['resolution_y'] = $info['gif']['header']['raw']['height']; + $info['gif']['version'] = $info['gif']['header']['raw']['version']; + $info['gif']['header']['flags']['global_color_table'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x80); + if ($info['gif']['header']['raw']['flags'] & 0x80) { + // Number of bits per primary color available to the original image, minus 1 + $info['gif']['header']['bits_per_pixel'] = 3 * ((($info['gif']['header']['raw']['flags'] & 0x70) >> 4) + 1); + } else { + $info['gif']['header']['bits_per_pixel'] = 0; + } + $info['gif']['header']['flags']['global_color_sorted'] = (bool) ($info['gif']['header']['raw']['flags'] & 0x40); + if ($info['gif']['header']['flags']['global_color_table']) { + // the number of bytes contained in the Global Color Table. To determine that + // actual size of the color table, raise 2 to [the value of the field + 1] + $info['gif']['header']['global_color_size'] = pow(2, ($info['gif']['header']['raw']['flags'] & 0x07) + 1); + $info['video']['bits_per_sample'] = ($info['gif']['header']['raw']['flags'] & 0x07) + 1; + } else { + $info['gif']['header']['global_color_size'] = 0; + } + if ($info['gif']['header']['raw']['aspect_ratio'] != 0) { + // Aspect Ratio = (Pixel Aspect Ratio + 15) / 64 + $info['gif']['header']['aspect_ratio'] = ($info['gif']['header']['raw']['aspect_ratio'] + 15) / 64; + } + +// if ($info['gif']['header']['flags']['global_color_table']) { +// $GIFcolorTable = fread($this->getid3->fp, 3 * $info['gif']['header']['global_color_size']); +// $offset = 0; +// for ($i = 0; $i < $info['gif']['header']['global_color_size']; $i++) { +// $red = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); +// $green = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); +// $blue = getid3_lib::LittleEndian2Int(substr($GIFcolorTable, $offset++, 1)); +// $info['gif']['global_color_table'][$i] = (($red << 16) | ($green << 8) | ($blue)); +// } +// } +// +// // Image Descriptor +// while (!feof($this->getid3->fp)) { +// $NextBlockTest = fread($this->getid3->fp, 1); +// switch ($NextBlockTest) { +// +// case ',': // ',' - Image separator character +// +// $ImageDescriptorData = $NextBlockTest.fread($this->getid3->fp, 9); +// $ImageDescriptor = array(); +// $ImageDescriptor['image_left'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 1, 2)); +// $ImageDescriptor['image_top'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 3, 2)); +// $ImageDescriptor['image_width'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 5, 2)); +// $ImageDescriptor['image_height'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 7, 2)); +// $ImageDescriptor['flags_raw'] = getid3_lib::LittleEndian2Int(substr($ImageDescriptorData, 9, 1)); +// $ImageDescriptor['flags']['use_local_color_map'] = (bool) ($ImageDescriptor['flags_raw'] & 0x80); +// $ImageDescriptor['flags']['image_interlaced'] = (bool) ($ImageDescriptor['flags_raw'] & 0x40); +// $info['gif']['image_descriptor'][] = $ImageDescriptor; +// +// if ($ImageDescriptor['flags']['use_local_color_map']) { +// +// $info['warning'][] = 'This version of getID3() cannot parse local color maps for GIFs'; +// return true; +// +// } +//echo 'Start of raster data: '.ftell($this->getid3->fp).'
    '; +// $RasterData = array(); +// $RasterData['code_size'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); +// $RasterData['block_byte_count'] = getid3_lib::LittleEndian2Int(fread($this->getid3->fp, 1)); +// $info['gif']['raster_data'][count($info['gif']['image_descriptor']) - 1] = $RasterData; +// +// $CurrentCodeSize = $RasterData['code_size'] + 1; +// for ($i = 0; $i < pow(2, $RasterData['code_size']); $i++) { +// $DefaultDataLookupTable[$i] = chr($i); +// } +// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 0] = ''; // Clear Code +// $DefaultDataLookupTable[pow(2, $RasterData['code_size']) + 1] = ''; // End Of Image Code +// +// +// $NextValue = $this->GetLSBits($CurrentCodeSize); +// echo 'Clear Code: '.$NextValue.'
    '; +// +// $NextValue = $this->GetLSBits($CurrentCodeSize); +// echo 'First Color: '.$NextValue.'
    '; +// +// $Prefix = $NextValue; +//$i = 0; +// while ($i++ < 20) { +// $NextValue = $this->GetLSBits($CurrentCodeSize); +// echo $NextValue.'
    '; +// } +//return true; +// break; +// +// case '!': +// // GIF Extension Block +// $ExtensionBlockData = $NextBlockTest.fread($this->getid3->fp, 2); +// $ExtensionBlock = array(); +// $ExtensionBlock['function_code'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 1, 1)); +// $ExtensionBlock['byte_length'] = getid3_lib::LittleEndian2Int(substr($ExtensionBlockData, 2, 1)); +// $ExtensionBlock['data'] = fread($this->getid3->fp, $ExtensionBlock['byte_length']); +// $info['gif']['extension_blocks'][] = $ExtensionBlock; +// break; +// +// case ';': +// $info['gif']['terminator_offset'] = ftell($this->getid3->fp) - 1; +// // GIF Terminator +// break; +// +// default: +// break; +// +// +// } +// } + + return true; + } + + + public function GetLSBits($bits) { + static $bitbuffer = ''; + while (strlen($bitbuffer) < $bits) { + $bitbuffer = str_pad(decbin(ord(fread($this->getid3->fp, 1))), 8, '0', STR_PAD_LEFT).$bitbuffer; + } + $value = bindec(substr($bitbuffer, 0 - $bits)); + $bitbuffer = substr($bitbuffer, 0, 0 - $bits); + + return $value; + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.jpg.php b/app/libs/vendor/getid3/module.graphic.jpg.php index cc6a6457..3db65438 100644 --- a/app/libs/vendor/getid3/module.graphic.jpg.php +++ b/app/libs/vendor/getid3/module.graphic.jpg.php @@ -1,344 +1,344 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.jpg.php // -// module for analyzing JPEG Image files // -// dependencies: PHP compiled with --enable-exif (optional) // -// module.tag.xmp.php (optional) // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_jpg extends getid3_handler -{ - - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'jpg'; - $info['video']['dataformat'] = 'jpg'; - $info['video']['lossless'] = false; - $info['video']['bits_per_sample'] = 24; - $info['video']['pixel_aspect_ratio'] = (float) 1; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $imageinfo = array(); - //list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo); - list($width, $height, $type) = getimagesize($info['filenamepath'], $imageinfo); // http://www.getid3.org/phpBB3/viewtopic.php?t=1474 - - - if (isset($imageinfo['APP13'])) { - // http://php.net/iptcparse - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html - $iptc_parsed = iptcparse($imageinfo['APP13']); - if (is_array($iptc_parsed)) { - foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) { - list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw); - $iptc_tagkey = intval(ltrim($iptc_tagkey, '0')); - foreach ($iptc_values as $key => $value) { - $IPTCrecordName = $this->IPTCrecordName($iptc_record); - $IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey); - if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) { - $info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value; - } else { - $info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value); - } - } - } - } - } - - $returnOK = false; - switch ($type) { - case IMG_JPG: - $info['video']['resolution_x'] = $width; - $info['video']['resolution_y'] = $height; - - if (isset($imageinfo['APP1'])) { - if (function_exists('exif_read_data')) { - if (substr($imageinfo['APP1'], 0, 4) == 'Exif') { -//$info['warning'][] = 'known issue: https://bugs.php.net/bug.php?id=62523'; -//return false; - $info['jpg']['exif'] = exif_read_data($info['filenamepath'], null, true, false); - } else { - $info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")'; - } - } else { - $info['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif'); - } - } - $returnOK = true; - break; - - default: - break; - } - - - $cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL'); - foreach ($cast_as_appropriate_keys as $exif_key) { - if (isset($info['jpg']['exif'][$exif_key])) { - foreach ($info['jpg']['exif'][$exif_key] as $key => $value) { - $info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value); - } - } - } - - - if (isset($info['jpg']['exif']['GPS'])) { - - if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) { - for ($i = 0; $i < 4; $i++) { - $version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1)); - } - $info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts); - } - - if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) { - $explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']); - $computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : ''); - $computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : ''); - $computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : ''); - - if (function_exists('date_default_timezone_set')) { - date_default_timezone_set('UTC'); - } else { - ini_set('date.timezone', 'UTC'); - } - - $computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0); - if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) { - foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) { - $computed_time[$key] = getid3_lib::DecimalizeFraction($value); - } - } - $info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]); - } - - if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) { - $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1); - foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) { - $computed_latitude[$key] = getid3_lib::DecimalizeFraction($value); - } - $info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600)); - } - - if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) { - $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1); - foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) { - $computed_longitude[$key] = getid3_lib::DecimalizeFraction($value); - } - $info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600)); - } - if (isset($info['jpg']['exif']['GPS']['GPSAltitudeRef'])) { - $info['jpg']['exif']['GPS']['GPSAltitudeRef'] = ord($info['jpg']['exif']['GPS']['GPSAltitudeRef']); // 0 = above sea level; 1 = below sea level - } - if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) { - $direction_multiplier = (!empty($info['jpg']['exif']['GPS']['GPSAltitudeRef']) ? -1 : 1); // 0 = above sea level; 1 = below sea level - $info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']); - } - - } - - - if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.xmp.php', __FILE__, false)) { - if (isset($info['filenamepath'])) { - $image_xmp = new Image_XMP($info['filenamepath']); - $xmp_raw = $image_xmp->getAllTags(); - foreach ($xmp_raw as $key => $value) { - if (strpos($key, ':')) { - list($subsection, $tagname) = explode(':', $key); - $info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value); - } else { - $info['warning'][] = 'XMP: expecting ":", found "'.$key.'"'; - } - } - } - } - - if (!$returnOK) { - unset($info['fileformat']); - return false; - } - return true; - } - - - public function CastAsAppropriate($value) { - if (is_array($value)) { - return $value; - } elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) { - return getid3_lib::DecimalizeFraction($value); - } elseif (preg_match('#^[0-9]+$#', $value)) { - return getid3_lib::CastAsInt($value); - } elseif (preg_match('#^[0-9\.]+$#', $value)) { - return (float) $value; - } - return $value; - } - - - public function IPTCrecordName($iptc_record) { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html - static $IPTCrecordName = array(); - if (empty($IPTCrecordName)) { - $IPTCrecordName = array( - 1 => 'IPTCEnvelope', - 2 => 'IPTCApplication', - 3 => 'IPTCNewsPhoto', - 7 => 'IPTCPreObjectData', - 8 => 'IPTCObjectData', - 9 => 'IPTCPostObjectData', - ); - } - return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : ''); - } - - - public function IPTCrecordTagName($iptc_record, $iptc_tagkey) { - // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html - static $IPTCrecordTagName = array(); - if (empty($IPTCrecordTagName)) { - $IPTCrecordTagName = array( - 1 => array( // IPTC EnvelopeRecord Tags - 0 => 'EnvelopeRecordVersion', - 5 => 'Destination', - 20 => 'FileFormat', - 22 => 'FileVersion', - 30 => 'ServiceIdentifier', - 40 => 'EnvelopeNumber', - 50 => 'ProductID', - 60 => 'EnvelopePriority', - 70 => 'DateSent', - 80 => 'TimeSent', - 90 => 'CodedCharacterSet', - 100 => 'UniqueObjectName', - 120 => 'ARMIdentifier', - 122 => 'ARMVersion', - ), - 2 => array( // IPTC ApplicationRecord Tags - 0 => 'ApplicationRecordVersion', - 3 => 'ObjectTypeReference', - 4 => 'ObjectAttributeReference', - 5 => 'ObjectName', - 7 => 'EditStatus', - 8 => 'EditorialUpdate', - 10 => 'Urgency', - 12 => 'SubjectReference', - 15 => 'Category', - 20 => 'SupplementalCategories', - 22 => 'FixtureIdentifier', - 25 => 'Keywords', - 26 => 'ContentLocationCode', - 27 => 'ContentLocationName', - 30 => 'ReleaseDate', - 35 => 'ReleaseTime', - 37 => 'ExpirationDate', - 38 => 'ExpirationTime', - 40 => 'SpecialInstructions', - 42 => 'ActionAdvised', - 45 => 'ReferenceService', - 47 => 'ReferenceDate', - 50 => 'ReferenceNumber', - 55 => 'DateCreated', - 60 => 'TimeCreated', - 62 => 'DigitalCreationDate', - 63 => 'DigitalCreationTime', - 65 => 'OriginatingProgram', - 70 => 'ProgramVersion', - 75 => 'ObjectCycle', - 80 => 'By-line', - 85 => 'By-lineTitle', - 90 => 'City', - 92 => 'Sub-location', - 95 => 'Province-State', - 100 => 'Country-PrimaryLocationCode', - 101 => 'Country-PrimaryLocationName', - 103 => 'OriginalTransmissionReference', - 105 => 'Headline', - 110 => 'Credit', - 115 => 'Source', - 116 => 'CopyrightNotice', - 118 => 'Contact', - 120 => 'Caption-Abstract', - 121 => 'LocalCaption', - 122 => 'Writer-Editor', - 125 => 'RasterizedCaption', - 130 => 'ImageType', - 131 => 'ImageOrientation', - 135 => 'LanguageIdentifier', - 150 => 'AudioType', - 151 => 'AudioSamplingRate', - 152 => 'AudioSamplingResolution', - 153 => 'AudioDuration', - 154 => 'AudioOutcue', - 184 => 'JobID', - 185 => 'MasterDocumentID', - 186 => 'ShortDocumentID', - 187 => 'UniqueDocumentID', - 188 => 'OwnerID', - 200 => 'ObjectPreviewFileFormat', - 201 => 'ObjectPreviewFileVersion', - 202 => 'ObjectPreviewData', - 221 => 'Prefs', - 225 => 'ClassifyState', - 228 => 'SimilarityIndex', - 230 => 'DocumentNotes', - 231 => 'DocumentHistory', - 232 => 'ExifCameraInfo', - ), - 3 => array( // IPTC NewsPhoto Tags - 0 => 'NewsPhotoVersion', - 10 => 'IPTCPictureNumber', - 20 => 'IPTCImageWidth', - 30 => 'IPTCImageHeight', - 40 => 'IPTCPixelWidth', - 50 => 'IPTCPixelHeight', - 55 => 'SupplementalType', - 60 => 'ColorRepresentation', - 64 => 'InterchangeColorSpace', - 65 => 'ColorSequence', - 66 => 'ICC_Profile', - 70 => 'ColorCalibrationMatrix', - 80 => 'LookupTable', - 84 => 'NumIndexEntries', - 85 => 'ColorPalette', - 86 => 'IPTCBitsPerSample', - 90 => 'SampleStructure', - 100 => 'ScanningDirection', - 102 => 'IPTCImageRotation', - 110 => 'DataCompressionMethod', - 120 => 'QuantizationMethod', - 125 => 'EndPoints', - 130 => 'ExcursionTolerance', - 135 => 'BitsPerComponent', - 140 => 'MaximumDensityRange', - 145 => 'GammaCompensatedValue', - ), - 7 => array( // IPTC PreObjectData Tags - 10 => 'SizeMode', - 20 => 'MaxSubfileSize', - 90 => 'ObjectSizeAnnounced', - 95 => 'MaximumObjectSize', - ), - 8 => array( // IPTC ObjectData Tags - 10 => 'SubFile', - ), - 9 => array( // IPTC PostObjectData Tags - 10 => 'ConfirmedObjectSize', - ), - ); - - } - return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.jpg.php // +// module for analyzing JPEG Image files // +// dependencies: PHP compiled with --enable-exif (optional) // +// module.tag.xmp.php (optional) // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_jpg extends getid3_handler +{ + + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'jpg'; + $info['video']['dataformat'] = 'jpg'; + $info['video']['lossless'] = false; + $info['video']['bits_per_sample'] = 24; + $info['video']['pixel_aspect_ratio'] = (float) 1; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $imageinfo = array(); + //list($width, $height, $type) = getid3_lib::GetDataImageSize(fread($this->getid3->fp, $info['filesize']), $imageinfo); + list($width, $height, $type) = getimagesize($info['filenamepath'], $imageinfo); // http://www.getid3.org/phpBB3/viewtopic.php?t=1474 + + + if (isset($imageinfo['APP13'])) { + // http://php.net/iptcparse + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html + $iptc_parsed = iptcparse($imageinfo['APP13']); + if (is_array($iptc_parsed)) { + foreach ($iptc_parsed as $iptc_key_raw => $iptc_values) { + list($iptc_record, $iptc_tagkey) = explode('#', $iptc_key_raw); + $iptc_tagkey = intval(ltrim($iptc_tagkey, '0')); + foreach ($iptc_values as $key => $value) { + $IPTCrecordName = $this->IPTCrecordName($iptc_record); + $IPTCrecordTagName = $this->IPTCrecordTagName($iptc_record, $iptc_tagkey); + if (isset($info['iptc'][$IPTCrecordName][$IPTCrecordTagName])) { + $info['iptc'][$IPTCrecordName][$IPTCrecordTagName][] = $value; + } else { + $info['iptc'][$IPTCrecordName][$IPTCrecordTagName] = array($value); + } + } + } + } + } + + $returnOK = false; + switch ($type) { + case IMG_JPG: + $info['video']['resolution_x'] = $width; + $info['video']['resolution_y'] = $height; + + if (isset($imageinfo['APP1'])) { + if (function_exists('exif_read_data')) { + if (substr($imageinfo['APP1'], 0, 4) == 'Exif') { +//$info['warning'][] = 'known issue: https://bugs.php.net/bug.php?id=62523'; +//return false; + $info['jpg']['exif'] = exif_read_data($info['filenamepath'], null, true, false); + } else { + $info['warning'][] = 'exif_read_data() cannot parse non-EXIF data in APP1 (expected "Exif", found "'.substr($imageinfo['APP1'], 0, 4).'")'; + } + } else { + $info['warning'][] = 'EXIF parsing only available when '.(GETID3_OS_ISWINDOWS ? 'php_exif.dll enabled' : 'compiled with --enable-exif'); + } + } + $returnOK = true; + break; + + default: + break; + } + + + $cast_as_appropriate_keys = array('EXIF', 'IFD0', 'THUMBNAIL'); + foreach ($cast_as_appropriate_keys as $exif_key) { + if (isset($info['jpg']['exif'][$exif_key])) { + foreach ($info['jpg']['exif'][$exif_key] as $key => $value) { + $info['jpg']['exif'][$exif_key][$key] = $this->CastAsAppropriate($value); + } + } + } + + + if (isset($info['jpg']['exif']['GPS'])) { + + if (isset($info['jpg']['exif']['GPS']['GPSVersion'])) { + for ($i = 0; $i < 4; $i++) { + $version_subparts[$i] = ord(substr($info['jpg']['exif']['GPS']['GPSVersion'], $i, 1)); + } + $info['jpg']['exif']['GPS']['computed']['version'] = 'v'.implode('.', $version_subparts); + } + + if (isset($info['jpg']['exif']['GPS']['GPSDateStamp'])) { + $explodedGPSDateStamp = explode(':', $info['jpg']['exif']['GPS']['GPSDateStamp']); + $computed_time[5] = (isset($explodedGPSDateStamp[0]) ? $explodedGPSDateStamp[0] : ''); + $computed_time[3] = (isset($explodedGPSDateStamp[1]) ? $explodedGPSDateStamp[1] : ''); + $computed_time[4] = (isset($explodedGPSDateStamp[2]) ? $explodedGPSDateStamp[2] : ''); + + if (function_exists('date_default_timezone_set')) { + date_default_timezone_set('UTC'); + } else { + ini_set('date.timezone', 'UTC'); + } + + $computed_time = array(0=>0, 1=>0, 2=>0, 3=>0, 4=>0, 5=>0); + if (isset($info['jpg']['exif']['GPS']['GPSTimeStamp']) && is_array($info['jpg']['exif']['GPS']['GPSTimeStamp'])) { + foreach ($info['jpg']['exif']['GPS']['GPSTimeStamp'] as $key => $value) { + $computed_time[$key] = getid3_lib::DecimalizeFraction($value); + } + } + $info['jpg']['exif']['GPS']['computed']['timestamp'] = mktime($computed_time[0], $computed_time[1], $computed_time[2], $computed_time[3], $computed_time[4], $computed_time[5]); + } + + if (isset($info['jpg']['exif']['GPS']['GPSLatitude']) && is_array($info['jpg']['exif']['GPS']['GPSLatitude'])) { + $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLatitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLatitudeRef'] == 'S')) ? -1 : 1); + foreach ($info['jpg']['exif']['GPS']['GPSLatitude'] as $key => $value) { + $computed_latitude[$key] = getid3_lib::DecimalizeFraction($value); + } + $info['jpg']['exif']['GPS']['computed']['latitude'] = $direction_multiplier * ($computed_latitude[0] + ($computed_latitude[1] / 60) + ($computed_latitude[2] / 3600)); + } + + if (isset($info['jpg']['exif']['GPS']['GPSLongitude']) && is_array($info['jpg']['exif']['GPS']['GPSLongitude'])) { + $direction_multiplier = ((isset($info['jpg']['exif']['GPS']['GPSLongitudeRef']) && ($info['jpg']['exif']['GPS']['GPSLongitudeRef'] == 'W')) ? -1 : 1); + foreach ($info['jpg']['exif']['GPS']['GPSLongitude'] as $key => $value) { + $computed_longitude[$key] = getid3_lib::DecimalizeFraction($value); + } + $info['jpg']['exif']['GPS']['computed']['longitude'] = $direction_multiplier * ($computed_longitude[0] + ($computed_longitude[1] / 60) + ($computed_longitude[2] / 3600)); + } + if (isset($info['jpg']['exif']['GPS']['GPSAltitudeRef'])) { + $info['jpg']['exif']['GPS']['GPSAltitudeRef'] = ord($info['jpg']['exif']['GPS']['GPSAltitudeRef']); // 0 = above sea level; 1 = below sea level + } + if (isset($info['jpg']['exif']['GPS']['GPSAltitude'])) { + $direction_multiplier = (!empty($info['jpg']['exif']['GPS']['GPSAltitudeRef']) ? -1 : 1); // 0 = above sea level; 1 = below sea level + $info['jpg']['exif']['GPS']['computed']['altitude'] = $direction_multiplier * getid3_lib::DecimalizeFraction($info['jpg']['exif']['GPS']['GPSAltitude']); + } + + } + + + if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.xmp.php', __FILE__, false)) { + if (isset($info['filenamepath'])) { + $image_xmp = new Image_XMP($info['filenamepath']); + $xmp_raw = $image_xmp->getAllTags(); + foreach ($xmp_raw as $key => $value) { + if (strpos($key, ':')) { + list($subsection, $tagname) = explode(':', $key); + $info['xmp'][$subsection][$tagname] = $this->CastAsAppropriate($value); + } else { + $info['warning'][] = 'XMP: expecting ":", found "'.$key.'"'; + } + } + } + } + + if (!$returnOK) { + unset($info['fileformat']); + return false; + } + return true; + } + + + public function CastAsAppropriate($value) { + if (is_array($value)) { + return $value; + } elseif (preg_match('#^[0-9]+/[0-9]+$#', $value)) { + return getid3_lib::DecimalizeFraction($value); + } elseif (preg_match('#^[0-9]+$#', $value)) { + return getid3_lib::CastAsInt($value); + } elseif (preg_match('#^[0-9\.]+$#', $value)) { + return (float) $value; + } + return $value; + } + + + public function IPTCrecordName($iptc_record) { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html + static $IPTCrecordName = array(); + if (empty($IPTCrecordName)) { + $IPTCrecordName = array( + 1 => 'IPTCEnvelope', + 2 => 'IPTCApplication', + 3 => 'IPTCNewsPhoto', + 7 => 'IPTCPreObjectData', + 8 => 'IPTCObjectData', + 9 => 'IPTCPostObjectData', + ); + } + return (isset($IPTCrecordName[$iptc_record]) ? $IPTCrecordName[$iptc_record] : ''); + } + + + public function IPTCrecordTagName($iptc_record, $iptc_tagkey) { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/IPTC.html + static $IPTCrecordTagName = array(); + if (empty($IPTCrecordTagName)) { + $IPTCrecordTagName = array( + 1 => array( // IPTC EnvelopeRecord Tags + 0 => 'EnvelopeRecordVersion', + 5 => 'Destination', + 20 => 'FileFormat', + 22 => 'FileVersion', + 30 => 'ServiceIdentifier', + 40 => 'EnvelopeNumber', + 50 => 'ProductID', + 60 => 'EnvelopePriority', + 70 => 'DateSent', + 80 => 'TimeSent', + 90 => 'CodedCharacterSet', + 100 => 'UniqueObjectName', + 120 => 'ARMIdentifier', + 122 => 'ARMVersion', + ), + 2 => array( // IPTC ApplicationRecord Tags + 0 => 'ApplicationRecordVersion', + 3 => 'ObjectTypeReference', + 4 => 'ObjectAttributeReference', + 5 => 'ObjectName', + 7 => 'EditStatus', + 8 => 'EditorialUpdate', + 10 => 'Urgency', + 12 => 'SubjectReference', + 15 => 'Category', + 20 => 'SupplementalCategories', + 22 => 'FixtureIdentifier', + 25 => 'Keywords', + 26 => 'ContentLocationCode', + 27 => 'ContentLocationName', + 30 => 'ReleaseDate', + 35 => 'ReleaseTime', + 37 => 'ExpirationDate', + 38 => 'ExpirationTime', + 40 => 'SpecialInstructions', + 42 => 'ActionAdvised', + 45 => 'ReferenceService', + 47 => 'ReferenceDate', + 50 => 'ReferenceNumber', + 55 => 'DateCreated', + 60 => 'TimeCreated', + 62 => 'DigitalCreationDate', + 63 => 'DigitalCreationTime', + 65 => 'OriginatingProgram', + 70 => 'ProgramVersion', + 75 => 'ObjectCycle', + 80 => 'By-line', + 85 => 'By-lineTitle', + 90 => 'City', + 92 => 'Sub-location', + 95 => 'Province-State', + 100 => 'Country-PrimaryLocationCode', + 101 => 'Country-PrimaryLocationName', + 103 => 'OriginalTransmissionReference', + 105 => 'Headline', + 110 => 'Credit', + 115 => 'Source', + 116 => 'CopyrightNotice', + 118 => 'Contact', + 120 => 'Caption-Abstract', + 121 => 'LocalCaption', + 122 => 'Writer-Editor', + 125 => 'RasterizedCaption', + 130 => 'ImageType', + 131 => 'ImageOrientation', + 135 => 'LanguageIdentifier', + 150 => 'AudioType', + 151 => 'AudioSamplingRate', + 152 => 'AudioSamplingResolution', + 153 => 'AudioDuration', + 154 => 'AudioOutcue', + 184 => 'JobID', + 185 => 'MasterDocumentID', + 186 => 'ShortDocumentID', + 187 => 'UniqueDocumentID', + 188 => 'OwnerID', + 200 => 'ObjectPreviewFileFormat', + 201 => 'ObjectPreviewFileVersion', + 202 => 'ObjectPreviewData', + 221 => 'Prefs', + 225 => 'ClassifyState', + 228 => 'SimilarityIndex', + 230 => 'DocumentNotes', + 231 => 'DocumentHistory', + 232 => 'ExifCameraInfo', + ), + 3 => array( // IPTC NewsPhoto Tags + 0 => 'NewsPhotoVersion', + 10 => 'IPTCPictureNumber', + 20 => 'IPTCImageWidth', + 30 => 'IPTCImageHeight', + 40 => 'IPTCPixelWidth', + 50 => 'IPTCPixelHeight', + 55 => 'SupplementalType', + 60 => 'ColorRepresentation', + 64 => 'InterchangeColorSpace', + 65 => 'ColorSequence', + 66 => 'ICC_Profile', + 70 => 'ColorCalibrationMatrix', + 80 => 'LookupTable', + 84 => 'NumIndexEntries', + 85 => 'ColorPalette', + 86 => 'IPTCBitsPerSample', + 90 => 'SampleStructure', + 100 => 'ScanningDirection', + 102 => 'IPTCImageRotation', + 110 => 'DataCompressionMethod', + 120 => 'QuantizationMethod', + 125 => 'EndPoints', + 130 => 'ExcursionTolerance', + 135 => 'BitsPerComponent', + 140 => 'MaximumDensityRange', + 145 => 'GammaCompensatedValue', + ), + 7 => array( // IPTC PreObjectData Tags + 10 => 'SizeMode', + 20 => 'MaxSubfileSize', + 90 => 'ObjectSizeAnnounced', + 95 => 'MaximumObjectSize', + ), + 8 => array( // IPTC ObjectData Tags + 10 => 'SubFile', + ), + 9 => array( // IPTC PostObjectData Tags + 10 => 'ConfirmedObjectSize', + ), + ); + + } + return (isset($IPTCrecordTagName[$iptc_record][$iptc_tagkey]) ? $IPTCrecordTagName[$iptc_record][$iptc_tagkey] : $iptc_tagkey); + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.pcd.php b/app/libs/vendor/getid3/module.graphic.pcd.php index c9d7594a..1f83a673 100644 --- a/app/libs/vendor/getid3/module.graphic.pcd.php +++ b/app/libs/vendor/getid3/module.graphic.pcd.php @@ -1,132 +1,132 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.pcd.php // -// module for analyzing PhotoCD (PCD) Image files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_pcd extends getid3_handler -{ - public $ExtractData = 0; - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'pcd'; - $info['video']['dataformat'] = 'pcd'; - $info['video']['lossless'] = false; - - - fseek($this->getid3->fp, $info['avdataoffset'] + 72, SEEK_SET); - - $PCDflags = fread($this->getid3->fp, 1); - $PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false); - - - if ($PCDisVertical) { - $info['video']['resolution_x'] = 3072; - $info['video']['resolution_y'] = 2048; - } else { - $info['video']['resolution_x'] = 2048; - $info['video']['resolution_y'] = 3072; - } - - - if ($this->ExtractData > 3) { - - $info['error'][] = 'Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.'; - - } elseif ($this->ExtractData > 0) { - - $PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16 - $PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4 - $PCD_levels[3] = array( 768, 512, 0x30000); // BASE - //$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption - //$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption - //$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only - - list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3]; - - fseek($this->getid3->fp, $info['avdataoffset'] + $PCD_dataOffset, SEEK_SET); - - for ($y = 0; $y < $PCD_height; $y += 2) { - // The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h. - // To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each - // consisting of ‘w’ bytes, where ‘w’ is the width of the image-subtype. The first ‘w’ bytes and - // the first half of the third ‘w’ bytes contain data for the first RGB-line, the second ‘w’ bytes - // and the second half of the third ‘w’ bytes contain data for a second RGB-line. - - $PCD_data_Y1 = fread($this->getid3->fp, $PCD_width); - $PCD_data_Y2 = fread($this->getid3->fp, $PCD_width); - $PCD_data_Cb = fread($this->getid3->fp, intval(round($PCD_width / 2))); - $PCD_data_Cr = fread($this->getid3->fp, intval(round($PCD_width / 2))); - - for ($x = 0; $x < $PCD_width; $x++) { - if ($PCDisVertical) { - $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); - $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); - } else { - $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); - $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); - } - } - } - - // Example for plotting extracted data - //getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); - //if ($PCDisVertical) { - // $BMPinfo['resolution_x'] = $PCD_height; - // $BMPinfo['resolution_y'] = $PCD_width; - //} else { - // $BMPinfo['resolution_x'] = $PCD_width; - // $BMPinfo['resolution_y'] = $PCD_height; - //} - //$BMPinfo['bmp']['data'] = $info['pcd']['data']; - //getid3_bmp::PlotBMP($BMPinfo); - //exit; - - } - - } - - public function YCbCr2RGB($Y, $Cb, $Cr) { - static $YCbCr_constants = array(); - if (empty($YCbCr_constants)) { - $YCbCr_constants['red']['Y'] = 0.0054980 * 256; - $YCbCr_constants['red']['Cb'] = 0.0000000 * 256; - $YCbCr_constants['red']['Cr'] = 0.0051681 * 256; - $YCbCr_constants['green']['Y'] = 0.0054980 * 256; - $YCbCr_constants['green']['Cb'] = -0.0015446 * 256; - $YCbCr_constants['green']['Cr'] = -0.0026325 * 256; - $YCbCr_constants['blue']['Y'] = 0.0054980 * 256; - $YCbCr_constants['blue']['Cb'] = 0.0079533 * 256; - $YCbCr_constants['blue']['Cr'] = 0.0000000 * 256; - } - - $RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0); - foreach ($RGBcolor as $rgbname => $dummy) { - $RGBcolor[$rgbname] = max(0, - min(255, - intval( - round( - ($YCbCr_constants[$rgbname]['Y'] * $Y) + - ($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) + - ($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137)) - ) - ) - ) - ); - } - return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.pcd.php // +// module for analyzing PhotoCD (PCD) Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_pcd extends getid3_handler +{ + public $ExtractData = 0; + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'pcd'; + $info['video']['dataformat'] = 'pcd'; + $info['video']['lossless'] = false; + + + fseek($this->getid3->fp, $info['avdataoffset'] + 72, SEEK_SET); + + $PCDflags = fread($this->getid3->fp, 1); + $PCDisVertical = ((ord($PCDflags) & 0x01) ? true : false); + + + if ($PCDisVertical) { + $info['video']['resolution_x'] = 3072; + $info['video']['resolution_y'] = 2048; + } else { + $info['video']['resolution_x'] = 2048; + $info['video']['resolution_y'] = 3072; + } + + + if ($this->ExtractData > 3) { + + $info['error'][] = 'Cannot extract PSD image data for detail levels above BASE (level-3) because encrypted with Kodak-proprietary compression/encryption.'; + + } elseif ($this->ExtractData > 0) { + + $PCD_levels[1] = array( 192, 128, 0x02000); // BASE/16 + $PCD_levels[2] = array( 384, 256, 0x0B800); // BASE/4 + $PCD_levels[3] = array( 768, 512, 0x30000); // BASE + //$PCD_levels[4] = array(1536, 1024, ??); // BASE*4 - encrypted with Kodak-proprietary compression/encryption + //$PCD_levels[5] = array(3072, 2048, ??); // BASE*16 - encrypted with Kodak-proprietary compression/encryption + //$PCD_levels[6] = array(6144, 4096, ??); // BASE*64 - encrypted with Kodak-proprietary compression/encryption; PhotoCD-Pro only + + list($PCD_width, $PCD_height, $PCD_dataOffset) = $PCD_levels[3]; + + fseek($this->getid3->fp, $info['avdataoffset'] + $PCD_dataOffset, SEEK_SET); + + for ($y = 0; $y < $PCD_height; $y += 2) { + // The image-data of these subtypes start at the respective offsets of 02000h, 0b800h and 30000h. + // To decode the YcbYr to the more usual RGB-code, three lines of data have to be read, each + // consisting of ‘w’ bytes, where ‘w’ is the width of the image-subtype. The first ‘w’ bytes and + // the first half of the third ‘w’ bytes contain data for the first RGB-line, the second ‘w’ bytes + // and the second half of the third ‘w’ bytes contain data for a second RGB-line. + + $PCD_data_Y1 = fread($this->getid3->fp, $PCD_width); + $PCD_data_Y2 = fread($this->getid3->fp, $PCD_width); + $PCD_data_Cb = fread($this->getid3->fp, intval(round($PCD_width / 2))); + $PCD_data_Cr = fread($this->getid3->fp, intval(round($PCD_width / 2))); + + for ($x = 0; $x < $PCD_width; $x++) { + if ($PCDisVertical) { + $info['pcd']['data'][$PCD_width - $x][$y] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); + $info['pcd']['data'][$PCD_width - $x][$y + 1] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); + } else { + $info['pcd']['data'][$y][$x] = $this->YCbCr2RGB(ord($PCD_data_Y1{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); + $info['pcd']['data'][$y + 1][$x] = $this->YCbCr2RGB(ord($PCD_data_Y2{$x}), ord($PCD_data_Cb{floor($x / 2)}), ord($PCD_data_Cr{floor($x / 2)})); + } + } + } + + // Example for plotting extracted data + //getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.audio.ac3.php', __FILE__, true); + //if ($PCDisVertical) { + // $BMPinfo['resolution_x'] = $PCD_height; + // $BMPinfo['resolution_y'] = $PCD_width; + //} else { + // $BMPinfo['resolution_x'] = $PCD_width; + // $BMPinfo['resolution_y'] = $PCD_height; + //} + //$BMPinfo['bmp']['data'] = $info['pcd']['data']; + //getid3_bmp::PlotBMP($BMPinfo); + //exit; + + } + + } + + public function YCbCr2RGB($Y, $Cb, $Cr) { + static $YCbCr_constants = array(); + if (empty($YCbCr_constants)) { + $YCbCr_constants['red']['Y'] = 0.0054980 * 256; + $YCbCr_constants['red']['Cb'] = 0.0000000 * 256; + $YCbCr_constants['red']['Cr'] = 0.0051681 * 256; + $YCbCr_constants['green']['Y'] = 0.0054980 * 256; + $YCbCr_constants['green']['Cb'] = -0.0015446 * 256; + $YCbCr_constants['green']['Cr'] = -0.0026325 * 256; + $YCbCr_constants['blue']['Y'] = 0.0054980 * 256; + $YCbCr_constants['blue']['Cb'] = 0.0079533 * 256; + $YCbCr_constants['blue']['Cr'] = 0.0000000 * 256; + } + + $RGBcolor = array('red'=>0, 'green'=>0, 'blue'=>0); + foreach ($RGBcolor as $rgbname => $dummy) { + $RGBcolor[$rgbname] = max(0, + min(255, + intval( + round( + ($YCbCr_constants[$rgbname]['Y'] * $Y) + + ($YCbCr_constants[$rgbname]['Cb'] * ($Cb - 156)) + + ($YCbCr_constants[$rgbname]['Cr'] * ($Cr - 137)) + ) + ) + ) + ); + } + return (($RGBcolor['red'] * 65536) + ($RGBcolor['green'] * 256) + $RGBcolor['blue']); + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.png.php b/app/libs/vendor/getid3/module.graphic.png.php index 47bbbbc8..250ca1b1 100644 --- a/app/libs/vendor/getid3/module.graphic.png.php +++ b/app/libs/vendor/getid3/module.graphic.png.php @@ -1,517 +1,517 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.png.php // -// module for analyzing PNG Image files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_png extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - // shortcut - $info['png'] = array(); - $thisfile_png = &$info['png']; - - $info['fileformat'] = 'png'; - $info['video']['dataformat'] = 'png'; - $info['video']['lossless'] = false; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $PNGfiledata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); - $offset = 0; - - $PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A - $offset += 8; - - if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") { - $info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier'; - unset($info['fileformat']); - return false; - } - - while (((ftell($this->getid3->fp) - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) { - $chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4)); - $offset += 4; - while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($this->getid3->fp) < $info['filesize'])) { - $PNGfiledata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size()); - } - $chunk['type_text'] = substr($PNGfiledata, $offset, 4); - $offset += 4; - $chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']); - $chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']); - $offset += $chunk['data_length']; - $chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4)); - $offset += 4; - - $chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000); - $chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000); - $chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000); - $chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020); - - // shortcut - $thisfile_png[$chunk['type_text']] = array(); - $thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']]; - - switch ($chunk['type_text']) { - - case 'IHDR': // Image Header - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)); - $thisfile_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)); - $thisfile_png_chunk_type_text['raw']['bit_depth'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); - $thisfile_png_chunk_type_text['raw']['color_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 9, 1)); - $thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1)); - $thisfile_png_chunk_type_text['raw']['filter_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1)); - $thisfile_png_chunk_type_text['raw']['interlace_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1)); - - $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']); - $thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01); - $thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02); - $thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04); - - $info['video']['resolution_x'] = $thisfile_png_chunk_type_text['width']; - $info['video']['resolution_y'] = $thisfile_png_chunk_type_text['height']; - - $info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']); - break; - - - case 'PLTE': // Palette - $thisfile_png_chunk_type_text['header'] = $chunk; - $paletteoffset = 0; - for ($i = 0; $i <= 255; $i++) { - //$thisfile_png_chunk_type_text['red'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - //$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - //$thisfile_png_chunk_type_text['blue'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - $red = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - $green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - $blue = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); - $thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue)); - } - break; - - - case 'tRNS': // Transparency - $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { - case 0: - $thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); - break; - - case 2: - $thisfile_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); - $thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2)); - $thisfile_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2)); - break; - - case 3: - for ($i = 0; $i < strlen($chunk['data']); $i++) { - $thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1)); - } - break; - - case 4: - case 6: - $info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']; - - default: - $info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']; - break; - } - break; - - - case 'gAMA': // Image Gamma - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($chunk['data']) / 100000; - break; - - - case 'cHRM': // Primary Chromaticities - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000; - $thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000; - $thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000; - $thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000; - $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000; - $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000; - $thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000; - $thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000; - break; - - - case 'sRGB': // Standard RGB Color Space - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($chunk['data']); - $thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']); - break; - - - case 'iCCP': // Embedded ICC Profile - $thisfile_png_chunk_type_text['header'] = $chunk; - list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['profile_name'] = $profilename; - $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1)); - $thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1); - - $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); - break; - - - case 'tEXt': // Textual Data - $thisfile_png_chunk_type_text['header'] = $chunk; - list($keyword, $text) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['keyword'] = $keyword; - $thisfile_png_chunk_type_text['text'] = $text; - - $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; - break; - - - case 'zTXt': // Compressed Textual Data - $thisfile_png_chunk_type_text['header'] = $chunk; - list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['keyword'] = $keyword; - $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); - $thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1); - $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); - switch ($thisfile_png_chunk_type_text['compression_method']) { - case 0: - $thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']); - break; - - default: - // unknown compression method - break; - } - - if (isset($thisfile_png_chunk_type_text['text'])) { - $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; - } - break; - - - case 'iTXt': // International Textual Data - $thisfile_png_chunk_type_text['header'] = $chunk; - list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['keyword'] = $keyword; - $thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); - $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1)); - $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); - list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3); - $thisfile_png_chunk_type_text['language_tag'] = $languagetag; - $thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword; - - if ($thisfile_png_chunk_type_text['compression']) { - - switch ($thisfile_png_chunk_type_text['compression_method']) { - case 0: - $thisfile_png_chunk_type_text['text'] = gzuncompress($text); - break; - - default: - // unknown compression method - break; - } - - } else { - - $thisfile_png_chunk_type_text['text'] = $text; - - } - - if (isset($thisfile_png_chunk_type_text['text'])) { - $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; - } - break; - - - case 'bKGD': // Background Color - $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { - case 0: - case 4: - $thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']); - break; - - case 2: - case 6: - $thisfile_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); - $thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); - $thisfile_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); - break; - - case 3: - $thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']); - break; - - default: - break; - } - break; - - - case 'pHYs': // Physical Pixel Dimensions - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)); - $thisfile_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)); - $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); - $thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); - break; - - - case 'sBIT': // Significant Bits - $thisfile_png_chunk_type_text['header'] = $chunk; - switch ($thisfile_png['IHDR']['raw']['color_type']) { - case 0: - $thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - break; - - case 2: - case 3: - $thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); - $thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); - break; - - case 4: - $thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); - break; - - case 6: - $thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); - $thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); - $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1)); - break; - - default: - break; - } - break; - - - case 'sPLT': // Suggested Palette - $thisfile_png_chunk_type_text['header'] = $chunk; - list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['palette_name'] = $palettename; - $sPLToffset = 0; - $thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1)); - $sPLToffset += 1; - $thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8; - $paletteCounter = 0; - while ($sPLToffset < strlen($otherdata)) { - $thisfile_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); - $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; - $thisfile_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); - $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; - $thisfile_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); - $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; - $thisfile_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); - $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; - $thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2)); - $sPLToffset += 2; - $paletteCounter++; - } - break; - - - case 'hIST': // Palette Histogram - $thisfile_png_chunk_type_text['header'] = $chunk; - $hISTcounter = 0; - while ($hISTcounter < strlen($chunk['data'])) { - $thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2)); - $hISTcounter += 2; - } - break; - - - case 'tIME': // Image Last-Modification Time - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); - $thisfile_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); - $thisfile_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1)); - $thisfile_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1)); - $thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1)); - $thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1)); - $thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']); - break; - - - case 'oFFs': // Image Offset - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true); - $thisfile_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true); - $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); - $thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); - break; - - - case 'pCAL': // Calibration Of Pixel Values - $thisfile_png_chunk_type_text['header'] = $chunk; - list($calibrationname, $otherdata) = explode("\x00", $chunk['data'], 2); - $thisfile_png_chunk_type_text['calibration_name'] = $calibrationname; - $pCALoffset = 0; - $thisfile_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true); - $pCALoffset += 4; - $thisfile_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true); - $pCALoffset += 4; - $thisfile_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1)); - $pCALoffset += 1; - $thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']); - $thisfile_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1)); - $pCALoffset += 1; - $thisfile_png_chunk_type_text['parameters'] = explode("\x00", substr($chunk['data'], $pCALoffset)); - break; - - - case 'sCAL': // Physical Scale Of Image Subject - $thisfile_png_chunk_type_text['header'] = $chunk; - $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - $thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); - list($pixelwidth, $pixelheight) = explode("\x00", substr($chunk['data'], 1)); - $thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth; - $thisfile_png_chunk_type_text['pixel_height'] = $pixelheight; - break; - - - case 'gIFg': // GIF Graphic Control Extension - $gIFgCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFgCounter = count($thisfile_png_chunk_type_text); - } - $thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk; - $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); - $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); - $thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2)); - break; - - - case 'gIFx': // GIF Application Extension - $gIFxCounter = 0; - if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { - $gIFxCounter = count($thisfile_png_chunk_type_text); - } - $thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk; - $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8); - $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3); - $thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11); - break; - - - case 'IDAT': // Image Data - $idatinformationfieldindex = 0; - if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) { - $idatinformationfieldindex = count($thisfile_png['IDAT']); - } - unset($chunk['data']); - $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk; - break; - - - case 'IEND': // Image Trailer - $thisfile_png_chunk_type_text['header'] = $chunk; - break; - - - default: - //unset($chunk['data']); - $thisfile_png_chunk_type_text['header'] = $chunk; - $info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text']; - break; - } - } - - return true; - } - - public function PNGsRGBintentLookup($sRGB) { - static $PNGsRGBintentLookup = array( - 0 => 'Perceptual', - 1 => 'Relative colorimetric', - 2 => 'Saturation', - 3 => 'Absolute colorimetric' - ); - return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid'); - } - - public function PNGcompressionMethodLookup($compressionmethod) { - static $PNGcompressionMethodLookup = array( - 0 => 'deflate/inflate' - ); - return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid'); - } - - public function PNGpHYsUnitLookup($unitid) { - static $PNGpHYsUnitLookup = array( - 0 => 'unknown', - 1 => 'meter' - ); - return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid'); - } - - public function PNGoFFsUnitLookup($unitid) { - static $PNGoFFsUnitLookup = array( - 0 => 'pixel', - 1 => 'micrometer' - ); - return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid'); - } - - public function PNGpCALequationTypeLookup($equationtype) { - static $PNGpCALequationTypeLookup = array( - 0 => 'Linear mapping', - 1 => 'Base-e exponential mapping', - 2 => 'Arbitrary-base exponential mapping', - 3 => 'Hyperbolic mapping' - ); - return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid'); - } - - public function PNGsCALUnitLookup($unitid) { - static $PNGsCALUnitLookup = array( - 0 => 'meter', - 1 => 'radian' - ); - return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid'); - } - - public function IHDRcalculateBitsPerSample($color_type, $bit_depth) { - switch ($color_type) { - case 0: // Each pixel is a grayscale sample. - return $bit_depth; - break; - - case 2: // Each pixel is an R,G,B triple - return 3 * $bit_depth; - break; - - case 3: // Each pixel is a palette index; a PLTE chunk must appear. - return $bit_depth; - break; - - case 4: // Each pixel is a grayscale sample, followed by an alpha sample. - return 2 * $bit_depth; - break; - - case 6: // Each pixel is an R,G,B triple, followed by an alpha sample. - return 4 * $bit_depth; - break; - } - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.png.php // +// module for analyzing PNG Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_png extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + // shortcut + $info['png'] = array(); + $thisfile_png = &$info['png']; + + $info['fileformat'] = 'png'; + $info['video']['dataformat'] = 'png'; + $info['video']['lossless'] = false; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $PNGfiledata = fread($this->getid3->fp, $this->getid3->fread_buffer_size()); + $offset = 0; + + $PNGidentifier = substr($PNGfiledata, $offset, 8); // $89 $50 $4E $47 $0D $0A $1A $0A + $offset += 8; + + if ($PNGidentifier != "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A") { + $info['error'][] = 'First 8 bytes of file ('.getid3_lib::PrintHexBytes($PNGidentifier).') did not match expected PNG identifier'; + unset($info['fileformat']); + return false; + } + + while (((ftell($this->getid3->fp) - (strlen($PNGfiledata) - $offset)) < $info['filesize'])) { + $chunk['data_length'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4)); + $offset += 4; + while (((strlen($PNGfiledata) - $offset) < ($chunk['data_length'] + 4)) && (ftell($this->getid3->fp) < $info['filesize'])) { + $PNGfiledata .= fread($this->getid3->fp, $this->getid3->fread_buffer_size()); + } + $chunk['type_text'] = substr($PNGfiledata, $offset, 4); + $offset += 4; + $chunk['type_raw'] = getid3_lib::BigEndian2Int($chunk['type_text']); + $chunk['data'] = substr($PNGfiledata, $offset, $chunk['data_length']); + $offset += $chunk['data_length']; + $chunk['crc'] = getid3_lib::BigEndian2Int(substr($PNGfiledata, $offset, 4)); + $offset += 4; + + $chunk['flags']['ancilliary'] = (bool) ($chunk['type_raw'] & 0x20000000); + $chunk['flags']['private'] = (bool) ($chunk['type_raw'] & 0x00200000); + $chunk['flags']['reserved'] = (bool) ($chunk['type_raw'] & 0x00002000); + $chunk['flags']['safe_to_copy'] = (bool) ($chunk['type_raw'] & 0x00000020); + + // shortcut + $thisfile_png[$chunk['type_text']] = array(); + $thisfile_png_chunk_type_text = &$thisfile_png[$chunk['type_text']]; + + switch ($chunk['type_text']) { + + case 'IHDR': // Image Header + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['width'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)); + $thisfile_png_chunk_type_text['height'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)); + $thisfile_png_chunk_type_text['raw']['bit_depth'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); + $thisfile_png_chunk_type_text['raw']['color_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 9, 1)); + $thisfile_png_chunk_type_text['raw']['compression_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 10, 1)); + $thisfile_png_chunk_type_text['raw']['filter_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 11, 1)); + $thisfile_png_chunk_type_text['raw']['interlace_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 1)); + + $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['raw']['compression_method']); + $thisfile_png_chunk_type_text['color_type']['palette'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x01); + $thisfile_png_chunk_type_text['color_type']['true_color'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x02); + $thisfile_png_chunk_type_text['color_type']['alpha'] = (bool) ($thisfile_png_chunk_type_text['raw']['color_type'] & 0x04); + + $info['video']['resolution_x'] = $thisfile_png_chunk_type_text['width']; + $info['video']['resolution_y'] = $thisfile_png_chunk_type_text['height']; + + $info['video']['bits_per_sample'] = $this->IHDRcalculateBitsPerSample($thisfile_png_chunk_type_text['raw']['color_type'], $thisfile_png_chunk_type_text['raw']['bit_depth']); + break; + + + case 'PLTE': // Palette + $thisfile_png_chunk_type_text['header'] = $chunk; + $paletteoffset = 0; + for ($i = 0; $i <= 255; $i++) { + //$thisfile_png_chunk_type_text['red'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + //$thisfile_png_chunk_type_text['green'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + //$thisfile_png_chunk_type_text['blue'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + $red = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + $green = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + $blue = getid3_lib::BigEndian2Int(substr($chunk['data'], $paletteoffset++, 1)); + $thisfile_png_chunk_type_text[$i] = (($red << 16) | ($green << 8) | ($blue)); + } + break; + + + case 'tRNS': // Transparency + $thisfile_png_chunk_type_text['header'] = $chunk; + switch ($thisfile_png['IHDR']['raw']['color_type']) { + case 0: + $thisfile_png_chunk_type_text['transparent_color_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); + break; + + case 2: + $thisfile_png_chunk_type_text['transparent_color_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); + $thisfile_png_chunk_type_text['transparent_color_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2)); + $thisfile_png_chunk_type_text['transparent_color_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 2)); + break; + + case 3: + for ($i = 0; $i < strlen($chunk['data']); $i++) { + $thisfile_png_chunk_type_text['palette_opacity'][$i] = getid3_lib::BigEndian2Int(substr($chunk['data'], $i, 1)); + } + break; + + case 4: + case 6: + $info['error'][] = 'Invalid color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']; + + default: + $info['warning'][] = 'Unhandled color_type in tRNS chunk: '.$thisfile_png['IHDR']['raw']['color_type']; + break; + } + break; + + + case 'gAMA': // Image Gamma + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['gamma'] = getid3_lib::BigEndian2Int($chunk['data']) / 100000; + break; + + + case 'cHRM': // Primary Chromaticities + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['white_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)) / 100000; + $thisfile_png_chunk_type_text['white_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)) / 100000; + $thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 4)) / 100000; + $thisfile_png_chunk_type_text['red_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 12, 4)) / 100000; + $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 16, 4)) / 100000; + $thisfile_png_chunk_type_text['green_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 20, 4)) / 100000; + $thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 24, 4)) / 100000; + $thisfile_png_chunk_type_text['blue_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 28, 4)) / 100000; + break; + + + case 'sRGB': // Standard RGB Color Space + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['reindering_intent'] = getid3_lib::BigEndian2Int($chunk['data']); + $thisfile_png_chunk_type_text['reindering_intent_text'] = $this->PNGsRGBintentLookup($thisfile_png_chunk_type_text['reindering_intent']); + break; + + + case 'iCCP': // Embedded ICC Profile + $thisfile_png_chunk_type_text['header'] = $chunk; + list($profilename, $compressiondata) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['profile_name'] = $profilename; + $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($compressiondata, 0, 1)); + $thisfile_png_chunk_type_text['compression_profile'] = substr($compressiondata, 1); + + $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); + break; + + + case 'tEXt': // Textual Data + $thisfile_png_chunk_type_text['header'] = $chunk; + list($keyword, $text) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['keyword'] = $keyword; + $thisfile_png_chunk_type_text['text'] = $text; + + $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; + break; + + + case 'zTXt': // Compressed Textual Data + $thisfile_png_chunk_type_text['header'] = $chunk; + list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['keyword'] = $keyword; + $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); + $thisfile_png_chunk_type_text['compressed_text'] = substr($otherdata, 1); + $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); + switch ($thisfile_png_chunk_type_text['compression_method']) { + case 0: + $thisfile_png_chunk_type_text['text'] = gzuncompress($thisfile_png_chunk_type_text['compressed_text']); + break; + + default: + // unknown compression method + break; + } + + if (isset($thisfile_png_chunk_type_text['text'])) { + $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; + } + break; + + + case 'iTXt': // International Textual Data + $thisfile_png_chunk_type_text['header'] = $chunk; + list($keyword, $otherdata) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['keyword'] = $keyword; + $thisfile_png_chunk_type_text['compression'] = (bool) getid3_lib::BigEndian2Int(substr($otherdata, 0, 1)); + $thisfile_png_chunk_type_text['compression_method'] = getid3_lib::BigEndian2Int(substr($otherdata, 1, 1)); + $thisfile_png_chunk_type_text['compression_method_text'] = $this->PNGcompressionMethodLookup($thisfile_png_chunk_type_text['compression_method']); + list($languagetag, $translatedkeyword, $text) = explode("\x00", substr($otherdata, 2), 3); + $thisfile_png_chunk_type_text['language_tag'] = $languagetag; + $thisfile_png_chunk_type_text['translated_keyword'] = $translatedkeyword; + + if ($thisfile_png_chunk_type_text['compression']) { + + switch ($thisfile_png_chunk_type_text['compression_method']) { + case 0: + $thisfile_png_chunk_type_text['text'] = gzuncompress($text); + break; + + default: + // unknown compression method + break; + } + + } else { + + $thisfile_png_chunk_type_text['text'] = $text; + + } + + if (isset($thisfile_png_chunk_type_text['text'])) { + $thisfile_png['comments'][$thisfile_png_chunk_type_text['keyword']][] = $thisfile_png_chunk_type_text['text']; + } + break; + + + case 'bKGD': // Background Color + $thisfile_png_chunk_type_text['header'] = $chunk; + switch ($thisfile_png['IHDR']['raw']['color_type']) { + case 0: + case 4: + $thisfile_png_chunk_type_text['background_gray'] = getid3_lib::BigEndian2Int($chunk['data']); + break; + + case 2: + case 6: + $thisfile_png_chunk_type_text['background_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); + $thisfile_png_chunk_type_text['background_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); + $thisfile_png_chunk_type_text['background_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2 * $thisfile_png['IHDR']['raw']['bit_depth'], $thisfile_png['IHDR']['raw']['bit_depth'])); + break; + + case 3: + $thisfile_png_chunk_type_text['background_index'] = getid3_lib::BigEndian2Int($chunk['data']); + break; + + default: + break; + } + break; + + + case 'pHYs': // Physical Pixel Dimensions + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['pixels_per_unit_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4)); + $thisfile_png_chunk_type_text['pixels_per_unit_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4)); + $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); + $thisfile_png_chunk_type_text['unit'] = $this->PNGpHYsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); + break; + + + case 'sBIT': // Significant Bits + $thisfile_png_chunk_type_text['header'] = $chunk; + switch ($thisfile_png['IHDR']['raw']['color_type']) { + case 0: + $thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + break; + + case 2: + case 3: + $thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); + $thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); + break; + + case 4: + $thisfile_png_chunk_type_text['significant_bits_gray'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); + break; + + case 6: + $thisfile_png_chunk_type_text['significant_bits_red'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + $thisfile_png_chunk_type_text['significant_bits_green'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); + $thisfile_png_chunk_type_text['significant_bits_blue'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); + $thisfile_png_chunk_type_text['significant_bits_alpha'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1)); + break; + + default: + break; + } + break; + + + case 'sPLT': // Suggested Palette + $thisfile_png_chunk_type_text['header'] = $chunk; + list($palettename, $otherdata) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['palette_name'] = $palettename; + $sPLToffset = 0; + $thisfile_png_chunk_type_text['sample_depth_bits'] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 1)); + $sPLToffset += 1; + $thisfile_png_chunk_type_text['sample_depth_bytes'] = $thisfile_png_chunk_type_text['sample_depth_bits'] / 8; + $paletteCounter = 0; + while ($sPLToffset < strlen($otherdata)) { + $thisfile_png_chunk_type_text['red'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); + $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; + $thisfile_png_chunk_type_text['green'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); + $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; + $thisfile_png_chunk_type_text['blue'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); + $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; + $thisfile_png_chunk_type_text['alpha'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, $thisfile_png_chunk_type_text['sample_depth_bytes'])); + $sPLToffset += $thisfile_png_chunk_type_text['sample_depth_bytes']; + $thisfile_png_chunk_type_text['frequency'][$paletteCounter] = getid3_lib::BigEndian2Int(substr($otherdata, $sPLToffset, 2)); + $sPLToffset += 2; + $paletteCounter++; + } + break; + + + case 'hIST': // Palette Histogram + $thisfile_png_chunk_type_text['header'] = $chunk; + $hISTcounter = 0; + while ($hISTcounter < strlen($chunk['data'])) { + $thisfile_png_chunk_type_text[$hISTcounter] = getid3_lib::BigEndian2Int(substr($chunk['data'], $hISTcounter / 2, 2)); + $hISTcounter += 2; + } + break; + + + case 'tIME': // Image Last-Modification Time + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['year'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 2)); + $thisfile_png_chunk_type_text['month'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 1)); + $thisfile_png_chunk_type_text['day'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 3, 1)); + $thisfile_png_chunk_type_text['hour'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 1)); + $thisfile_png_chunk_type_text['minute'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 5, 1)); + $thisfile_png_chunk_type_text['second'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 6, 1)); + $thisfile_png_chunk_type_text['unix'] = gmmktime($thisfile_png_chunk_type_text['hour'], $thisfile_png_chunk_type_text['minute'], $thisfile_png_chunk_type_text['second'], $thisfile_png_chunk_type_text['month'], $thisfile_png_chunk_type_text['day'], $thisfile_png_chunk_type_text['year']); + break; + + + case 'oFFs': // Image Offset + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['position_x'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 4), false, true); + $thisfile_png_chunk_type_text['position_y'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 4, 4), false, true); + $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 8, 1)); + $thisfile_png_chunk_type_text['unit'] = $this->PNGoFFsUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); + break; + + + case 'pCAL': // Calibration Of Pixel Values + $thisfile_png_chunk_type_text['header'] = $chunk; + list($calibrationname, $otherdata) = explode("\x00", $chunk['data'], 2); + $thisfile_png_chunk_type_text['calibration_name'] = $calibrationname; + $pCALoffset = 0; + $thisfile_png_chunk_type_text['original_zero'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true); + $pCALoffset += 4; + $thisfile_png_chunk_type_text['original_max'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 4), false, true); + $pCALoffset += 4; + $thisfile_png_chunk_type_text['equation_type'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1)); + $pCALoffset += 1; + $thisfile_png_chunk_type_text['equation_type_text'] = $this->PNGpCALequationTypeLookup($thisfile_png_chunk_type_text['equation_type']); + $thisfile_png_chunk_type_text['parameter_count'] = getid3_lib::BigEndian2Int(substr($chunk['data'], $pCALoffset, 1)); + $pCALoffset += 1; + $thisfile_png_chunk_type_text['parameters'] = explode("\x00", substr($chunk['data'], $pCALoffset)); + break; + + + case 'sCAL': // Physical Scale Of Image Subject + $thisfile_png_chunk_type_text['header'] = $chunk; + $thisfile_png_chunk_type_text['unit_specifier'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + $thisfile_png_chunk_type_text['unit'] = $this->PNGsCALUnitLookup($thisfile_png_chunk_type_text['unit_specifier']); + list($pixelwidth, $pixelheight) = explode("\x00", substr($chunk['data'], 1)); + $thisfile_png_chunk_type_text['pixel_width'] = $pixelwidth; + $thisfile_png_chunk_type_text['pixel_height'] = $pixelheight; + break; + + + case 'gIFg': // GIF Graphic Control Extension + $gIFgCounter = 0; + if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { + $gIFgCounter = count($thisfile_png_chunk_type_text); + } + $thisfile_png_chunk_type_text[$gIFgCounter]['header'] = $chunk; + $thisfile_png_chunk_type_text[$gIFgCounter]['disposal_method'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 0, 1)); + $thisfile_png_chunk_type_text[$gIFgCounter]['user_input_flag'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 1, 1)); + $thisfile_png_chunk_type_text[$gIFgCounter]['delay_time'] = getid3_lib::BigEndian2Int(substr($chunk['data'], 2, 2)); + break; + + + case 'gIFx': // GIF Application Extension + $gIFxCounter = 0; + if (isset($thisfile_png_chunk_type_text) && is_array($thisfile_png_chunk_type_text)) { + $gIFxCounter = count($thisfile_png_chunk_type_text); + } + $thisfile_png_chunk_type_text[$gIFxCounter]['header'] = $chunk; + $thisfile_png_chunk_type_text[$gIFxCounter]['application_identifier'] = substr($chunk['data'], 0, 8); + $thisfile_png_chunk_type_text[$gIFxCounter]['authentication_code'] = substr($chunk['data'], 8, 3); + $thisfile_png_chunk_type_text[$gIFxCounter]['application_data'] = substr($chunk['data'], 11); + break; + + + case 'IDAT': // Image Data + $idatinformationfieldindex = 0; + if (isset($thisfile_png['IDAT']) && is_array($thisfile_png['IDAT'])) { + $idatinformationfieldindex = count($thisfile_png['IDAT']); + } + unset($chunk['data']); + $thisfile_png_chunk_type_text[$idatinformationfieldindex]['header'] = $chunk; + break; + + + case 'IEND': // Image Trailer + $thisfile_png_chunk_type_text['header'] = $chunk; + break; + + + default: + //unset($chunk['data']); + $thisfile_png_chunk_type_text['header'] = $chunk; + $info['warning'][] = 'Unhandled chunk type: '.$chunk['type_text']; + break; + } + } + + return true; + } + + public function PNGsRGBintentLookup($sRGB) { + static $PNGsRGBintentLookup = array( + 0 => 'Perceptual', + 1 => 'Relative colorimetric', + 2 => 'Saturation', + 3 => 'Absolute colorimetric' + ); + return (isset($PNGsRGBintentLookup[$sRGB]) ? $PNGsRGBintentLookup[$sRGB] : 'invalid'); + } + + public function PNGcompressionMethodLookup($compressionmethod) { + static $PNGcompressionMethodLookup = array( + 0 => 'deflate/inflate' + ); + return (isset($PNGcompressionMethodLookup[$compressionmethod]) ? $PNGcompressionMethodLookup[$compressionmethod] : 'invalid'); + } + + public function PNGpHYsUnitLookup($unitid) { + static $PNGpHYsUnitLookup = array( + 0 => 'unknown', + 1 => 'meter' + ); + return (isset($PNGpHYsUnitLookup[$unitid]) ? $PNGpHYsUnitLookup[$unitid] : 'invalid'); + } + + public function PNGoFFsUnitLookup($unitid) { + static $PNGoFFsUnitLookup = array( + 0 => 'pixel', + 1 => 'micrometer' + ); + return (isset($PNGoFFsUnitLookup[$unitid]) ? $PNGoFFsUnitLookup[$unitid] : 'invalid'); + } + + public function PNGpCALequationTypeLookup($equationtype) { + static $PNGpCALequationTypeLookup = array( + 0 => 'Linear mapping', + 1 => 'Base-e exponential mapping', + 2 => 'Arbitrary-base exponential mapping', + 3 => 'Hyperbolic mapping' + ); + return (isset($PNGpCALequationTypeLookup[$equationtype]) ? $PNGpCALequationTypeLookup[$equationtype] : 'invalid'); + } + + public function PNGsCALUnitLookup($unitid) { + static $PNGsCALUnitLookup = array( + 0 => 'meter', + 1 => 'radian' + ); + return (isset($PNGsCALUnitLookup[$unitid]) ? $PNGsCALUnitLookup[$unitid] : 'invalid'); + } + + public function IHDRcalculateBitsPerSample($color_type, $bit_depth) { + switch ($color_type) { + case 0: // Each pixel is a grayscale sample. + return $bit_depth; + break; + + case 2: // Each pixel is an R,G,B triple + return 3 * $bit_depth; + break; + + case 3: // Each pixel is a palette index; a PLTE chunk must appear. + return $bit_depth; + break; + + case 4: // Each pixel is a grayscale sample, followed by an alpha sample. + return 2 * $bit_depth; + break; + + case 6: // Each pixel is an R,G,B triple, followed by an alpha sample. + return 4 * $bit_depth; + break; + } + return false; + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.svg.php b/app/libs/vendor/getid3/module.graphic.svg.php index 2973e095..8b31167e 100644 --- a/app/libs/vendor/getid3/module.graphic.svg.php +++ b/app/libs/vendor/getid3/module.graphic.svg.php @@ -1,101 +1,101 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.graphic.svg.php // -// module for analyzing SVG Image files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_svg extends getid3_handler -{ - - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - - $SVGheader = fread($this->getid3->fp, 4096); - if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) { - $info['svg']['xml']['raw'] = $matches; - } - if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) { - $info['svg']['doctype']['raw'] = $matches; - } - if (preg_match('#\]+)\>#i', $SVGheader, $matches)) { - $info['svg']['svg']['raw'] = $matches; - } - if (isset($info['svg']['svg']['raw'])) { - - $sections_to_fix = array('xml', 'doctype', 'svg'); - foreach ($sections_to_fix as $section_to_fix) { - if (!isset($info['svg'][$section_to_fix])) { - continue; - } - $section_data = array(); - while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { - $section_data[] = $matches[1]; - $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); - } - while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { - $section_data[] = $matches[0]; - $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); - } - $section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['svg'][$section_to_fix]['raw'][1])); - foreach ($section_data as $keyvaluepair) { - $keyvaluepair = trim($keyvaluepair); - if ($keyvaluepair) { - $keyvalueexploded = explode('=', $keyvaluepair); - $key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : ''); - $value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : ''); - $info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"'); - } - } - } - - $info['fileformat'] = 'svg'; - $info['video']['dataformat'] = 'svg'; - $info['video']['lossless'] = true; - //$info['video']['bits_per_sample'] = 24; - $info['video']['pixel_aspect_ratio'] = (float) 1; - - if (!empty($info['svg']['svg']['sections']['width'])) { - $info['svg']['width'] = intval($info['svg']['svg']['sections']['width']); - } - if (!empty($info['svg']['svg']['sections']['height'])) { - $info['svg']['height'] = intval($info['svg']['svg']['sections']['height']); - } - if (!empty($info['svg']['svg']['sections']['version'])) { - $info['svg']['version'] = $info['svg']['svg']['sections']['version']; - } - if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) { - foreach ($info['svg']['doctype']['sections'] as $key => $value) { - if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) { - $info['svg']['version'] = $matches[1]; - break; - } - } - } - - if (!empty($info['svg']['width'])) { - $info['video']['resolution_x'] = $info['svg']['width']; - } - if (!empty($info['svg']['height'])) { - $info['video']['resolution_y'] = $info['svg']['height']; - } - - return true; - } - $info['error'][] = 'Did not find expected tag'; - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.graphic.svg.php // +// module for analyzing SVG Image files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_svg extends getid3_handler +{ + + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + + $SVGheader = fread($this->getid3->fp, 4096); + if (preg_match('#\<\?xml([^\>]+)\?\>#i', $SVGheader, $matches)) { + $info['svg']['xml']['raw'] = $matches; + } + if (preg_match('#\<\!DOCTYPE([^\>]+)\>#i', $SVGheader, $matches)) { + $info['svg']['doctype']['raw'] = $matches; + } + if (preg_match('#\]+)\>#i', $SVGheader, $matches)) { + $info['svg']['svg']['raw'] = $matches; + } + if (isset($info['svg']['svg']['raw'])) { + + $sections_to_fix = array('xml', 'doctype', 'svg'); + foreach ($sections_to_fix as $section_to_fix) { + if (!isset($info['svg'][$section_to_fix])) { + continue; + } + $section_data = array(); + while (preg_match('/ "([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { + $section_data[] = $matches[1]; + $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); + } + while (preg_match('/([^\s]+)="([^"]+)"/', $info['svg'][$section_to_fix]['raw'][1], $matches)) { + $section_data[] = $matches[0]; + $info['svg'][$section_to_fix]['raw'][1] = str_replace($matches[0], '', $info['svg'][$section_to_fix]['raw'][1]); + } + $section_data = array_merge($section_data, preg_split('/[\s,]+/', $info['svg'][$section_to_fix]['raw'][1])); + foreach ($section_data as $keyvaluepair) { + $keyvaluepair = trim($keyvaluepair); + if ($keyvaluepair) { + $keyvalueexploded = explode('=', $keyvaluepair); + $key = (isset($keyvalueexploded[0]) ? $keyvalueexploded[0] : ''); + $value = (isset($keyvalueexploded[1]) ? $keyvalueexploded[1] : ''); + $info['svg'][$section_to_fix]['sections'][$key] = trim($value, '"'); + } + } + } + + $info['fileformat'] = 'svg'; + $info['video']['dataformat'] = 'svg'; + $info['video']['lossless'] = true; + //$info['video']['bits_per_sample'] = 24; + $info['video']['pixel_aspect_ratio'] = (float) 1; + + if (!empty($info['svg']['svg']['sections']['width'])) { + $info['svg']['width'] = intval($info['svg']['svg']['sections']['width']); + } + if (!empty($info['svg']['svg']['sections']['height'])) { + $info['svg']['height'] = intval($info['svg']['svg']['sections']['height']); + } + if (!empty($info['svg']['svg']['sections']['version'])) { + $info['svg']['version'] = $info['svg']['svg']['sections']['version']; + } + if (!isset($info['svg']['version']) && isset($info['svg']['doctype']['sections'])) { + foreach ($info['svg']['doctype']['sections'] as $key => $value) { + if (preg_match('#//W3C//DTD SVG ([0-9\.]+)//#i', $key, $matches)) { + $info['svg']['version'] = $matches[1]; + break; + } + } + } + + if (!empty($info['svg']['width'])) { + $info['video']['resolution_x'] = $info['svg']['width']; + } + if (!empty($info['svg']['height'])) { + $info['video']['resolution_y'] = $info['svg']['height']; + } + + return true; + } + $info['error'][] = 'Did not find expected tag'; + return false; + } + +} diff --git a/app/libs/vendor/getid3/module.graphic.tiff.php b/app/libs/vendor/getid3/module.graphic.tiff.php index 3a2962ba..25996f0e 100644 --- a/app/libs/vendor/getid3/module.graphic.tiff.php +++ b/app/libs/vendor/getid3/module.graphic.tiff.php @@ -1,224 +1,224 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.archive.tiff.php // -// module for analyzing TIFF files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_tiff extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $TIFFheader = fread($this->getid3->fp, 4); - - switch (substr($TIFFheader, 0, 2)) { - case 'II': - $info['tiff']['byte_order'] = 'Intel'; - break; - case 'MM': - $info['tiff']['byte_order'] = 'Motorola'; - break; - default: - $info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']; - return false; - break; - } - - $info['fileformat'] = 'tiff'; - $info['video']['dataformat'] = 'tiff'; - $info['video']['lossless'] = true; - $info['tiff']['ifd'] = array(); - $CurrentIFD = array(); - - $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8); - - $nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); - - while ($nextIFDoffset > 0) { - - $CurrentIFD['offset'] = $nextIFDoffset; - - fseek($this->getid3->fp, $info['avdataoffset'] + $nextIFDoffset, SEEK_SET); - $CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); - - for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) { - $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); - $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); - $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); - $CurrentIFD['fields'][$i]['raw']['offset'] = fread($this->getid3->fp, 4); - - switch ($CurrentIFD['fields'][$i]['raw']['type']) { - case 1: // BYTE An 8-bit unsigned integer. - if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) { - $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']); - } else { - $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); - } - break; - - case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null. - if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) { - $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3); - } else { - $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); - } - break; - - case 3: // SHORT A 16-bit (2-byte) unsigned integer. - if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) { - $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']); - } else { - $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); - } - break; - - case 4: // LONG A 32-bit (4-byte) unsigned integer. - if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) { - $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); - } else { - $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); - } - break; - - case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator. - break; - } - } - - $info['tiff']['ifd'][] = $CurrentIFD; - $CurrentIFD = array(); - $nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); - - } - - foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) { - foreach ($IFDarray['fields'] as $key => $fieldarray) { - switch ($fieldarray['raw']['tag']) { - case 256: // ImageWidth - case 257: // ImageLength - case 258: // BitsPerSample - case 259: // Compression - if (!isset($fieldarray['value'])) { - fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET); - $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]); - - } - break; - - case 270: // ImageDescription - case 271: // Make - case 272: // Model - case 305: // Software - case 306: // DateTime - case 315: // Artist - case 316: // HostComputer - if (isset($fieldarray['value'])) { - $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value']; - } else { - fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET); - $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]); - - } - break; - } - switch ($fieldarray['raw']['tag']) { - case 256: // ImageWidth - $info['video']['resolution_x'] = $fieldarray['value']; - break; - - case 257: // ImageLength - $info['video']['resolution_y'] = $fieldarray['value']; - break; - - case 258: // BitsPerSample - if (isset($fieldarray['value'])) { - $info['video']['bits_per_sample'] = $fieldarray['value']; - } else { - $info['video']['bits_per_sample'] = 0; - for ($i = 0; $i < $fieldarray['raw']['length']; $i++) { - $info['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $info['tiff']['byte_order']); - } - } - break; - - case 259: // Compression - $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']); - break; - - case 270: // ImageDescription - case 271: // Make - case 272: // Model - case 305: // Software - case 306: // DateTime - case 315: // Artist - case 316: // HostComputer - $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']); - if (isset($info['tiff']['comments'][$TIFFcommentName])) { - $info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']; - } else { - $info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']); - } - break; - - default: - break; - } - } - } - - return true; - } - - - public function TIFFendian2Int($bytestring, $byteorder) { - if ($byteorder == 'Intel') { - return getid3_lib::LittleEndian2Int($bytestring); - } elseif ($byteorder == 'Motorola') { - return getid3_lib::BigEndian2Int($bytestring); - } - return false; - } - - public function TIFFcompressionMethod($id) { - static $TIFFcompressionMethod = array(); - if (empty($TIFFcompressionMethod)) { - $TIFFcompressionMethod = array( - 1 => 'Uncompressed', - 2 => 'Huffman', - 3 => 'Fax - CCITT 3', - 5 => 'LZW', - 32773 => 'PackBits', - ); - } - return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')'); - } - - public function TIFFcommentName($id) { - static $TIFFcommentName = array(); - if (empty($TIFFcommentName)) { - $TIFFcommentName = array( - 270 => 'imagedescription', - 271 => 'make', - 272 => 'model', - 305 => 'software', - 306 => 'datetime', - 315 => 'artist', - 316 => 'hostcomputer', - ); - } - return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')'); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.archive.tiff.php // +// module for analyzing TIFF files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_tiff extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $TIFFheader = fread($this->getid3->fp, 4); + + switch (substr($TIFFheader, 0, 2)) { + case 'II': + $info['tiff']['byte_order'] = 'Intel'; + break; + case 'MM': + $info['tiff']['byte_order'] = 'Motorola'; + break; + default: + $info['error'][] = 'Invalid TIFF byte order identifier ('.substr($TIFFheader, 0, 2).') at offset '.$info['avdataoffset']; + return false; + break; + } + + $info['fileformat'] = 'tiff'; + $info['video']['dataformat'] = 'tiff'; + $info['video']['lossless'] = true; + $info['tiff']['ifd'] = array(); + $CurrentIFD = array(); + + $FieldTypeByteLength = array(1=>1, 2=>1, 3=>2, 4=>4, 5=>8); + + $nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); + + while ($nextIFDoffset > 0) { + + $CurrentIFD['offset'] = $nextIFDoffset; + + fseek($this->getid3->fp, $info['avdataoffset'] + $nextIFDoffset, SEEK_SET); + $CurrentIFD['fieldcount'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); + + for ($i = 0; $i < $CurrentIFD['fieldcount']; $i++) { + $CurrentIFD['fields'][$i]['raw']['tag'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); + $CurrentIFD['fields'][$i]['raw']['type'] = $this->TIFFendian2Int(fread($this->getid3->fp, 2), $info['tiff']['byte_order']); + $CurrentIFD['fields'][$i]['raw']['length'] = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); + $CurrentIFD['fields'][$i]['raw']['offset'] = fread($this->getid3->fp, 4); + + switch ($CurrentIFD['fields'][$i]['raw']['type']) { + case 1: // BYTE An 8-bit unsigned integer. + if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) { + $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 1), $info['tiff']['byte_order']); + } else { + $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); + } + break; + + case 2: // ASCII 8-bit bytes that store ASCII codes; the last byte must be null. + if ($CurrentIFD['fields'][$i]['raw']['length'] <= 4) { + $CurrentIFD['fields'][$i]['value'] = substr($CurrentIFD['fields'][$i]['raw']['offset'], 3); + } else { + $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); + } + break; + + case 3: // SHORT A 16-bit (2-byte) unsigned integer. + if ($CurrentIFD['fields'][$i]['raw']['length'] <= 2) { + $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int(substr($CurrentIFD['fields'][$i]['raw']['offset'], 0, 2), $info['tiff']['byte_order']); + } else { + $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); + } + break; + + case 4: // LONG A 32-bit (4-byte) unsigned integer. + if ($CurrentIFD['fields'][$i]['raw']['length'] <= 1) { + $CurrentIFD['fields'][$i]['value'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); + } else { + $CurrentIFD['fields'][$i]['offset'] = $this->TIFFendian2Int($CurrentIFD['fields'][$i]['raw']['offset'], $info['tiff']['byte_order']); + } + break; + + case 5: // RATIONAL Two LONG_s: the first represents the numerator of a fraction, the second the denominator. + break; + } + } + + $info['tiff']['ifd'][] = $CurrentIFD; + $CurrentIFD = array(); + $nextIFDoffset = $this->TIFFendian2Int(fread($this->getid3->fp, 4), $info['tiff']['byte_order']); + + } + + foreach ($info['tiff']['ifd'] as $IFDid => $IFDarray) { + foreach ($IFDarray['fields'] as $key => $fieldarray) { + switch ($fieldarray['raw']['tag']) { + case 256: // ImageWidth + case 257: // ImageLength + case 258: // BitsPerSample + case 259: // Compression + if (!isset($fieldarray['value'])) { + fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET); + $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]); + + } + break; + + case 270: // ImageDescription + case 271: // Make + case 272: // Model + case 305: // Software + case 306: // DateTime + case 315: // Artist + case 316: // HostComputer + if (isset($fieldarray['value'])) { + $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = $fieldarray['value']; + } else { + fseek($this->getid3->fp, $fieldarray['offset'], SEEK_SET); + $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'] = fread($this->getid3->fp, $fieldarray['raw']['length'] * $FieldTypeByteLength[$fieldarray['raw']['type']]); + + } + break; + } + switch ($fieldarray['raw']['tag']) { + case 256: // ImageWidth + $info['video']['resolution_x'] = $fieldarray['value']; + break; + + case 257: // ImageLength + $info['video']['resolution_y'] = $fieldarray['value']; + break; + + case 258: // BitsPerSample + if (isset($fieldarray['value'])) { + $info['video']['bits_per_sample'] = $fieldarray['value']; + } else { + $info['video']['bits_per_sample'] = 0; + for ($i = 0; $i < $fieldarray['raw']['length']; $i++) { + $info['video']['bits_per_sample'] += $this->TIFFendian2Int(substr($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data'], $i * $FieldTypeByteLength[$fieldarray['raw']['type']], $FieldTypeByteLength[$fieldarray['raw']['type']]), $info['tiff']['byte_order']); + } + } + break; + + case 259: // Compression + $info['video']['codec'] = $this->TIFFcompressionMethod($fieldarray['value']); + break; + + case 270: // ImageDescription + case 271: // Make + case 272: // Model + case 305: // Software + case 306: // DateTime + case 315: // Artist + case 316: // HostComputer + $TIFFcommentName = $this->TIFFcommentName($fieldarray['raw']['tag']); + if (isset($info['tiff']['comments'][$TIFFcommentName])) { + $info['tiff']['comments'][$TIFFcommentName][] = $info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']; + } else { + $info['tiff']['comments'][$TIFFcommentName] = array($info['tiff']['ifd'][$IFDid]['fields'][$key]['raw']['data']); + } + break; + + default: + break; + } + } + } + + return true; + } + + + public function TIFFendian2Int($bytestring, $byteorder) { + if ($byteorder == 'Intel') { + return getid3_lib::LittleEndian2Int($bytestring); + } elseif ($byteorder == 'Motorola') { + return getid3_lib::BigEndian2Int($bytestring); + } + return false; + } + + public function TIFFcompressionMethod($id) { + static $TIFFcompressionMethod = array(); + if (empty($TIFFcompressionMethod)) { + $TIFFcompressionMethod = array( + 1 => 'Uncompressed', + 2 => 'Huffman', + 3 => 'Fax - CCITT 3', + 5 => 'LZW', + 32773 => 'PackBits', + ); + } + return (isset($TIFFcompressionMethod[$id]) ? $TIFFcompressionMethod[$id] : 'unknown/invalid ('.$id.')'); + } + + public function TIFFcommentName($id) { + static $TIFFcommentName = array(); + if (empty($TIFFcommentName)) { + $TIFFcommentName = array( + 270 => 'imagedescription', + 271 => 'make', + 272 => 'model', + 305 => 'software', + 306 => 'datetime', + 315 => 'artist', + 316 => 'hostcomputer', + ); + } + return (isset($TIFFcommentName[$id]) ? $TIFFcommentName[$id] : 'unknown/invalid ('.$id.')'); + } + +} diff --git a/app/libs/vendor/getid3/module.misc.cue.php b/app/libs/vendor/getid3/module.misc.cue.php index 9cdb3368..a4536289 100644 --- a/app/libs/vendor/getid3/module.misc.cue.php +++ b/app/libs/vendor/getid3/module.misc.cue.php @@ -1,311 +1,311 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.cue.php // -// module for analyzing CUEsheet files // -// dependencies: NONE // -// // -///////////////////////////////////////////////////////////////// -// // -// Module originally written [2009-Mar-25] by // -// Nigel Barnes // -// Minor reformatting and similar small changes to integrate // -// into getID3 by James Heinrich // -// /// -///////////////////////////////////////////////////////////////// - -/* - * CueSheet parser by Nigel Barnes. - * - * This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp) - */ - -/** - * A CueSheet class used to open and parse cuesheets. - * - */ -class getid3_cue extends getid3_handler -{ - public $cuesheet = array(); - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'cue'; - $this->readCueSheetFilename($info['filenamepath']); - $info['cue'] = $this->cuesheet; - return true; - } - - - - public function readCueSheetFilename($filename) - { - $filedata = file_get_contents($filename); - return $this->readCueSheet($filedata); - } - /** - * Parses a cue sheet file. - * - * @param string $filename - The filename for the cue sheet to open. - */ - public function readCueSheet(&$filedata) - { - $cue_lines = array(); - foreach (explode("\n", str_replace("\r", null, $filedata)) as $line) - { - if ( (strlen($line) > 0) && ($line[0] != '#')) - { - $cue_lines[] = trim($line); - } - } - $this->parseCueSheet($cue_lines); - - return $this->cuesheet; - } - - /** - * Parses the cue sheet array. - * - * @param array $file - The cuesheet as an array of each line. - */ - public function parseCueSheet($file) - { - //-1 means still global, all others are track specific - $track_on = -1; - - for ($i=0; $i < count($file); $i++) - { - list($key) = explode(' ', strtolower($file[$i]), 2); - switch ($key) - { - case 'catalog': - case 'cdtextfile': - case 'isrc': - case 'performer': - case 'songwriter': - case 'title': - $this->parseString($file[$i], $track_on); - break; - case 'file': - $currentFile = $this->parseFile($file[$i]); - break; - case 'flags': - $this->parseFlags($file[$i], $track_on); - break; - case 'index': - case 'postgap': - case 'pregap': - $this->parseIndex($file[$i], $track_on); - break; - case 'rem': - $this->parseComment($file[$i], $track_on); - break; - case 'track': - $track_on++; - $this->parseTrack($file[$i], $track_on); - if (isset($currentFile)) // if there's a file - { - $this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile; - } - break; - default: - //save discarded junk and place string[] with track it was found in - $this->parseGarbage($file[$i], $track_on); - break; - } - } - } - - /** - * Parses the REM command. - * - * @param string $line - The line in the cue file that contains the TRACK command. - * @param integer $track_on - The track currently processing. - */ - public function parseComment($line, $track_on) - { - $explodedline = explode(' ', $line, 3); - $comment_REM = (isset($explodedline[0]) ? $explodedline[0] : ''); - $comment_type = (isset($explodedline[1]) ? $explodedline[1] : ''); - $comment_data = (isset($explodedline[2]) ? $explodedline[2] : ''); - if (($comment_REM == 'REM') && $comment_type) { - $comment_type = strtolower($comment_type); - $commment_data = trim($comment_data, ' "'); - if ($track_on != -1) { - $this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data; - } else { - $this->cuesheet['comments'][$comment_type][] = $comment_data; - } - } - } - - /** - * Parses the FILE command. - * - * @param string $line - The line in the cue file that contains the FILE command. - * @return array - Array of FILENAME and TYPE of file.. - */ - public function parseFile($line) - { - $line = substr($line, strpos($line, ' ') + 1); - $type = strtolower(substr($line, strrpos($line, ' '))); - - //remove type - $line = substr($line, 0, strrpos($line, ' ') - 1); - - //if quotes around it, remove them. - $line = trim($line, '"'); - - return array('filename'=>$line, 'type'=>$type); - } - - /** - * Parses the FLAG command. - * - * @param string $line - The line in the cue file that contains the TRACK command. - * @param integer $track_on - The track currently processing. - */ - public function parseFlags($line, $track_on) - { - if ($track_on != -1) - { - foreach (explode(' ', strtolower($line)) as $type) - { - switch ($type) - { - case 'flags': - // first entry in this line - $this->cuesheet['tracks'][$track_on]['flags'] = array( - '4ch' => false, - 'data' => false, - 'dcp' => false, - 'pre' => false, - 'scms' => false, - ); - break; - case 'data': - case 'dcp': - case '4ch': - case 'pre': - case 'scms': - $this->cuesheet['tracks'][$track_on]['flags'][$type] = true; - break; - default: - break; - } - } - } - } - - /** - * Collect any unidentified data. - * - * @param string $line - The line in the cue file that contains the TRACK command. - * @param integer $track_on - The track currently processing. - */ - public function parseGarbage($line, $track_on) - { - if ( strlen($line) > 0 ) - { - if ($track_on == -1) - { - $this->cuesheet['garbage'][] = $line; - } - else - { - $this->cuesheet['tracks'][$track_on]['garbage'][] = $line; - } - } - } - - /** - * Parses the INDEX command of a TRACK. - * - * @param string $line - The line in the cue file that contains the TRACK command. - * @param integer $track_on - The track currently processing. - */ - public function parseIndex($line, $track_on) - { - $type = strtolower(substr($line, 0, strpos($line, ' '))); - $line = substr($line, strpos($line, ' ') + 1); - - if ($type == 'index') - { - //read the index number - $number = intval(substr($line, 0, strpos($line, ' '))); - $line = substr($line, strpos($line, ' ') + 1); - } - - //extract the minutes, seconds, and frames - $explodedline = explode(':', $line); - $minutes = (isset($explodedline[0]) ? $explodedline[0] : ''); - $seconds = (isset($explodedline[1]) ? $explodedline[1] : ''); - $frames = (isset($explodedline[2]) ? $explodedline[2] : ''); - - switch ($type) { - case 'index': - $this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); - break; - case 'pregap': - case 'postgap': - $this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); - break; - } - } - - public function parseString($line, $track_on) - { - $category = strtolower(substr($line, 0, strpos($line, ' '))); - $line = substr($line, strpos($line, ' ') + 1); - - //get rid of the quotes - $line = trim($line, '"'); - - switch ($category) - { - case 'catalog': - case 'cdtextfile': - case 'isrc': - case 'performer': - case 'songwriter': - case 'title': - if ($track_on == -1) - { - $this->cuesheet[$category] = $line; - } - else - { - $this->cuesheet['tracks'][$track_on][$category] = $line; - } - break; - default: - break; - } - } - - /** - * Parses the TRACK command. - * - * @param string $line - The line in the cue file that contains the TRACK command. - * @param integer $track_on - The track currently processing. - */ - public function parseTrack($line, $track_on) - { - $line = substr($line, strpos($line, ' ') + 1); - $track = ltrim(substr($line, 0, strpos($line, ' ')), '0'); - - //find the data type. - $datatype = strtolower(substr($line, strpos($line, ' ') + 1)); - - $this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype); - } - -} - + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.cue.php // +// module for analyzing CUEsheet files // +// dependencies: NONE // +// // +///////////////////////////////////////////////////////////////// +// // +// Module originally written [2009-Mar-25] by // +// Nigel Barnes // +// Minor reformatting and similar small changes to integrate // +// into getID3 by James Heinrich // +// /// +///////////////////////////////////////////////////////////////// + +/* + * CueSheet parser by Nigel Barnes. + * + * This is a PHP conversion of CueSharp 0.5 by Wyatt O'Day (wyday.com/cuesharp) + */ + +/** + * A CueSheet class used to open and parse cuesheets. + * + */ +class getid3_cue extends getid3_handler +{ + public $cuesheet = array(); + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'cue'; + $this->readCueSheetFilename($info['filenamepath']); + $info['cue'] = $this->cuesheet; + return true; + } + + + + public function readCueSheetFilename($filename) + { + $filedata = file_get_contents($filename); + return $this->readCueSheet($filedata); + } + /** + * Parses a cue sheet file. + * + * @param string $filename - The filename for the cue sheet to open. + */ + public function readCueSheet(&$filedata) + { + $cue_lines = array(); + foreach (explode("\n", str_replace("\r", null, $filedata)) as $line) + { + if ( (strlen($line) > 0) && ($line[0] != '#')) + { + $cue_lines[] = trim($line); + } + } + $this->parseCueSheet($cue_lines); + + return $this->cuesheet; + } + + /** + * Parses the cue sheet array. + * + * @param array $file - The cuesheet as an array of each line. + */ + public function parseCueSheet($file) + { + //-1 means still global, all others are track specific + $track_on = -1; + + for ($i=0; $i < count($file); $i++) + { + list($key) = explode(' ', strtolower($file[$i]), 2); + switch ($key) + { + case 'catalog': + case 'cdtextfile': + case 'isrc': + case 'performer': + case 'songwriter': + case 'title': + $this->parseString($file[$i], $track_on); + break; + case 'file': + $currentFile = $this->parseFile($file[$i]); + break; + case 'flags': + $this->parseFlags($file[$i], $track_on); + break; + case 'index': + case 'postgap': + case 'pregap': + $this->parseIndex($file[$i], $track_on); + break; + case 'rem': + $this->parseComment($file[$i], $track_on); + break; + case 'track': + $track_on++; + $this->parseTrack($file[$i], $track_on); + if (isset($currentFile)) // if there's a file + { + $this->cuesheet['tracks'][$track_on]['datafile'] = $currentFile; + } + break; + default: + //save discarded junk and place string[] with track it was found in + $this->parseGarbage($file[$i], $track_on); + break; + } + } + } + + /** + * Parses the REM command. + * + * @param string $line - The line in the cue file that contains the TRACK command. + * @param integer $track_on - The track currently processing. + */ + public function parseComment($line, $track_on) + { + $explodedline = explode(' ', $line, 3); + $comment_REM = (isset($explodedline[0]) ? $explodedline[0] : ''); + $comment_type = (isset($explodedline[1]) ? $explodedline[1] : ''); + $comment_data = (isset($explodedline[2]) ? $explodedline[2] : ''); + if (($comment_REM == 'REM') && $comment_type) { + $comment_type = strtolower($comment_type); + $commment_data = trim($comment_data, ' "'); + if ($track_on != -1) { + $this->cuesheet['tracks'][$track_on]['comments'][$comment_type][] = $comment_data; + } else { + $this->cuesheet['comments'][$comment_type][] = $comment_data; + } + } + } + + /** + * Parses the FILE command. + * + * @param string $line - The line in the cue file that contains the FILE command. + * @return array - Array of FILENAME and TYPE of file.. + */ + public function parseFile($line) + { + $line = substr($line, strpos($line, ' ') + 1); + $type = strtolower(substr($line, strrpos($line, ' '))); + + //remove type + $line = substr($line, 0, strrpos($line, ' ') - 1); + + //if quotes around it, remove them. + $line = trim($line, '"'); + + return array('filename'=>$line, 'type'=>$type); + } + + /** + * Parses the FLAG command. + * + * @param string $line - The line in the cue file that contains the TRACK command. + * @param integer $track_on - The track currently processing. + */ + public function parseFlags($line, $track_on) + { + if ($track_on != -1) + { + foreach (explode(' ', strtolower($line)) as $type) + { + switch ($type) + { + case 'flags': + // first entry in this line + $this->cuesheet['tracks'][$track_on]['flags'] = array( + '4ch' => false, + 'data' => false, + 'dcp' => false, + 'pre' => false, + 'scms' => false, + ); + break; + case 'data': + case 'dcp': + case '4ch': + case 'pre': + case 'scms': + $this->cuesheet['tracks'][$track_on]['flags'][$type] = true; + break; + default: + break; + } + } + } + } + + /** + * Collect any unidentified data. + * + * @param string $line - The line in the cue file that contains the TRACK command. + * @param integer $track_on - The track currently processing. + */ + public function parseGarbage($line, $track_on) + { + if ( strlen($line) > 0 ) + { + if ($track_on == -1) + { + $this->cuesheet['garbage'][] = $line; + } + else + { + $this->cuesheet['tracks'][$track_on]['garbage'][] = $line; + } + } + } + + /** + * Parses the INDEX command of a TRACK. + * + * @param string $line - The line in the cue file that contains the TRACK command. + * @param integer $track_on - The track currently processing. + */ + public function parseIndex($line, $track_on) + { + $type = strtolower(substr($line, 0, strpos($line, ' '))); + $line = substr($line, strpos($line, ' ') + 1); + + if ($type == 'index') + { + //read the index number + $number = intval(substr($line, 0, strpos($line, ' '))); + $line = substr($line, strpos($line, ' ') + 1); + } + + //extract the minutes, seconds, and frames + $explodedline = explode(':', $line); + $minutes = (isset($explodedline[0]) ? $explodedline[0] : ''); + $seconds = (isset($explodedline[1]) ? $explodedline[1] : ''); + $frames = (isset($explodedline[2]) ? $explodedline[2] : ''); + + switch ($type) { + case 'index': + $this->cuesheet['tracks'][$track_on][$type][$number] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); + break; + case 'pregap': + case 'postgap': + $this->cuesheet['tracks'][$track_on][$type] = array('minutes'=>intval($minutes), 'seconds'=>intval($seconds), 'frames'=>intval($frames)); + break; + } + } + + public function parseString($line, $track_on) + { + $category = strtolower(substr($line, 0, strpos($line, ' '))); + $line = substr($line, strpos($line, ' ') + 1); + + //get rid of the quotes + $line = trim($line, '"'); + + switch ($category) + { + case 'catalog': + case 'cdtextfile': + case 'isrc': + case 'performer': + case 'songwriter': + case 'title': + if ($track_on == -1) + { + $this->cuesheet[$category] = $line; + } + else + { + $this->cuesheet['tracks'][$track_on][$category] = $line; + } + break; + default: + break; + } + } + + /** + * Parses the TRACK command. + * + * @param string $line - The line in the cue file that contains the TRACK command. + * @param integer $track_on - The track currently processing. + */ + public function parseTrack($line, $track_on) + { + $line = substr($line, strpos($line, ' ') + 1); + $track = ltrim(substr($line, 0, strpos($line, ' ')), '0'); + + //find the data type. + $datatype = strtolower(substr($line, strpos($line, ' ') + 1)); + + $this->cuesheet['tracks'][$track_on] = array('track_number'=>$track, 'datatype'=>$datatype); + } + +} + diff --git a/app/libs/vendor/getid3/module.misc.exe.php b/app/libs/vendor/getid3/module.misc.exe.php index d5cfefd7..15e786b4 100644 --- a/app/libs/vendor/getid3/module.misc.exe.php +++ b/app/libs/vendor/getid3/module.misc.exe.php @@ -1,58 +1,58 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.exe.php // -// module for analyzing EXE files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_exe extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $EXEheader = fread($this->getid3->fp, 28); - - $magic = 'MZ'; - if (substr($EXEheader, 0, 2) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"'; - return false; - } - - $info['fileformat'] = 'exe'; - $info['exe']['mz']['magic'] = 'MZ'; - - $info['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2)); - $info['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2)); - $info['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2)); - $info['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2)); - $info['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2)); - $info['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2)); - $info['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2)); - $info['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2)); - $info['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2)); - $info['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4)); - $info['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2)); - $info['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2)); - - $info['exe']['mz']['byte_size'] = (($info['exe']['mz']['raw']['page_count'] - 1)) * 512 + $info['exe']['mz']['raw']['last_page_size']; - $info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16; - $info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16; - $info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16; - -$info['error'][] = 'EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.exe.php // +// module for analyzing EXE files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_exe extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $EXEheader = fread($this->getid3->fp, 28); + + $magic = 'MZ'; + if (substr($EXEheader, 0, 2) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at offset '.$info['avdataoffset'].', found "'.getid3_lib::PrintHexBytes(substr($EXEheader, 0, 2)).'"'; + return false; + } + + $info['fileformat'] = 'exe'; + $info['exe']['mz']['magic'] = 'MZ'; + + $info['exe']['mz']['raw']['last_page_size'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 2, 2)); + $info['exe']['mz']['raw']['page_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 4, 2)); + $info['exe']['mz']['raw']['relocation_count'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 6, 2)); + $info['exe']['mz']['raw']['header_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 8, 2)); + $info['exe']['mz']['raw']['min_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 10, 2)); + $info['exe']['mz']['raw']['max_memory_paragraphs'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 12, 2)); + $info['exe']['mz']['raw']['initial_ss'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 14, 2)); + $info['exe']['mz']['raw']['initial_sp'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 16, 2)); + $info['exe']['mz']['raw']['checksum'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 18, 2)); + $info['exe']['mz']['raw']['cs_ip'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 20, 4)); + $info['exe']['mz']['raw']['relocation_table_offset'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 24, 2)); + $info['exe']['mz']['raw']['overlay_number'] = getid3_lib::LittleEndian2Int(substr($EXEheader, 26, 2)); + + $info['exe']['mz']['byte_size'] = (($info['exe']['mz']['raw']['page_count'] - 1)) * 512 + $info['exe']['mz']['raw']['last_page_size']; + $info['exe']['mz']['header_size'] = $info['exe']['mz']['raw']['header_paragraphs'] * 16; + $info['exe']['mz']['memory_minimum'] = $info['exe']['mz']['raw']['min_memory_paragraphs'] * 16; + $info['exe']['mz']['memory_recommended'] = $info['exe']['mz']['raw']['max_memory_paragraphs'] * 16; + +$info['error'][] = 'EXE parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + + } + +} diff --git a/app/libs/vendor/getid3/module.misc.iso.php b/app/libs/vendor/getid3/module.misc.iso.php index 80b300ea..39bd16af 100644 --- a/app/libs/vendor/getid3/module.misc.iso.php +++ b/app/libs/vendor/getid3/module.misc.iso.php @@ -1,387 +1,387 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.iso.php // -// module for analyzing ISO files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_iso extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'iso'; - - for ($i = 16; $i <= 19; $i++) { - fseek($this->getid3->fp, 2048 * $i, SEEK_SET); - $ISOheader = fread($this->getid3->fp, 2048); - if (substr($ISOheader, 1, 5) == 'CD001') { - switch (ord($ISOheader{0})) { - case 1: - $info['iso']['primary_volume_descriptor']['offset'] = 2048 * $i; - $this->ParsePrimaryVolumeDescriptor($ISOheader); - break; - - case 2: - $info['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i; - $this->ParseSupplementaryVolumeDescriptor($ISOheader); - break; - - default: - // skip - break; - } - } - } - - $this->ParsePathTable(); - - $info['iso']['files'] = array(); - foreach ($info['iso']['path_table']['directories'] as $directorynum => $directorydata) { - $info['iso']['directories'][$directorynum] = $this->ParseDirectoryRecord($directorydata); - } - - return true; - } - - - public function ParsePrimaryVolumeDescriptor(&$ISOheader) { - // ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!! - // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field - - // shortcuts - $info = &$this->getid3->info; - $info['iso']['primary_volume_descriptor']['raw'] = array(); - $thisfile_iso_primaryVD = &$info['iso']['primary_volume_descriptor']; - $thisfile_iso_primaryVD_raw = &$thisfile_iso_primaryVD['raw']; - - $thisfile_iso_primaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1)); - $thisfile_iso_primaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5); - if ($thisfile_iso_primaryVD_raw['standard_identifier'] != 'CD001') { - $info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_primaryVD['offset'] + 1).'), found "'.$thisfile_iso_primaryVD_raw['standard_identifier'].'" instead'; - unset($info['fileformat']); - unset($info['iso']); - return false; - } - - - $thisfile_iso_primaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1)); - //$thisfile_iso_primaryVD_raw['unused_1'] = substr($ISOheader, 7, 1); - $thisfile_iso_primaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32); - $thisfile_iso_primaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32); - //$thisfile_iso_primaryVD_raw['unused_2'] = substr($ISOheader, 72, 8); - $thisfile_iso_primaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4)); - //$thisfile_iso_primaryVD_raw['unused_3'] = substr($ISOheader, 88, 32); - $thisfile_iso_primaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2)); - $thisfile_iso_primaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2)); - $thisfile_iso_primaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2)); - $thisfile_iso_primaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4)); - $thisfile_iso_primaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2)); - $thisfile_iso_primaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2)); - $thisfile_iso_primaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2)); - $thisfile_iso_primaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2)); - $thisfile_iso_primaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34); - $thisfile_iso_primaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128); - $thisfile_iso_primaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128); - $thisfile_iso_primaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128); - $thisfile_iso_primaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128); - $thisfile_iso_primaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37); - $thisfile_iso_primaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37); - $thisfile_iso_primaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); - $thisfile_iso_primaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17); - $thisfile_iso_primaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17); - $thisfile_iso_primaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17); - $thisfile_iso_primaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17); - $thisfile_iso_primaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1)); - //$thisfile_iso_primaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1)); - $thisfile_iso_primaryVD_raw['application_data'] = substr($ISOheader, 883, 512); - //$thisfile_iso_primaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653); - - $thisfile_iso_primaryVD['system_identifier'] = trim($thisfile_iso_primaryVD_raw['system_identifier']); - $thisfile_iso_primaryVD['volume_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_identifier']); - $thisfile_iso_primaryVD['volume_set_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_set_identifier']); - $thisfile_iso_primaryVD['publisher_identifier'] = trim($thisfile_iso_primaryVD_raw['publisher_identifier']); - $thisfile_iso_primaryVD['data_preparer_identifier'] = trim($thisfile_iso_primaryVD_raw['data_preparer_identifier']); - $thisfile_iso_primaryVD['application_identifier'] = trim($thisfile_iso_primaryVD_raw['application_identifier']); - $thisfile_iso_primaryVD['copyright_file_identifier'] = trim($thisfile_iso_primaryVD_raw['copyright_file_identifier']); - $thisfile_iso_primaryVD['abstract_file_identifier'] = trim($thisfile_iso_primaryVD_raw['abstract_file_identifier']); - $thisfile_iso_primaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_primaryVD_raw['bibliographic_file_identifier']); - $thisfile_iso_primaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_creation_date_time']); - $thisfile_iso_primaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_modification_date_time']); - $thisfile_iso_primaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_expiration_date_time']); - $thisfile_iso_primaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_effective_date_time']); - - if (($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048) > $info['filesize']) { - $info['error'][] = 'Volume Space Size ('.($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)'; - } - - return true; - } - - - public function ParseSupplementaryVolumeDescriptor(&$ISOheader) { - // ISO integer values are stored Both-Endian format!! - // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field - - // shortcuts - $info = &$this->getid3->info; - $info['iso']['supplementary_volume_descriptor']['raw'] = array(); - $thisfile_iso_supplementaryVD = &$info['iso']['supplementary_volume_descriptor']; - $thisfile_iso_supplementaryVD_raw = &$thisfile_iso_supplementaryVD['raw']; - - $thisfile_iso_supplementaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1)); - $thisfile_iso_supplementaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5); - if ($thisfile_iso_supplementaryVD_raw['standard_identifier'] != 'CD001') { - $info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_supplementaryVD['offset'] + 1).'), found "'.$thisfile_iso_supplementaryVD_raw['standard_identifier'].'" instead'; - unset($info['fileformat']); - unset($info['iso']); - return false; - } - - $thisfile_iso_supplementaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1)); - //$thisfile_iso_supplementaryVD_raw['unused_1'] = substr($ISOheader, 7, 1); - $thisfile_iso_supplementaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32); - $thisfile_iso_supplementaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32); - //$thisfile_iso_supplementaryVD_raw['unused_2'] = substr($ISOheader, 72, 8); - $thisfile_iso_supplementaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4)); - if ($thisfile_iso_supplementaryVD_raw['volume_space_size'] == 0) { - // Supplementary Volume Descriptor not used - //unset($thisfile_iso_supplementaryVD); - //return false; - } - - //$thisfile_iso_supplementaryVD_raw['unused_3'] = substr($ISOheader, 88, 32); - $thisfile_iso_supplementaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2)); - $thisfile_iso_supplementaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2)); - $thisfile_iso_supplementaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2)); - $thisfile_iso_supplementaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4)); - $thisfile_iso_supplementaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2)); - $thisfile_iso_supplementaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2)); - $thisfile_iso_supplementaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2)); - $thisfile_iso_supplementaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2)); - $thisfile_iso_supplementaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34); - $thisfile_iso_supplementaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128); - $thisfile_iso_supplementaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128); - $thisfile_iso_supplementaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128); - $thisfile_iso_supplementaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128); - $thisfile_iso_supplementaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37); - $thisfile_iso_supplementaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37); - $thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); - $thisfile_iso_supplementaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17); - $thisfile_iso_supplementaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17); - $thisfile_iso_supplementaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17); - $thisfile_iso_supplementaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17); - $thisfile_iso_supplementaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1)); - //$thisfile_iso_supplementaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1)); - $thisfile_iso_supplementaryVD_raw['application_data'] = substr($ISOheader, 883, 512); - //$thisfile_iso_supplementaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653); - - $thisfile_iso_supplementaryVD['system_identifier'] = trim($thisfile_iso_supplementaryVD_raw['system_identifier']); - $thisfile_iso_supplementaryVD['volume_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_identifier']); - $thisfile_iso_supplementaryVD['volume_set_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_set_identifier']); - $thisfile_iso_supplementaryVD['publisher_identifier'] = trim($thisfile_iso_supplementaryVD_raw['publisher_identifier']); - $thisfile_iso_supplementaryVD['data_preparer_identifier'] = trim($thisfile_iso_supplementaryVD_raw['data_preparer_identifier']); - $thisfile_iso_supplementaryVD['application_identifier'] = trim($thisfile_iso_supplementaryVD_raw['application_identifier']); - $thisfile_iso_supplementaryVD['copyright_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['copyright_file_identifier']); - $thisfile_iso_supplementaryVD['abstract_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['abstract_file_identifier']); - $thisfile_iso_supplementaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier']); - $thisfile_iso_supplementaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_creation_date_time']); - $thisfile_iso_supplementaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_modification_date_time']); - $thisfile_iso_supplementaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_expiration_date_time']); - $thisfile_iso_supplementaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_effective_date_time']); - - if (($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']) > $info['filesize']) { - $info['error'][] = 'Volume Space Size ('.($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)'; - } - - return true; - } - - - public function ParsePathTable() { - $info = &$this->getid3->info; - if (!isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($info['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) { - return false; - } - if (isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) { - $PathTableLocation = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']; - $PathTableSize = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_size']; - $TextEncoding = 'UTF-16BE'; // Big-Endian Unicode - } else { - $PathTableLocation = $info['iso']['primary_volume_descriptor']['raw']['path_table_l_location']; - $PathTableSize = $info['iso']['primary_volume_descriptor']['raw']['path_table_size']; - $TextEncoding = 'ISO-8859-1'; // Latin-1 - } - - if (($PathTableLocation * 2048) > $info['filesize']) { - $info['error'][] = 'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$info['filesize'].')'; - return false; - } - - $info['iso']['path_table']['offset'] = $PathTableLocation * 2048; - fseek($this->getid3->fp, $info['iso']['path_table']['offset'], SEEK_SET); - $info['iso']['path_table']['raw'] = fread($this->getid3->fp, $PathTableSize); - - $offset = 0; - $pathcounter = 1; - while ($offset < $PathTableSize) { - // shortcut - $info['iso']['path_table']['directories'][$pathcounter] = array(); - $thisfile_iso_pathtable_directories_current = &$info['iso']['path_table']['directories'][$pathcounter]; - - $thisfile_iso_pathtable_directories_current['length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1)); - $offset += 1; - $thisfile_iso_pathtable_directories_current['extended_length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1)); - $offset += 1; - $thisfile_iso_pathtable_directories_current['location_logical'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 4)); - $offset += 4; - $thisfile_iso_pathtable_directories_current['parent_directory'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 2)); - $offset += 2; - $thisfile_iso_pathtable_directories_current['name'] = substr($info['iso']['path_table']['raw'], $offset, $thisfile_iso_pathtable_directories_current['length']); - $offset += $thisfile_iso_pathtable_directories_current['length'] + ($thisfile_iso_pathtable_directories_current['length'] % 2); - - $thisfile_iso_pathtable_directories_current['name_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $thisfile_iso_pathtable_directories_current['name']); - - $thisfile_iso_pathtable_directories_current['location_bytes'] = $thisfile_iso_pathtable_directories_current['location_logical'] * 2048; - if ($pathcounter == 1) { - $thisfile_iso_pathtable_directories_current['full_path'] = '/'; - } else { - $thisfile_iso_pathtable_directories_current['full_path'] = $info['iso']['path_table']['directories'][$thisfile_iso_pathtable_directories_current['parent_directory']]['full_path'].$thisfile_iso_pathtable_directories_current['name_ascii'].'/'; - } - $FullPathArray[] = $thisfile_iso_pathtable_directories_current['full_path']; - - $pathcounter++; - } - - return true; - } - - - public function ParseDirectoryRecord($directorydata) { - $info = &$this->getid3->info; - if (isset($info['iso']['supplementary_volume_descriptor'])) { - $TextEncoding = 'UTF-16BE'; // Big-Endian Unicode - } else { - $TextEncoding = 'ISO-8859-1'; // Latin-1 - } - - fseek($this->getid3->fp, $directorydata['location_bytes'], SEEK_SET); - $DirectoryRecordData = fread($this->getid3->fp, 1); - - while (ord($DirectoryRecordData{0}) > 33) { - - $DirectoryRecordData .= fread($this->getid3->fp, ord($DirectoryRecordData{0}) - 1); - - $ThisDirectoryRecord['raw']['length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 0, 1)); - $ThisDirectoryRecord['raw']['extended_attribute_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 1, 1)); - $ThisDirectoryRecord['raw']['offset_logical'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 2, 4)); - $ThisDirectoryRecord['raw']['filesize'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 10, 4)); - $ThisDirectoryRecord['raw']['recording_date_time'] = substr($DirectoryRecordData, 18, 7); - $ThisDirectoryRecord['raw']['file_flags'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 25, 1)); - $ThisDirectoryRecord['raw']['file_unit_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 26, 1)); - $ThisDirectoryRecord['raw']['interleave_gap_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 27, 1)); - $ThisDirectoryRecord['raw']['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 28, 2)); - $ThisDirectoryRecord['raw']['file_identifier_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 32, 1)); - $ThisDirectoryRecord['raw']['file_identifier'] = substr($DirectoryRecordData, 33, $ThisDirectoryRecord['raw']['file_identifier_length']); - - $ThisDirectoryRecord['file_identifier_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $ThisDirectoryRecord['raw']['file_identifier']); - - $ThisDirectoryRecord['filesize'] = $ThisDirectoryRecord['raw']['filesize']; - $ThisDirectoryRecord['offset_bytes'] = $ThisDirectoryRecord['raw']['offset_logical'] * 2048; - $ThisDirectoryRecord['file_flags']['hidden'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x01); - $ThisDirectoryRecord['file_flags']['directory'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x02); - $ThisDirectoryRecord['file_flags']['associated'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x04); - $ThisDirectoryRecord['file_flags']['extended'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x08); - $ThisDirectoryRecord['file_flags']['permissions'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x10); - $ThisDirectoryRecord['file_flags']['multiple'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x80); - $ThisDirectoryRecord['recording_timestamp'] = $this->ISOtime2UNIXtime($ThisDirectoryRecord['raw']['recording_date_time']); - - if ($ThisDirectoryRecord['file_flags']['directory']) { - $ThisDirectoryRecord['filename'] = $directorydata['full_path']; - } else { - $ThisDirectoryRecord['filename'] = $directorydata['full_path'].$this->ISOstripFilenameVersion($ThisDirectoryRecord['file_identifier_ascii']); - $info['iso']['files'] = getid3_lib::array_merge_clobber($info['iso']['files'], getid3_lib::CreateDeepArray($ThisDirectoryRecord['filename'], '/', $ThisDirectoryRecord['filesize'])); - } - - $DirectoryRecord[] = $ThisDirectoryRecord; - $DirectoryRecordData = fread($this->getid3->fp, 1); - } - - return $DirectoryRecord; - } - - public function ISOstripFilenameVersion($ISOfilename) { - // convert 'filename.ext;1' to 'filename.ext' - if (!strstr($ISOfilename, ';')) { - return $ISOfilename; - } else { - return substr($ISOfilename, 0, strpos($ISOfilename, ';')); - } - } - - public function ISOtimeText2UNIXtime($ISOtime) { - - $UNIXyear = (int) substr($ISOtime, 0, 4); - $UNIXmonth = (int) substr($ISOtime, 4, 2); - $UNIXday = (int) substr($ISOtime, 6, 2); - $UNIXhour = (int) substr($ISOtime, 8, 2); - $UNIXminute = (int) substr($ISOtime, 10, 2); - $UNIXsecond = (int) substr($ISOtime, 12, 2); - - if (!$UNIXyear) { - return false; - } - return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); - } - - public function ISOtime2UNIXtime($ISOtime) { - // Represented by seven bytes: - // 1: Number of years since 1900 - // 2: Month of the year from 1 to 12 - // 3: Day of the Month from 1 to 31 - // 4: Hour of the day from 0 to 23 - // 5: Minute of the hour from 0 to 59 - // 6: second of the minute from 0 to 59 - // 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East) - - $UNIXyear = ord($ISOtime{0}) + 1900; - $UNIXmonth = ord($ISOtime{1}); - $UNIXday = ord($ISOtime{2}); - $UNIXhour = ord($ISOtime{3}); - $UNIXminute = ord($ISOtime{4}); - $UNIXsecond = ord($ISOtime{5}); - $GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5})); - - return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); - } - - public function TwosCompliment2Decimal($BinaryValue) { - // http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html - // First check if the number is negative or positive by looking at the sign bit. - // If it is positive, simply convert it to decimal. - // If it is negative, make it positive by inverting the bits and adding one. - // Then, convert the result to decimal. - // The negative of this number is the value of the original binary. - - if ($BinaryValue & 0x80) { - - // negative number - return (0 - ((~$BinaryValue & 0xFF) + 1)); - } else { - // positive number - return $BinaryValue; - } - } - - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.iso.php // +// module for analyzing ISO files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_iso extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'iso'; + + for ($i = 16; $i <= 19; $i++) { + fseek($this->getid3->fp, 2048 * $i, SEEK_SET); + $ISOheader = fread($this->getid3->fp, 2048); + if (substr($ISOheader, 1, 5) == 'CD001') { + switch (ord($ISOheader{0})) { + case 1: + $info['iso']['primary_volume_descriptor']['offset'] = 2048 * $i; + $this->ParsePrimaryVolumeDescriptor($ISOheader); + break; + + case 2: + $info['iso']['supplementary_volume_descriptor']['offset'] = 2048 * $i; + $this->ParseSupplementaryVolumeDescriptor($ISOheader); + break; + + default: + // skip + break; + } + } + } + + $this->ParsePathTable(); + + $info['iso']['files'] = array(); + foreach ($info['iso']['path_table']['directories'] as $directorynum => $directorydata) { + $info['iso']['directories'][$directorynum] = $this->ParseDirectoryRecord($directorydata); + } + + return true; + } + + + public function ParsePrimaryVolumeDescriptor(&$ISOheader) { + // ISO integer values are stored *BOTH* Little-Endian AND Big-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + // shortcuts + $info = &$this->getid3->info; + $info['iso']['primary_volume_descriptor']['raw'] = array(); + $thisfile_iso_primaryVD = &$info['iso']['primary_volume_descriptor']; + $thisfile_iso_primaryVD_raw = &$thisfile_iso_primaryVD['raw']; + + $thisfile_iso_primaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1)); + $thisfile_iso_primaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5); + if ($thisfile_iso_primaryVD_raw['standard_identifier'] != 'CD001') { + $info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_primaryVD['offset'] + 1).'), found "'.$thisfile_iso_primaryVD_raw['standard_identifier'].'" instead'; + unset($info['fileformat']); + unset($info['iso']); + return false; + } + + + $thisfile_iso_primaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1)); + //$thisfile_iso_primaryVD_raw['unused_1'] = substr($ISOheader, 7, 1); + $thisfile_iso_primaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32); + $thisfile_iso_primaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32); + //$thisfile_iso_primaryVD_raw['unused_2'] = substr($ISOheader, 72, 8); + $thisfile_iso_primaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4)); + //$thisfile_iso_primaryVD_raw['unused_3'] = substr($ISOheader, 88, 32); + $thisfile_iso_primaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2)); + $thisfile_iso_primaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2)); + $thisfile_iso_primaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2)); + $thisfile_iso_primaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4)); + $thisfile_iso_primaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2)); + $thisfile_iso_primaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2)); + $thisfile_iso_primaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2)); + $thisfile_iso_primaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2)); + $thisfile_iso_primaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34); + $thisfile_iso_primaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128); + $thisfile_iso_primaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128); + $thisfile_iso_primaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128); + $thisfile_iso_primaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128); + $thisfile_iso_primaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37); + $thisfile_iso_primaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37); + $thisfile_iso_primaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); + $thisfile_iso_primaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17); + $thisfile_iso_primaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17); + $thisfile_iso_primaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17); + $thisfile_iso_primaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17); + $thisfile_iso_primaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1)); + //$thisfile_iso_primaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1)); + $thisfile_iso_primaryVD_raw['application_data'] = substr($ISOheader, 883, 512); + //$thisfile_iso_primaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653); + + $thisfile_iso_primaryVD['system_identifier'] = trim($thisfile_iso_primaryVD_raw['system_identifier']); + $thisfile_iso_primaryVD['volume_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_identifier']); + $thisfile_iso_primaryVD['volume_set_identifier'] = trim($thisfile_iso_primaryVD_raw['volume_set_identifier']); + $thisfile_iso_primaryVD['publisher_identifier'] = trim($thisfile_iso_primaryVD_raw['publisher_identifier']); + $thisfile_iso_primaryVD['data_preparer_identifier'] = trim($thisfile_iso_primaryVD_raw['data_preparer_identifier']); + $thisfile_iso_primaryVD['application_identifier'] = trim($thisfile_iso_primaryVD_raw['application_identifier']); + $thisfile_iso_primaryVD['copyright_file_identifier'] = trim($thisfile_iso_primaryVD_raw['copyright_file_identifier']); + $thisfile_iso_primaryVD['abstract_file_identifier'] = trim($thisfile_iso_primaryVD_raw['abstract_file_identifier']); + $thisfile_iso_primaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_primaryVD_raw['bibliographic_file_identifier']); + $thisfile_iso_primaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_creation_date_time']); + $thisfile_iso_primaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_modification_date_time']); + $thisfile_iso_primaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_expiration_date_time']); + $thisfile_iso_primaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_primaryVD_raw['volume_effective_date_time']); + + if (($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048) > $info['filesize']) { + $info['error'][] = 'Volume Space Size ('.($thisfile_iso_primaryVD_raw['volume_space_size'] * 2048).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)'; + } + + return true; + } + + + public function ParseSupplementaryVolumeDescriptor(&$ISOheader) { + // ISO integer values are stored Both-Endian format!! + // ie 12345 == 0x3039 is stored as $39 $30 $30 $39 in a 4-byte field + + // shortcuts + $info = &$this->getid3->info; + $info['iso']['supplementary_volume_descriptor']['raw'] = array(); + $thisfile_iso_supplementaryVD = &$info['iso']['supplementary_volume_descriptor']; + $thisfile_iso_supplementaryVD_raw = &$thisfile_iso_supplementaryVD['raw']; + + $thisfile_iso_supplementaryVD_raw['volume_descriptor_type'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 0, 1)); + $thisfile_iso_supplementaryVD_raw['standard_identifier'] = substr($ISOheader, 1, 5); + if ($thisfile_iso_supplementaryVD_raw['standard_identifier'] != 'CD001') { + $info['error'][] = 'Expected "CD001" at offset ('.($thisfile_iso_supplementaryVD['offset'] + 1).'), found "'.$thisfile_iso_supplementaryVD_raw['standard_identifier'].'" instead'; + unset($info['fileformat']); + unset($info['iso']); + return false; + } + + $thisfile_iso_supplementaryVD_raw['volume_descriptor_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 6, 1)); + //$thisfile_iso_supplementaryVD_raw['unused_1'] = substr($ISOheader, 7, 1); + $thisfile_iso_supplementaryVD_raw['system_identifier'] = substr($ISOheader, 8, 32); + $thisfile_iso_supplementaryVD_raw['volume_identifier'] = substr($ISOheader, 40, 32); + //$thisfile_iso_supplementaryVD_raw['unused_2'] = substr($ISOheader, 72, 8); + $thisfile_iso_supplementaryVD_raw['volume_space_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 80, 4)); + if ($thisfile_iso_supplementaryVD_raw['volume_space_size'] == 0) { + // Supplementary Volume Descriptor not used + //unset($thisfile_iso_supplementaryVD); + //return false; + } + + //$thisfile_iso_supplementaryVD_raw['unused_3'] = substr($ISOheader, 88, 32); + $thisfile_iso_supplementaryVD_raw['volume_set_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 120, 2)); + $thisfile_iso_supplementaryVD_raw['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 124, 2)); + $thisfile_iso_supplementaryVD_raw['logical_block_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 128, 2)); + $thisfile_iso_supplementaryVD_raw['path_table_size'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 132, 4)); + $thisfile_iso_supplementaryVD_raw['path_table_l_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 140, 2)); + $thisfile_iso_supplementaryVD_raw['path_table_l_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 144, 2)); + $thisfile_iso_supplementaryVD_raw['path_table_m_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 148, 2)); + $thisfile_iso_supplementaryVD_raw['path_table_m_opt_location'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 152, 2)); + $thisfile_iso_supplementaryVD_raw['root_directory_record'] = substr($ISOheader, 156, 34); + $thisfile_iso_supplementaryVD_raw['volume_set_identifier'] = substr($ISOheader, 190, 128); + $thisfile_iso_supplementaryVD_raw['publisher_identifier'] = substr($ISOheader, 318, 128); + $thisfile_iso_supplementaryVD_raw['data_preparer_identifier'] = substr($ISOheader, 446, 128); + $thisfile_iso_supplementaryVD_raw['application_identifier'] = substr($ISOheader, 574, 128); + $thisfile_iso_supplementaryVD_raw['copyright_file_identifier'] = substr($ISOheader, 702, 37); + $thisfile_iso_supplementaryVD_raw['abstract_file_identifier'] = substr($ISOheader, 739, 37); + $thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier'] = substr($ISOheader, 776, 37); + $thisfile_iso_supplementaryVD_raw['volume_creation_date_time'] = substr($ISOheader, 813, 17); + $thisfile_iso_supplementaryVD_raw['volume_modification_date_time'] = substr($ISOheader, 830, 17); + $thisfile_iso_supplementaryVD_raw['volume_expiration_date_time'] = substr($ISOheader, 847, 17); + $thisfile_iso_supplementaryVD_raw['volume_effective_date_time'] = substr($ISOheader, 864, 17); + $thisfile_iso_supplementaryVD_raw['file_structure_version'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 881, 1)); + //$thisfile_iso_supplementaryVD_raw['unused_4'] = getid3_lib::LittleEndian2Int(substr($ISOheader, 882, 1)); + $thisfile_iso_supplementaryVD_raw['application_data'] = substr($ISOheader, 883, 512); + //$thisfile_iso_supplementaryVD_raw['unused_5'] = substr($ISOheader, 1395, 653); + + $thisfile_iso_supplementaryVD['system_identifier'] = trim($thisfile_iso_supplementaryVD_raw['system_identifier']); + $thisfile_iso_supplementaryVD['volume_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_identifier']); + $thisfile_iso_supplementaryVD['volume_set_identifier'] = trim($thisfile_iso_supplementaryVD_raw['volume_set_identifier']); + $thisfile_iso_supplementaryVD['publisher_identifier'] = trim($thisfile_iso_supplementaryVD_raw['publisher_identifier']); + $thisfile_iso_supplementaryVD['data_preparer_identifier'] = trim($thisfile_iso_supplementaryVD_raw['data_preparer_identifier']); + $thisfile_iso_supplementaryVD['application_identifier'] = trim($thisfile_iso_supplementaryVD_raw['application_identifier']); + $thisfile_iso_supplementaryVD['copyright_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['copyright_file_identifier']); + $thisfile_iso_supplementaryVD['abstract_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['abstract_file_identifier']); + $thisfile_iso_supplementaryVD['bibliographic_file_identifier'] = trim($thisfile_iso_supplementaryVD_raw['bibliographic_file_identifier']); + $thisfile_iso_supplementaryVD['volume_creation_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_creation_date_time']); + $thisfile_iso_supplementaryVD['volume_modification_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_modification_date_time']); + $thisfile_iso_supplementaryVD['volume_expiration_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_expiration_date_time']); + $thisfile_iso_supplementaryVD['volume_effective_date_time'] = $this->ISOtimeText2UNIXtime($thisfile_iso_supplementaryVD_raw['volume_effective_date_time']); + + if (($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']) > $info['filesize']) { + $info['error'][] = 'Volume Space Size ('.($thisfile_iso_supplementaryVD_raw['volume_space_size'] * $thisfile_iso_supplementaryVD_raw['logical_block_size']).' bytes) is larger than the file size ('.$info['filesize'].' bytes) (truncated file?)'; + } + + return true; + } + + + public function ParsePathTable() { + $info = &$this->getid3->info; + if (!isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']) && !isset($info['iso']['primary_volume_descriptor']['raw']['path_table_l_location'])) { + return false; + } + if (isset($info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location'])) { + $PathTableLocation = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_l_location']; + $PathTableSize = $info['iso']['supplementary_volume_descriptor']['raw']['path_table_size']; + $TextEncoding = 'UTF-16BE'; // Big-Endian Unicode + } else { + $PathTableLocation = $info['iso']['primary_volume_descriptor']['raw']['path_table_l_location']; + $PathTableSize = $info['iso']['primary_volume_descriptor']['raw']['path_table_size']; + $TextEncoding = 'ISO-8859-1'; // Latin-1 + } + + if (($PathTableLocation * 2048) > $info['filesize']) { + $info['error'][] = 'Path Table Location specifies an offset ('.($PathTableLocation * 2048).') beyond the end-of-file ('.$info['filesize'].')'; + return false; + } + + $info['iso']['path_table']['offset'] = $PathTableLocation * 2048; + fseek($this->getid3->fp, $info['iso']['path_table']['offset'], SEEK_SET); + $info['iso']['path_table']['raw'] = fread($this->getid3->fp, $PathTableSize); + + $offset = 0; + $pathcounter = 1; + while ($offset < $PathTableSize) { + // shortcut + $info['iso']['path_table']['directories'][$pathcounter] = array(); + $thisfile_iso_pathtable_directories_current = &$info['iso']['path_table']['directories'][$pathcounter]; + + $thisfile_iso_pathtable_directories_current['length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1)); + $offset += 1; + $thisfile_iso_pathtable_directories_current['extended_length'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 1)); + $offset += 1; + $thisfile_iso_pathtable_directories_current['location_logical'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 4)); + $offset += 4; + $thisfile_iso_pathtable_directories_current['parent_directory'] = getid3_lib::LittleEndian2Int(substr($info['iso']['path_table']['raw'], $offset, 2)); + $offset += 2; + $thisfile_iso_pathtable_directories_current['name'] = substr($info['iso']['path_table']['raw'], $offset, $thisfile_iso_pathtable_directories_current['length']); + $offset += $thisfile_iso_pathtable_directories_current['length'] + ($thisfile_iso_pathtable_directories_current['length'] % 2); + + $thisfile_iso_pathtable_directories_current['name_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $thisfile_iso_pathtable_directories_current['name']); + + $thisfile_iso_pathtable_directories_current['location_bytes'] = $thisfile_iso_pathtable_directories_current['location_logical'] * 2048; + if ($pathcounter == 1) { + $thisfile_iso_pathtable_directories_current['full_path'] = '/'; + } else { + $thisfile_iso_pathtable_directories_current['full_path'] = $info['iso']['path_table']['directories'][$thisfile_iso_pathtable_directories_current['parent_directory']]['full_path'].$thisfile_iso_pathtable_directories_current['name_ascii'].'/'; + } + $FullPathArray[] = $thisfile_iso_pathtable_directories_current['full_path']; + + $pathcounter++; + } + + return true; + } + + + public function ParseDirectoryRecord($directorydata) { + $info = &$this->getid3->info; + if (isset($info['iso']['supplementary_volume_descriptor'])) { + $TextEncoding = 'UTF-16BE'; // Big-Endian Unicode + } else { + $TextEncoding = 'ISO-8859-1'; // Latin-1 + } + + fseek($this->getid3->fp, $directorydata['location_bytes'], SEEK_SET); + $DirectoryRecordData = fread($this->getid3->fp, 1); + + while (ord($DirectoryRecordData{0}) > 33) { + + $DirectoryRecordData .= fread($this->getid3->fp, ord($DirectoryRecordData{0}) - 1); + + $ThisDirectoryRecord['raw']['length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 0, 1)); + $ThisDirectoryRecord['raw']['extended_attribute_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 1, 1)); + $ThisDirectoryRecord['raw']['offset_logical'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 2, 4)); + $ThisDirectoryRecord['raw']['filesize'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 10, 4)); + $ThisDirectoryRecord['raw']['recording_date_time'] = substr($DirectoryRecordData, 18, 7); + $ThisDirectoryRecord['raw']['file_flags'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 25, 1)); + $ThisDirectoryRecord['raw']['file_unit_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 26, 1)); + $ThisDirectoryRecord['raw']['interleave_gap_size'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 27, 1)); + $ThisDirectoryRecord['raw']['volume_sequence_number'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 28, 2)); + $ThisDirectoryRecord['raw']['file_identifier_length'] = getid3_lib::LittleEndian2Int(substr($DirectoryRecordData, 32, 1)); + $ThisDirectoryRecord['raw']['file_identifier'] = substr($DirectoryRecordData, 33, $ThisDirectoryRecord['raw']['file_identifier_length']); + + $ThisDirectoryRecord['file_identifier_ascii'] = getid3_lib::iconv_fallback($TextEncoding, $info['encoding'], $ThisDirectoryRecord['raw']['file_identifier']); + + $ThisDirectoryRecord['filesize'] = $ThisDirectoryRecord['raw']['filesize']; + $ThisDirectoryRecord['offset_bytes'] = $ThisDirectoryRecord['raw']['offset_logical'] * 2048; + $ThisDirectoryRecord['file_flags']['hidden'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x01); + $ThisDirectoryRecord['file_flags']['directory'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x02); + $ThisDirectoryRecord['file_flags']['associated'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x04); + $ThisDirectoryRecord['file_flags']['extended'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x08); + $ThisDirectoryRecord['file_flags']['permissions'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x10); + $ThisDirectoryRecord['file_flags']['multiple'] = (bool) ($ThisDirectoryRecord['raw']['file_flags'] & 0x80); + $ThisDirectoryRecord['recording_timestamp'] = $this->ISOtime2UNIXtime($ThisDirectoryRecord['raw']['recording_date_time']); + + if ($ThisDirectoryRecord['file_flags']['directory']) { + $ThisDirectoryRecord['filename'] = $directorydata['full_path']; + } else { + $ThisDirectoryRecord['filename'] = $directorydata['full_path'].$this->ISOstripFilenameVersion($ThisDirectoryRecord['file_identifier_ascii']); + $info['iso']['files'] = getid3_lib::array_merge_clobber($info['iso']['files'], getid3_lib::CreateDeepArray($ThisDirectoryRecord['filename'], '/', $ThisDirectoryRecord['filesize'])); + } + + $DirectoryRecord[] = $ThisDirectoryRecord; + $DirectoryRecordData = fread($this->getid3->fp, 1); + } + + return $DirectoryRecord; + } + + public function ISOstripFilenameVersion($ISOfilename) { + // convert 'filename.ext;1' to 'filename.ext' + if (!strstr($ISOfilename, ';')) { + return $ISOfilename; + } else { + return substr($ISOfilename, 0, strpos($ISOfilename, ';')); + } + } + + public function ISOtimeText2UNIXtime($ISOtime) { + + $UNIXyear = (int) substr($ISOtime, 0, 4); + $UNIXmonth = (int) substr($ISOtime, 4, 2); + $UNIXday = (int) substr($ISOtime, 6, 2); + $UNIXhour = (int) substr($ISOtime, 8, 2); + $UNIXminute = (int) substr($ISOtime, 10, 2); + $UNIXsecond = (int) substr($ISOtime, 12, 2); + + if (!$UNIXyear) { + return false; + } + return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); + } + + public function ISOtime2UNIXtime($ISOtime) { + // Represented by seven bytes: + // 1: Number of years since 1900 + // 2: Month of the year from 1 to 12 + // 3: Day of the Month from 1 to 31 + // 4: Hour of the day from 0 to 23 + // 5: Minute of the hour from 0 to 59 + // 6: second of the minute from 0 to 59 + // 7: Offset from Greenwich Mean Time in number of 15 minute intervals from -48 (West) to +52 (East) + + $UNIXyear = ord($ISOtime{0}) + 1900; + $UNIXmonth = ord($ISOtime{1}); + $UNIXday = ord($ISOtime{2}); + $UNIXhour = ord($ISOtime{3}); + $UNIXminute = ord($ISOtime{4}); + $UNIXsecond = ord($ISOtime{5}); + $GMToffset = $this->TwosCompliment2Decimal(ord($ISOtime{5})); + + return gmmktime($UNIXhour, $UNIXminute, $UNIXsecond, $UNIXmonth, $UNIXday, $UNIXyear); + } + + public function TwosCompliment2Decimal($BinaryValue) { + // http://sandbox.mc.edu/~bennet/cs110/tc/tctod.html + // First check if the number is negative or positive by looking at the sign bit. + // If it is positive, simply convert it to decimal. + // If it is negative, make it positive by inverting the bits and adding one. + // Then, convert the result to decimal. + // The negative of this number is the value of the original binary. + + if ($BinaryValue & 0x80) { + + // negative number + return (0 - ((~$BinaryValue & 0xFF) + 1)); + } else { + // positive number + return $BinaryValue; + } + } + + +} diff --git a/app/libs/vendor/getid3/module.misc.msoffice.php b/app/libs/vendor/getid3/module.misc.msoffice.php index 0a120969..e488854c 100644 --- a/app/libs/vendor/getid3/module.misc.msoffice.php +++ b/app/libs/vendor/getid3/module.misc.msoffice.php @@ -1,37 +1,37 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.msoffice.php // -// module for analyzing MS Office (.doc, .xls, etc) files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_msoffice extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); - $DOCFILEheader = fread($this->getid3->fp, 8); - $magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"; - if (substr($DOCFILEheader, 0, 8) != $magic) { - $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.'; - return false; - } - $info['fileformat'] = 'msoffice'; - -$info['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; -return false; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.msoffice.php // +// module for analyzing MS Office (.doc, .xls, etc) files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_msoffice extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + fseek($this->getid3->fp, $info['avdataoffset'], SEEK_SET); + $DOCFILEheader = fread($this->getid3->fp, 8); + $magic = "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1"; + if (substr($DOCFILEheader, 0, 8) != $magic) { + $info['error'][] = 'Expecting "'.getid3_lib::PrintHexBytes($magic).'" at '.$info['avdataoffset'].', found '.getid3_lib::PrintHexBytes(substr($DOCFILEheader, 0, 8)).' instead.'; + return false; + } + $info['fileformat'] = 'msoffice'; + +$info['error'][] = 'MS Office (.doc, .xls, etc) parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; +return false; + + } + +} diff --git a/app/libs/vendor/getid3/module.misc.par2.php b/app/libs/vendor/getid3/module.misc.par2.php index 13ef1ba0..80b47d29 100644 --- a/app/libs/vendor/getid3/module.misc.par2.php +++ b/app/libs/vendor/getid3/module.misc.par2.php @@ -1,30 +1,30 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.par2.php // -// module for analyzing PAR2 files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_par2 extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'par2'; - - $info['error'][] = 'PAR2 parsing not enabled in this version of getID3()'; - return false; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.par2.php // +// module for analyzing PAR2 files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_par2 extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'par2'; + + $info['error'][] = 'PAR2 parsing not enabled in this version of getID3()'; + return false; + + } + +} diff --git a/app/libs/vendor/getid3/module.misc.pdf.php b/app/libs/vendor/getid3/module.misc.pdf.php index b5972dd9..3b8aaa14 100644 --- a/app/libs/vendor/getid3/module.misc.pdf.php +++ b/app/libs/vendor/getid3/module.misc.pdf.php @@ -1,30 +1,30 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.misc.pdf.php // -// module for analyzing PDF files // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_pdf extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - $info['fileformat'] = 'pdf'; - - $info['error'][] = 'PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; - return false; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.misc.pdf.php // +// module for analyzing PDF files // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_pdf extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + $info['fileformat'] = 'pdf'; + + $info['error'][] = 'PDF parsing not enabled in this version of getID3() ['.$this->getid3->version().']'; + return false; + + } + +} diff --git a/app/libs/vendor/getid3/module.tag.apetag.php b/app/libs/vendor/getid3/module.tag.apetag.php index ffadd79f..afeede76 100644 --- a/app/libs/vendor/getid3/module.tag.apetag.php +++ b/app/libs/vendor/getid3/module.tag.apetag.php @@ -1,370 +1,370 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.tag.apetag.php // -// module for analyzing APE tags // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - -class getid3_apetag extends getid3_handler -{ - public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory - public $overrideendoffset = 0; - - public function Analyze() { - $info = &$this->getid3->info; - - if (!getid3_lib::intValueSupported($info['filesize'])) { - $info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - - $id3v1tagsize = 128; - $apetagheadersize = 32; - $lyrics3tagsize = 10; - - if ($this->overrideendoffset == 0) { - - fseek($this->getid3->fp, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END); - $APEfooterID3v1 = fread($this->getid3->fp, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize); - - //if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) { - if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') { - - // APE tag found before ID3v1 - $info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize; - - //} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) { - } elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') { - - // APE tag found, no ID3v1 - $info['ape']['tag_offset_end'] = $info['filesize']; - - } - - } else { - - fseek($this->getid3->fp, $this->overrideendoffset - $apetagheadersize, SEEK_SET); - if (fread($this->getid3->fp, 8) == 'APETAGEX') { - $info['ape']['tag_offset_end'] = $this->overrideendoffset; - } - - } - if (!isset($info['ape']['tag_offset_end'])) { - - // APE tag not found - unset($info['ape']); - return false; - - } - - // shortcut - $thisfile_ape = &$info['ape']; - - fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET); - $APEfooterData = fread($this->getid3->fp, 32); - if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) { - $info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end']; - return false; - } - - if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) { - fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET); - $thisfile_ape['tag_offset_start'] = ftell($this->getid3->fp); - $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize); - } else { - $thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize']; - fseek($this->getid3->fp, $thisfile_ape['tag_offset_start'], SEEK_SET); - $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize']); - } - $info['avdataend'] = $thisfile_ape['tag_offset_start']; - - if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) { - $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data'; - unset($info['id3v1']); - foreach ($info['warning'] as $key => $value) { - if ($value == 'Some ID3v1 fields do not use NULL characters for padding') { - unset($info['warning'][$key]); - sort($info['warning']); - break; - } - } - } - - $offset = 0; - if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) { - if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) { - $offset += $apetagheadersize; - } else { - $info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start']; - return false; - } - } - - // shortcut - $info['replay_gain'] = array(); - $thisfile_replaygain = &$info['replay_gain']; - - for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) { - $value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4)); - $offset += 4; - $item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4)); - $offset += 4; - if (strstr(substr($APEtagData, $offset), "\x00") === false) { - $info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset); - return false; - } - $ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset; - $item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength)); - - // shortcut - $thisfile_ape['items'][$item_key] = array(); - $thisfile_ape_items_current = &$thisfile_ape['items'][$item_key]; - - $thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset; - - $offset += ($ItemKeyLength + 1); // skip 0x00 terminator - $thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size); - $offset += $value_size; - - $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags); - switch ($thisfile_ape_items_current['flags']['item_contents_raw']) { - case 0: // UTF-8 - case 3: // Locator (URL, filename, etc), UTF-8 encoded - $thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data'])); - break; - - default: // binary data - break; - } - - switch (strtolower($item_key)) { - case 'replaygain_track_gain': - $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! - $thisfile_replaygain['track']['originator'] = 'unspecified'; - break; - - case 'replaygain_track_peak': - $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! - $thisfile_replaygain['track']['originator'] = 'unspecified'; - if ($thisfile_replaygain['track']['peak'] <= 0) { - $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; - } - break; - - case 'replaygain_album_gain': - $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! - $thisfile_replaygain['album']['originator'] = 'unspecified'; - break; - - case 'replaygain_album_peak': - $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! - $thisfile_replaygain['album']['originator'] = 'unspecified'; - if ($thisfile_replaygain['album']['peak'] <= 0) { - $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; - } - break; - - case 'mp3gain_undo': - list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]); - $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); - $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); - $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); - break; - - case 'mp3gain_minmax': - list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]); - $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); - $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); - break; - - case 'mp3gain_album_minmax': - list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]); - $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); - $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); - break; - - case 'tracknumber': - if (is_array($thisfile_ape_items_current['data'])) { - foreach ($thisfile_ape_items_current['data'] as $comment) { - $thisfile_ape['comments']['track'][] = $comment; - } - } - break; - - case 'cover art (artist)': - case 'cover art (back)': - case 'cover art (band logo)': - case 'cover art (band)': - case 'cover art (colored fish)': - case 'cover art (composer)': - case 'cover art (conductor)': - case 'cover art (front)': - case 'cover art (icon)': - case 'cover art (illustration)': - case 'cover art (lead)': - case 'cover art (leaflet)': - case 'cover art (lyricist)': - case 'cover art (media)': - case 'cover art (movie scene)': - case 'cover art (other icon)': - case 'cover art (other)': - case 'cover art (performance)': - case 'cover art (publisher logo)': - case 'cover art (recording)': - case 'cover art (studio)': - // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html - list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2); - $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); - $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); - - $thisfile_ape_items_current['image_mime'] = ''; - $imageinfo = array(); - $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); - $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); - - do { - if ($this->inline_attachments === false) { - // skip entirely - unset($thisfile_ape_items_current['data']); - break; - } - if ($this->inline_attachments === true) { - // great - } elseif (is_int($this->inline_attachments)) { - if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) { - // too big, skip - $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)'; - unset($thisfile_ape_items_current['data']); - break; - } - } elseif (is_string($this->inline_attachments)) { - $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR); - if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) { - // cannot write, skip - $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)'; - unset($thisfile_ape_items_current['data']); - break; - } - } - // if we get this far, must be OK - if (is_string($this->inline_attachments)) { - $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset']; - if (!file_exists($destination_filename) || is_writable($destination_filename)) { - file_put_contents($destination_filename, $thisfile_ape_items_current['data']); - } else { - $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)'; - } - $thisfile_ape_items_current['data_filename'] = $destination_filename; - unset($thisfile_ape_items_current['data']); - } else { - if (!isset($info['ape']['comments']['picture'])) { - $info['ape']['comments']['picture'] = array(); - } - $info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']); - } - } while (false); - break; - - default: - if (is_array($thisfile_ape_items_current['data'])) { - foreach ($thisfile_ape_items_current['data'] as $comment) { - $thisfile_ape['comments'][strtolower($item_key)][] = $comment; - } - } - break; - } - - } - if (empty($thisfile_replaygain)) { - unset($info['replay_gain']); - } - return true; - } - - public function parseAPEheaderFooter($APEheaderFooterData) { - // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html - - // shortcut - $headerfooterinfo['raw'] = array(); - $headerfooterinfo_raw = &$headerfooterinfo['raw']; - - $headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8); - if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') { - return false; - } - $headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4)); - $headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4)); - $headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4)); - $headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4)); - $headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8); - - $headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000; - if ($headerfooterinfo['tag_version'] >= 2) { - $headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']); - } - return $headerfooterinfo; - } - - public function parseAPEtagFlags($rawflagint) { - // "Note: APE Tags 1.0 do not use any of the APE Tag flags. - // All are set to zero on creation and ignored on reading." - // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html - $flags['header'] = (bool) ($rawflagint & 0x80000000); - $flags['footer'] = (bool) ($rawflagint & 0x40000000); - $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000); - $flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1; - $flags['read_only'] = (bool) ($rawflagint & 0x00000001); - - $flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']); - - return $flags; - } - - public function APEcontentTypeFlagLookup($contenttypeid) { - static $APEcontentTypeFlagLookup = array( - 0 => 'utf-8', - 1 => 'binary', - 2 => 'external', - 3 => 'reserved' - ); - return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid'); - } - - public function APEtagItemIsUTF8Lookup($itemkey) { - static $APEtagItemIsUTF8Lookup = array( - 'title', - 'subtitle', - 'artist', - 'album', - 'debut album', - 'publisher', - 'conductor', - 'track', - 'composer', - 'comment', - 'copyright', - 'publicationright', - 'file', - 'year', - 'record date', - 'record location', - 'genre', - 'media', - 'related', - 'isrc', - 'abstract', - 'language', - 'bibliography' - ); - return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup); - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.tag.apetag.php // +// module for analyzing APE tags // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + +class getid3_apetag extends getid3_handler +{ + public $inline_attachments = true; // true: return full data for all attachments; false: return no data for all attachments; integer: return data for attachments <= than this; string: save as file to this directory + public $overrideendoffset = 0; + + public function Analyze() { + $info = &$this->getid3->info; + + if (!getid3_lib::intValueSupported($info['filesize'])) { + $info['warning'][] = 'Unable to check for APEtags because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + + $id3v1tagsize = 128; + $apetagheadersize = 32; + $lyrics3tagsize = 10; + + if ($this->overrideendoffset == 0) { + + fseek($this->getid3->fp, 0 - $id3v1tagsize - $apetagheadersize - $lyrics3tagsize, SEEK_END); + $APEfooterID3v1 = fread($this->getid3->fp, $id3v1tagsize + $apetagheadersize + $lyrics3tagsize); + + //if (preg_match('/APETAGEX.{24}TAG.{125}$/i', $APEfooterID3v1)) { + if (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $id3v1tagsize - $apetagheadersize, 8) == 'APETAGEX') { + + // APE tag found before ID3v1 + $info['ape']['tag_offset_end'] = $info['filesize'] - $id3v1tagsize; + + //} elseif (preg_match('/APETAGEX.{24}$/i', $APEfooterID3v1)) { + } elseif (substr($APEfooterID3v1, strlen($APEfooterID3v1) - $apetagheadersize, 8) == 'APETAGEX') { + + // APE tag found, no ID3v1 + $info['ape']['tag_offset_end'] = $info['filesize']; + + } + + } else { + + fseek($this->getid3->fp, $this->overrideendoffset - $apetagheadersize, SEEK_SET); + if (fread($this->getid3->fp, 8) == 'APETAGEX') { + $info['ape']['tag_offset_end'] = $this->overrideendoffset; + } + + } + if (!isset($info['ape']['tag_offset_end'])) { + + // APE tag not found + unset($info['ape']); + return false; + + } + + // shortcut + $thisfile_ape = &$info['ape']; + + fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $apetagheadersize, SEEK_SET); + $APEfooterData = fread($this->getid3->fp, 32); + if (!($thisfile_ape['footer'] = $this->parseAPEheaderFooter($APEfooterData))) { + $info['error'][] = 'Error parsing APE footer at offset '.$thisfile_ape['tag_offset_end']; + return false; + } + + if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) { + fseek($this->getid3->fp, $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize'] - $apetagheadersize, SEEK_SET); + $thisfile_ape['tag_offset_start'] = ftell($this->getid3->fp); + $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize'] + $apetagheadersize); + } else { + $thisfile_ape['tag_offset_start'] = $thisfile_ape['tag_offset_end'] - $thisfile_ape['footer']['raw']['tagsize']; + fseek($this->getid3->fp, $thisfile_ape['tag_offset_start'], SEEK_SET); + $APEtagData = fread($this->getid3->fp, $thisfile_ape['footer']['raw']['tagsize']); + } + $info['avdataend'] = $thisfile_ape['tag_offset_start']; + + if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] < $thisfile_ape['tag_offset_end'])) { + $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in APEtag data'; + unset($info['id3v1']); + foreach ($info['warning'] as $key => $value) { + if ($value == 'Some ID3v1 fields do not use NULL characters for padding') { + unset($info['warning'][$key]); + sort($info['warning']); + break; + } + } + } + + $offset = 0; + if (isset($thisfile_ape['footer']['flags']['header']) && $thisfile_ape['footer']['flags']['header']) { + if ($thisfile_ape['header'] = $this->parseAPEheaderFooter(substr($APEtagData, 0, $apetagheadersize))) { + $offset += $apetagheadersize; + } else { + $info['error'][] = 'Error parsing APE header at offset '.$thisfile_ape['tag_offset_start']; + return false; + } + } + + // shortcut + $info['replay_gain'] = array(); + $thisfile_replaygain = &$info['replay_gain']; + + for ($i = 0; $i < $thisfile_ape['footer']['raw']['tag_items']; $i++) { + $value_size = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4)); + $offset += 4; + $item_flags = getid3_lib::LittleEndian2Int(substr($APEtagData, $offset, 4)); + $offset += 4; + if (strstr(substr($APEtagData, $offset), "\x00") === false) { + $info['error'][] = 'Cannot find null-byte (0x00) seperator between ItemKey #'.$i.' and value. ItemKey starts '.$offset.' bytes into the APE tag, at file offset '.($thisfile_ape['tag_offset_start'] + $offset); + return false; + } + $ItemKeyLength = strpos($APEtagData, "\x00", $offset) - $offset; + $item_key = strtolower(substr($APEtagData, $offset, $ItemKeyLength)); + + // shortcut + $thisfile_ape['items'][$item_key] = array(); + $thisfile_ape_items_current = &$thisfile_ape['items'][$item_key]; + + $thisfile_ape_items_current['offset'] = $thisfile_ape['tag_offset_start'] + $offset; + + $offset += ($ItemKeyLength + 1); // skip 0x00 terminator + $thisfile_ape_items_current['data'] = substr($APEtagData, $offset, $value_size); + $offset += $value_size; + + $thisfile_ape_items_current['flags'] = $this->parseAPEtagFlags($item_flags); + switch ($thisfile_ape_items_current['flags']['item_contents_raw']) { + case 0: // UTF-8 + case 3: // Locator (URL, filename, etc), UTF-8 encoded + $thisfile_ape_items_current['data'] = explode("\x00", trim($thisfile_ape_items_current['data'])); + break; + + default: // binary data + break; + } + + switch (strtolower($item_key)) { + case 'replaygain_track_gain': + $thisfile_replaygain['track']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $thisfile_replaygain['track']['originator'] = 'unspecified'; + break; + + case 'replaygain_track_peak': + $thisfile_replaygain['track']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $thisfile_replaygain['track']['originator'] = 'unspecified'; + if ($thisfile_replaygain['track']['peak'] <= 0) { + $info['warning'][] = 'ReplayGain Track peak from APEtag appears invalid: '.$thisfile_replaygain['track']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; + } + break; + + case 'replaygain_album_gain': + $thisfile_replaygain['album']['adjustment'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $thisfile_replaygain['album']['originator'] = 'unspecified'; + break; + + case 'replaygain_album_peak': + $thisfile_replaygain['album']['peak'] = (float) str_replace(',', '.', $thisfile_ape_items_current['data'][0]); // float casting will see "0,95" as zero! + $thisfile_replaygain['album']['originator'] = 'unspecified'; + if ($thisfile_replaygain['album']['peak'] <= 0) { + $info['warning'][] = 'ReplayGain Album peak from APEtag appears invalid: '.$thisfile_replaygain['album']['peak'].' (original value = "'.$thisfile_ape_items_current['data'][0].'")'; + } + break; + + case 'mp3gain_undo': + list($mp3gain_undo_left, $mp3gain_undo_right, $mp3gain_undo_wrap) = explode(',', $thisfile_ape_items_current['data'][0]); + $thisfile_replaygain['mp3gain']['undo_left'] = intval($mp3gain_undo_left); + $thisfile_replaygain['mp3gain']['undo_right'] = intval($mp3gain_undo_right); + $thisfile_replaygain['mp3gain']['undo_wrap'] = (($mp3gain_undo_wrap == 'Y') ? true : false); + break; + + case 'mp3gain_minmax': + list($mp3gain_globalgain_min, $mp3gain_globalgain_max) = explode(',', $thisfile_ape_items_current['data'][0]); + $thisfile_replaygain['mp3gain']['globalgain_track_min'] = intval($mp3gain_globalgain_min); + $thisfile_replaygain['mp3gain']['globalgain_track_max'] = intval($mp3gain_globalgain_max); + break; + + case 'mp3gain_album_minmax': + list($mp3gain_globalgain_album_min, $mp3gain_globalgain_album_max) = explode(',', $thisfile_ape_items_current['data'][0]); + $thisfile_replaygain['mp3gain']['globalgain_album_min'] = intval($mp3gain_globalgain_album_min); + $thisfile_replaygain['mp3gain']['globalgain_album_max'] = intval($mp3gain_globalgain_album_max); + break; + + case 'tracknumber': + if (is_array($thisfile_ape_items_current['data'])) { + foreach ($thisfile_ape_items_current['data'] as $comment) { + $thisfile_ape['comments']['track'][] = $comment; + } + } + break; + + case 'cover art (artist)': + case 'cover art (back)': + case 'cover art (band logo)': + case 'cover art (band)': + case 'cover art (colored fish)': + case 'cover art (composer)': + case 'cover art (conductor)': + case 'cover art (front)': + case 'cover art (icon)': + case 'cover art (illustration)': + case 'cover art (lead)': + case 'cover art (leaflet)': + case 'cover art (lyricist)': + case 'cover art (media)': + case 'cover art (movie scene)': + case 'cover art (other icon)': + case 'cover art (other)': + case 'cover art (performance)': + case 'cover art (publisher logo)': + case 'cover art (recording)': + case 'cover art (studio)': + // list of possible cover arts from http://taglib-sharp.sourcearchive.com/documentation/2.0.3.0-2/Ape_2Tag_8cs-source.html + list($thisfile_ape_items_current['filename'], $thisfile_ape_items_current['data']) = explode("\x00", $thisfile_ape_items_current['data'], 2); + $thisfile_ape_items_current['data_offset'] = $thisfile_ape_items_current['offset'] + strlen($thisfile_ape_items_current['filename']."\x00"); + $thisfile_ape_items_current['data_length'] = strlen($thisfile_ape_items_current['data']); + + $thisfile_ape_items_current['image_mime'] = ''; + $imageinfo = array(); + $imagechunkcheck = getid3_lib::GetDataImageSize($thisfile_ape_items_current['data'], $imageinfo); + $thisfile_ape_items_current['image_mime'] = image_type_to_mime_type($imagechunkcheck[2]); + + do { + if ($this->inline_attachments === false) { + // skip entirely + unset($thisfile_ape_items_current['data']); + break; + } + if ($this->inline_attachments === true) { + // great + } elseif (is_int($this->inline_attachments)) { + if ($this->inline_attachments < $thisfile_ape_items_current['data_length']) { + // too big, skip + $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' is too large to process inline ('.number_format($thisfile_ape_items_current['data_length']).' bytes)'; + unset($thisfile_ape_items_current['data']); + break; + } + } elseif (is_string($this->inline_attachments)) { + $this->inline_attachments = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->inline_attachments), DIRECTORY_SEPARATOR); + if (!is_dir($this->inline_attachments) || !is_writable($this->inline_attachments)) { + // cannot write, skip + $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$this->inline_attachments.'" (not writable)'; + unset($thisfile_ape_items_current['data']); + break; + } + } + // if we get this far, must be OK + if (is_string($this->inline_attachments)) { + $destination_filename = $this->inline_attachments.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$thisfile_ape_items_current['data_offset']; + if (!file_exists($destination_filename) || is_writable($destination_filename)) { + file_put_contents($destination_filename, $thisfile_ape_items_current['data']); + } else { + $info['warning'][] = 'attachment at '.$thisfile_ape_items_current['offset'].' cannot be saved to "'.$destination_filename.'" (not writable)'; + } + $thisfile_ape_items_current['data_filename'] = $destination_filename; + unset($thisfile_ape_items_current['data']); + } else { + if (!isset($info['ape']['comments']['picture'])) { + $info['ape']['comments']['picture'] = array(); + } + $info['ape']['comments']['picture'][] = array('data'=>$thisfile_ape_items_current['data'], 'image_mime'=>$thisfile_ape_items_current['image_mime']); + } + } while (false); + break; + + default: + if (is_array($thisfile_ape_items_current['data'])) { + foreach ($thisfile_ape_items_current['data'] as $comment) { + $thisfile_ape['comments'][strtolower($item_key)][] = $comment; + } + } + break; + } + + } + if (empty($thisfile_replaygain)) { + unset($info['replay_gain']); + } + return true; + } + + public function parseAPEheaderFooter($APEheaderFooterData) { + // http://www.uni-jena.de/~pfk/mpp/sv8/apeheader.html + + // shortcut + $headerfooterinfo['raw'] = array(); + $headerfooterinfo_raw = &$headerfooterinfo['raw']; + + $headerfooterinfo_raw['footer_tag'] = substr($APEheaderFooterData, 0, 8); + if ($headerfooterinfo_raw['footer_tag'] != 'APETAGEX') { + return false; + } + $headerfooterinfo_raw['version'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 8, 4)); + $headerfooterinfo_raw['tagsize'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 12, 4)); + $headerfooterinfo_raw['tag_items'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 16, 4)); + $headerfooterinfo_raw['global_flags'] = getid3_lib::LittleEndian2Int(substr($APEheaderFooterData, 20, 4)); + $headerfooterinfo_raw['reserved'] = substr($APEheaderFooterData, 24, 8); + + $headerfooterinfo['tag_version'] = $headerfooterinfo_raw['version'] / 1000; + if ($headerfooterinfo['tag_version'] >= 2) { + $headerfooterinfo['flags'] = $this->parseAPEtagFlags($headerfooterinfo_raw['global_flags']); + } + return $headerfooterinfo; + } + + public function parseAPEtagFlags($rawflagint) { + // "Note: APE Tags 1.0 do not use any of the APE Tag flags. + // All are set to zero on creation and ignored on reading." + // http://www.uni-jena.de/~pfk/mpp/sv8/apetagflags.html + $flags['header'] = (bool) ($rawflagint & 0x80000000); + $flags['footer'] = (bool) ($rawflagint & 0x40000000); + $flags['this_is_header'] = (bool) ($rawflagint & 0x20000000); + $flags['item_contents_raw'] = ($rawflagint & 0x00000006) >> 1; + $flags['read_only'] = (bool) ($rawflagint & 0x00000001); + + $flags['item_contents'] = $this->APEcontentTypeFlagLookup($flags['item_contents_raw']); + + return $flags; + } + + public function APEcontentTypeFlagLookup($contenttypeid) { + static $APEcontentTypeFlagLookup = array( + 0 => 'utf-8', + 1 => 'binary', + 2 => 'external', + 3 => 'reserved' + ); + return (isset($APEcontentTypeFlagLookup[$contenttypeid]) ? $APEcontentTypeFlagLookup[$contenttypeid] : 'invalid'); + } + + public function APEtagItemIsUTF8Lookup($itemkey) { + static $APEtagItemIsUTF8Lookup = array( + 'title', + 'subtitle', + 'artist', + 'album', + 'debut album', + 'publisher', + 'conductor', + 'track', + 'composer', + 'comment', + 'copyright', + 'publicationright', + 'file', + 'year', + 'record date', + 'record location', + 'genre', + 'media', + 'related', + 'isrc', + 'abstract', + 'language', + 'bibliography' + ); + return in_array(strtolower($itemkey), $APEtagItemIsUTF8Lookup); + } + +} diff --git a/app/libs/vendor/getid3/module.tag.id3v1.php b/app/libs/vendor/getid3/module.tag.id3v1.php index 8ef3a251..fd9069e0 100644 --- a/app/libs/vendor/getid3/module.tag.id3v1.php +++ b/app/libs/vendor/getid3/module.tag.id3v1.php @@ -1,359 +1,359 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.tag.id3v1.php // -// module for analyzing ID3v1 tags // -// dependencies: NONE // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_id3v1 extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - if (!getid3_lib::intValueSupported($info['filesize'])) { - $info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - - fseek($this->getid3->fp, -256, SEEK_END); - $preid3v1 = fread($this->getid3->fp, 128); - $id3v1tag = fread($this->getid3->fp, 128); - - if (substr($id3v1tag, 0, 3) == 'TAG') { - - $info['avdataend'] = $info['filesize'] - 128; - - $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30)); - $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30)); - $ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30)); - $ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4)); - $ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them - $ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1)); - - // If second-last byte of comment field is null and last byte of comment field is non-null - // then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number - if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) { - $ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1)); - $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28); - } - $ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']); - - $ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']); - if (!empty($ParsedID3v1['genre'])) { - unset($ParsedID3v1['genreid']); - } - if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) { - unset($ParsedID3v1['genre']); - } - - foreach ($ParsedID3v1 as $key => $value) { - $ParsedID3v1['comments'][$key][0] = $value; - } - - // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces - $GoodFormatID3v1tag = $this->GenerateID3v1Tag( - $ParsedID3v1['title'], - $ParsedID3v1['artist'], - $ParsedID3v1['album'], - $ParsedID3v1['year'], - (isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false), - $ParsedID3v1['comment'], - (!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : '')); - $ParsedID3v1['padding_valid'] = true; - if ($id3v1tag !== $GoodFormatID3v1tag) { - $ParsedID3v1['padding_valid'] = false; - $info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding'; - } - - $ParsedID3v1['tag_offset_end'] = $info['filesize']; - $ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128; - - $info['id3v1'] = $ParsedID3v1; - } - - if (substr($preid3v1, 0, 3) == 'TAG') { - // The way iTunes handles tags is, well, brain-damaged. - // It completely ignores v1 if ID3v2 is present. - // This goes as far as adding a new v1 tag *even if there already is one* - - // A suspected double-ID3v1 tag has been detected, but it could be that - // the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag - if (substr($preid3v1, 96, 8) == 'APETAGEX') { - // an APE tag footer was found before the last ID3v1, assume false "TAG" synch - } elseif (substr($preid3v1, 119, 6) == 'LYRICS') { - // a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch - } else { - // APE and Lyrics3 footers not found - assume double ID3v1 - $info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes'; - $info['avdataend'] -= 128; - } - } - - return true; - } - - public static function cutfield($str) { - return trim(substr($str, 0, strcspn($str, "\x00"))); - } - - public static function ArrayOfGenres($allowSCMPXextended=false) { - static $GenreLookup = array( - 0 => 'Blues', - 1 => 'Classic Rock', - 2 => 'Country', - 3 => 'Dance', - 4 => 'Disco', - 5 => 'Funk', - 6 => 'Grunge', - 7 => 'Hip-Hop', - 8 => 'Jazz', - 9 => 'Metal', - 10 => 'New Age', - 11 => 'Oldies', - 12 => 'Other', - 13 => 'Pop', - 14 => 'R&B', - 15 => 'Rap', - 16 => 'Reggae', - 17 => 'Rock', - 18 => 'Techno', - 19 => 'Industrial', - 20 => 'Alternative', - 21 => 'Ska', - 22 => 'Death Metal', - 23 => 'Pranks', - 24 => 'Soundtrack', - 25 => 'Euro-Techno', - 26 => 'Ambient', - 27 => 'Trip-Hop', - 28 => 'Vocal', - 29 => 'Jazz+Funk', - 30 => 'Fusion', - 31 => 'Trance', - 32 => 'Classical', - 33 => 'Instrumental', - 34 => 'Acid', - 35 => 'House', - 36 => 'Game', - 37 => 'Sound Clip', - 38 => 'Gospel', - 39 => 'Noise', - 40 => 'Alt. Rock', - 41 => 'Bass', - 42 => 'Soul', - 43 => 'Punk', - 44 => 'Space', - 45 => 'Meditative', - 46 => 'Instrumental Pop', - 47 => 'Instrumental Rock', - 48 => 'Ethnic', - 49 => 'Gothic', - 50 => 'Darkwave', - 51 => 'Techno-Industrial', - 52 => 'Electronic', - 53 => 'Pop-Folk', - 54 => 'Eurodance', - 55 => 'Dream', - 56 => 'Southern Rock', - 57 => 'Comedy', - 58 => 'Cult', - 59 => 'Gangsta Rap', - 60 => 'Top 40', - 61 => 'Christian Rap', - 62 => 'Pop/Funk', - 63 => 'Jungle', - 64 => 'Native American', - 65 => 'Cabaret', - 66 => 'New Wave', - 67 => 'Psychedelic', - 68 => 'Rave', - 69 => 'Showtunes', - 70 => 'Trailer', - 71 => 'Lo-Fi', - 72 => 'Tribal', - 73 => 'Acid Punk', - 74 => 'Acid Jazz', - 75 => 'Polka', - 76 => 'Retro', - 77 => 'Musical', - 78 => 'Rock & Roll', - 79 => 'Hard Rock', - 80 => 'Folk', - 81 => 'Folk/Rock', - 82 => 'National Folk', - 83 => 'Swing', - 84 => 'Fast-Fusion', - 85 => 'Bebob', - 86 => 'Latin', - 87 => 'Revival', - 88 => 'Celtic', - 89 => 'Bluegrass', - 90 => 'Avantgarde', - 91 => 'Gothic Rock', - 92 => 'Progressive Rock', - 93 => 'Psychedelic Rock', - 94 => 'Symphonic Rock', - 95 => 'Slow Rock', - 96 => 'Big Band', - 97 => 'Chorus', - 98 => 'Easy Listening', - 99 => 'Acoustic', - 100 => 'Humour', - 101 => 'Speech', - 102 => 'Chanson', - 103 => 'Opera', - 104 => 'Chamber Music', - 105 => 'Sonata', - 106 => 'Symphony', - 107 => 'Booty Bass', - 108 => 'Primus', - 109 => 'Porn Groove', - 110 => 'Satire', - 111 => 'Slow Jam', - 112 => 'Club', - 113 => 'Tango', - 114 => 'Samba', - 115 => 'Folklore', - 116 => 'Ballad', - 117 => 'Power Ballad', - 118 => 'Rhythmic Soul', - 119 => 'Freestyle', - 120 => 'Duet', - 121 => 'Punk Rock', - 122 => 'Drum Solo', - 123 => 'A Cappella', - 124 => 'Euro-House', - 125 => 'Dance Hall', - 126 => 'Goa', - 127 => 'Drum & Bass', - 128 => 'Club-House', - 129 => 'Hardcore', - 130 => 'Terror', - 131 => 'Indie', - 132 => 'BritPop', - 133 => 'Negerpunk', - 134 => 'Polsk Punk', - 135 => 'Beat', - 136 => 'Christian Gangsta Rap', - 137 => 'Heavy Metal', - 138 => 'Black Metal', - 139 => 'Crossover', - 140 => 'Contemporary Christian', - 141 => 'Christian Rock', - 142 => 'Merengue', - 143 => 'Salsa', - 144 => 'Thrash Metal', - 145 => 'Anime', - 146 => 'JPop', - 147 => 'Synthpop', - - 255 => 'Unknown', - - 'CR' => 'Cover', - 'RX' => 'Remix' - ); - - static $GenreLookupSCMPX = array(); - if ($allowSCMPXextended && empty($GenreLookupSCMPX)) { - $GenreLookupSCMPX = $GenreLookup; - // http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended - // Extended ID3v1 genres invented by SCMPX - // Note that 255 "Japanese Anime" conflicts with standard "Unknown" - $GenreLookupSCMPX[240] = 'Sacred'; - $GenreLookupSCMPX[241] = 'Northern Europe'; - $GenreLookupSCMPX[242] = 'Irish & Scottish'; - $GenreLookupSCMPX[243] = 'Scotland'; - $GenreLookupSCMPX[244] = 'Ethnic Europe'; - $GenreLookupSCMPX[245] = 'Enka'; - $GenreLookupSCMPX[246] = 'Children\'s Song'; - $GenreLookupSCMPX[247] = 'Japanese Sky'; - $GenreLookupSCMPX[248] = 'Japanese Heavy Rock'; - $GenreLookupSCMPX[249] = 'Japanese Doom Rock'; - $GenreLookupSCMPX[250] = 'Japanese J-POP'; - $GenreLookupSCMPX[251] = 'Japanese Seiyu'; - $GenreLookupSCMPX[252] = 'Japanese Ambient Techno'; - $GenreLookupSCMPX[253] = 'Japanese Moemoe'; - $GenreLookupSCMPX[254] = 'Japanese Tokusatsu'; - //$GenreLookupSCMPX[255] = 'Japanese Anime'; - } - - return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup); - } - - public static function LookupGenreName($genreid, $allowSCMPXextended=true) { - switch ($genreid) { - case 'RX': - case 'CR': - break; - default: - if (!is_numeric($genreid)) { - return false; - } - $genreid = intval($genreid); // to handle 3 or '3' or '03' - break; - } - $GenreLookup = self::ArrayOfGenres($allowSCMPXextended); - return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false); - } - - public static function LookupGenreID($genre, $allowSCMPXextended=false) { - $GenreLookup = self::ArrayOfGenres($allowSCMPXextended); - $LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre)); - foreach ($GenreLookup as $key => $value) { - if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) { - return $key; - } - } - return false; - } - - public static function StandardiseID3v1GenreName($OriginalGenre) { - if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) { - return self::LookupGenreName($GenreID); - } - return $OriginalGenre; - } - - public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') { - $ID3v1Tag = 'TAG'; - $ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT); - $ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT); - $ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT); - $ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT); - if (!empty($track) && ($track > 0) && ($track <= 255)) { - $ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT); - $ID3v1Tag .= "\x00"; - if (gettype($track) == 'string') { - $track = (int) $track; - } - $ID3v1Tag .= chr($track); - } else { - $ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT); - } - if (($genreid < 0) || ($genreid > 147)) { - $genreid = 255; // 'unknown' genre - } - switch (gettype($genreid)) { - case 'string': - case 'integer': - $ID3v1Tag .= chr(intval($genreid)); - break; - default: - $ID3v1Tag .= chr(255); // 'unknown' genre - break; - } - - return $ID3v1Tag; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.tag.id3v1.php // +// module for analyzing ID3v1 tags // +// dependencies: NONE // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_id3v1 extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + if (!getid3_lib::intValueSupported($info['filesize'])) { + $info['warning'][] = 'Unable to check for ID3v1 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + + fseek($this->getid3->fp, -256, SEEK_END); + $preid3v1 = fread($this->getid3->fp, 128); + $id3v1tag = fread($this->getid3->fp, 128); + + if (substr($id3v1tag, 0, 3) == 'TAG') { + + $info['avdataend'] = $info['filesize'] - 128; + + $ParsedID3v1['title'] = $this->cutfield(substr($id3v1tag, 3, 30)); + $ParsedID3v1['artist'] = $this->cutfield(substr($id3v1tag, 33, 30)); + $ParsedID3v1['album'] = $this->cutfield(substr($id3v1tag, 63, 30)); + $ParsedID3v1['year'] = $this->cutfield(substr($id3v1tag, 93, 4)); + $ParsedID3v1['comment'] = substr($id3v1tag, 97, 30); // can't remove nulls yet, track detection depends on them + $ParsedID3v1['genreid'] = ord(substr($id3v1tag, 127, 1)); + + // If second-last byte of comment field is null and last byte of comment field is non-null + // then this is ID3v1.1 and the comment field is 28 bytes long and the 30th byte is the track number + if (($id3v1tag{125} === "\x00") && ($id3v1tag{126} !== "\x00")) { + $ParsedID3v1['track'] = ord(substr($ParsedID3v1['comment'], 29, 1)); + $ParsedID3v1['comment'] = substr($ParsedID3v1['comment'], 0, 28); + } + $ParsedID3v1['comment'] = $this->cutfield($ParsedID3v1['comment']); + + $ParsedID3v1['genre'] = $this->LookupGenreName($ParsedID3v1['genreid']); + if (!empty($ParsedID3v1['genre'])) { + unset($ParsedID3v1['genreid']); + } + if (isset($ParsedID3v1['genre']) && (empty($ParsedID3v1['genre']) || ($ParsedID3v1['genre'] == 'Unknown'))) { + unset($ParsedID3v1['genre']); + } + + foreach ($ParsedID3v1 as $key => $value) { + $ParsedID3v1['comments'][$key][0] = $value; + } + + // ID3v1 data is supposed to be padded with NULL characters, but some taggers pad with spaces + $GoodFormatID3v1tag = $this->GenerateID3v1Tag( + $ParsedID3v1['title'], + $ParsedID3v1['artist'], + $ParsedID3v1['album'], + $ParsedID3v1['year'], + (isset($ParsedID3v1['genre']) ? $this->LookupGenreID($ParsedID3v1['genre']) : false), + $ParsedID3v1['comment'], + (!empty($ParsedID3v1['track']) ? $ParsedID3v1['track'] : '')); + $ParsedID3v1['padding_valid'] = true; + if ($id3v1tag !== $GoodFormatID3v1tag) { + $ParsedID3v1['padding_valid'] = false; + $info['warning'][] = 'Some ID3v1 fields do not use NULL characters for padding'; + } + + $ParsedID3v1['tag_offset_end'] = $info['filesize']; + $ParsedID3v1['tag_offset_start'] = $ParsedID3v1['tag_offset_end'] - 128; + + $info['id3v1'] = $ParsedID3v1; + } + + if (substr($preid3v1, 0, 3) == 'TAG') { + // The way iTunes handles tags is, well, brain-damaged. + // It completely ignores v1 if ID3v2 is present. + // This goes as far as adding a new v1 tag *even if there already is one* + + // A suspected double-ID3v1 tag has been detected, but it could be that + // the "TAG" identifier is a legitimate part of an APE or Lyrics3 tag + if (substr($preid3v1, 96, 8) == 'APETAGEX') { + // an APE tag footer was found before the last ID3v1, assume false "TAG" synch + } elseif (substr($preid3v1, 119, 6) == 'LYRICS') { + // a Lyrics3 tag footer was found before the last ID3v1, assume false "TAG" synch + } else { + // APE and Lyrics3 footers not found - assume double ID3v1 + $info['warning'][] = 'Duplicate ID3v1 tag detected - this has been known to happen with iTunes'; + $info['avdataend'] -= 128; + } + } + + return true; + } + + public static function cutfield($str) { + return trim(substr($str, 0, strcspn($str, "\x00"))); + } + + public static function ArrayOfGenres($allowSCMPXextended=false) { + static $GenreLookup = array( + 0 => 'Blues', + 1 => 'Classic Rock', + 2 => 'Country', + 3 => 'Dance', + 4 => 'Disco', + 5 => 'Funk', + 6 => 'Grunge', + 7 => 'Hip-Hop', + 8 => 'Jazz', + 9 => 'Metal', + 10 => 'New Age', + 11 => 'Oldies', + 12 => 'Other', + 13 => 'Pop', + 14 => 'R&B', + 15 => 'Rap', + 16 => 'Reggae', + 17 => 'Rock', + 18 => 'Techno', + 19 => 'Industrial', + 20 => 'Alternative', + 21 => 'Ska', + 22 => 'Death Metal', + 23 => 'Pranks', + 24 => 'Soundtrack', + 25 => 'Euro-Techno', + 26 => 'Ambient', + 27 => 'Trip-Hop', + 28 => 'Vocal', + 29 => 'Jazz+Funk', + 30 => 'Fusion', + 31 => 'Trance', + 32 => 'Classical', + 33 => 'Instrumental', + 34 => 'Acid', + 35 => 'House', + 36 => 'Game', + 37 => 'Sound Clip', + 38 => 'Gospel', + 39 => 'Noise', + 40 => 'Alt. Rock', + 41 => 'Bass', + 42 => 'Soul', + 43 => 'Punk', + 44 => 'Space', + 45 => 'Meditative', + 46 => 'Instrumental Pop', + 47 => 'Instrumental Rock', + 48 => 'Ethnic', + 49 => 'Gothic', + 50 => 'Darkwave', + 51 => 'Techno-Industrial', + 52 => 'Electronic', + 53 => 'Pop-Folk', + 54 => 'Eurodance', + 55 => 'Dream', + 56 => 'Southern Rock', + 57 => 'Comedy', + 58 => 'Cult', + 59 => 'Gangsta Rap', + 60 => 'Top 40', + 61 => 'Christian Rap', + 62 => 'Pop/Funk', + 63 => 'Jungle', + 64 => 'Native American', + 65 => 'Cabaret', + 66 => 'New Wave', + 67 => 'Psychedelic', + 68 => 'Rave', + 69 => 'Showtunes', + 70 => 'Trailer', + 71 => 'Lo-Fi', + 72 => 'Tribal', + 73 => 'Acid Punk', + 74 => 'Acid Jazz', + 75 => 'Polka', + 76 => 'Retro', + 77 => 'Musical', + 78 => 'Rock & Roll', + 79 => 'Hard Rock', + 80 => 'Folk', + 81 => 'Folk/Rock', + 82 => 'National Folk', + 83 => 'Swing', + 84 => 'Fast-Fusion', + 85 => 'Bebob', + 86 => 'Latin', + 87 => 'Revival', + 88 => 'Celtic', + 89 => 'Bluegrass', + 90 => 'Avantgarde', + 91 => 'Gothic Rock', + 92 => 'Progressive Rock', + 93 => 'Psychedelic Rock', + 94 => 'Symphonic Rock', + 95 => 'Slow Rock', + 96 => 'Big Band', + 97 => 'Chorus', + 98 => 'Easy Listening', + 99 => 'Acoustic', + 100 => 'Humour', + 101 => 'Speech', + 102 => 'Chanson', + 103 => 'Opera', + 104 => 'Chamber Music', + 105 => 'Sonata', + 106 => 'Symphony', + 107 => 'Booty Bass', + 108 => 'Primus', + 109 => 'Porn Groove', + 110 => 'Satire', + 111 => 'Slow Jam', + 112 => 'Club', + 113 => 'Tango', + 114 => 'Samba', + 115 => 'Folklore', + 116 => 'Ballad', + 117 => 'Power Ballad', + 118 => 'Rhythmic Soul', + 119 => 'Freestyle', + 120 => 'Duet', + 121 => 'Punk Rock', + 122 => 'Drum Solo', + 123 => 'A Cappella', + 124 => 'Euro-House', + 125 => 'Dance Hall', + 126 => 'Goa', + 127 => 'Drum & Bass', + 128 => 'Club-House', + 129 => 'Hardcore', + 130 => 'Terror', + 131 => 'Indie', + 132 => 'BritPop', + 133 => 'Negerpunk', + 134 => 'Polsk Punk', + 135 => 'Beat', + 136 => 'Christian Gangsta Rap', + 137 => 'Heavy Metal', + 138 => 'Black Metal', + 139 => 'Crossover', + 140 => 'Contemporary Christian', + 141 => 'Christian Rock', + 142 => 'Merengue', + 143 => 'Salsa', + 144 => 'Thrash Metal', + 145 => 'Anime', + 146 => 'JPop', + 147 => 'Synthpop', + + 255 => 'Unknown', + + 'CR' => 'Cover', + 'RX' => 'Remix' + ); + + static $GenreLookupSCMPX = array(); + if ($allowSCMPXextended && empty($GenreLookupSCMPX)) { + $GenreLookupSCMPX = $GenreLookup; + // http://www.geocities.co.jp/SiliconValley-Oakland/3664/alittle.html#GenreExtended + // Extended ID3v1 genres invented by SCMPX + // Note that 255 "Japanese Anime" conflicts with standard "Unknown" + $GenreLookupSCMPX[240] = 'Sacred'; + $GenreLookupSCMPX[241] = 'Northern Europe'; + $GenreLookupSCMPX[242] = 'Irish & Scottish'; + $GenreLookupSCMPX[243] = 'Scotland'; + $GenreLookupSCMPX[244] = 'Ethnic Europe'; + $GenreLookupSCMPX[245] = 'Enka'; + $GenreLookupSCMPX[246] = 'Children\'s Song'; + $GenreLookupSCMPX[247] = 'Japanese Sky'; + $GenreLookupSCMPX[248] = 'Japanese Heavy Rock'; + $GenreLookupSCMPX[249] = 'Japanese Doom Rock'; + $GenreLookupSCMPX[250] = 'Japanese J-POP'; + $GenreLookupSCMPX[251] = 'Japanese Seiyu'; + $GenreLookupSCMPX[252] = 'Japanese Ambient Techno'; + $GenreLookupSCMPX[253] = 'Japanese Moemoe'; + $GenreLookupSCMPX[254] = 'Japanese Tokusatsu'; + //$GenreLookupSCMPX[255] = 'Japanese Anime'; + } + + return ($allowSCMPXextended ? $GenreLookupSCMPX : $GenreLookup); + } + + public static function LookupGenreName($genreid, $allowSCMPXextended=true) { + switch ($genreid) { + case 'RX': + case 'CR': + break; + default: + if (!is_numeric($genreid)) { + return false; + } + $genreid = intval($genreid); // to handle 3 or '3' or '03' + break; + } + $GenreLookup = self::ArrayOfGenres($allowSCMPXextended); + return (isset($GenreLookup[$genreid]) ? $GenreLookup[$genreid] : false); + } + + public static function LookupGenreID($genre, $allowSCMPXextended=false) { + $GenreLookup = self::ArrayOfGenres($allowSCMPXextended); + $LowerCaseNoSpaceSearchTerm = strtolower(str_replace(' ', '', $genre)); + foreach ($GenreLookup as $key => $value) { + if (strtolower(str_replace(' ', '', $value)) == $LowerCaseNoSpaceSearchTerm) { + return $key; + } + } + return false; + } + + public static function StandardiseID3v1GenreName($OriginalGenre) { + if (($GenreID = self::LookupGenreID($OriginalGenre)) !== false) { + return self::LookupGenreName($GenreID); + } + return $OriginalGenre; + } + + public static function GenerateID3v1Tag($title, $artist, $album, $year, $genreid, $comment, $track='') { + $ID3v1Tag = 'TAG'; + $ID3v1Tag .= str_pad(trim(substr($title, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(trim(substr($artist, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(trim(substr($album, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + $ID3v1Tag .= str_pad(trim(substr($year, 0, 4)), 4, "\x00", STR_PAD_LEFT); + if (!empty($track) && ($track > 0) && ($track <= 255)) { + $ID3v1Tag .= str_pad(trim(substr($comment, 0, 28)), 28, "\x00", STR_PAD_RIGHT); + $ID3v1Tag .= "\x00"; + if (gettype($track) == 'string') { + $track = (int) $track; + } + $ID3v1Tag .= chr($track); + } else { + $ID3v1Tag .= str_pad(trim(substr($comment, 0, 30)), 30, "\x00", STR_PAD_RIGHT); + } + if (($genreid < 0) || ($genreid > 147)) { + $genreid = 255; // 'unknown' genre + } + switch (gettype($genreid)) { + case 'string': + case 'integer': + $ID3v1Tag .= chr(intval($genreid)); + break; + default: + $ID3v1Tag .= chr(255); // 'unknown' genre + break; + } + + return $ID3v1Tag; + } + +} diff --git a/app/libs/vendor/getid3/module.tag.id3v2.php b/app/libs/vendor/getid3/module.tag.id3v2.php index aa71529f..b08f9f9a 100644 --- a/app/libs/vendor/getid3/module.tag.id3v2.php +++ b/app/libs/vendor/getid3/module.tag.id3v2.php @@ -1,3414 +1,3414 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -/// // -// module.tag.id3v2.php // -// module for analyzing ID3v2 tags // -// dependencies: module.tag.id3v1.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); - -class getid3_id3v2 extends getid3_handler -{ - public $StartingOffset = 0; - - public function Analyze() { - $info = &$this->getid3->info; - - // Overall tag structure: - // +-----------------------------+ - // | Header (10 bytes) | - // +-----------------------------+ - // | Extended Header | - // | (variable length, OPTIONAL) | - // +-----------------------------+ - // | Frames (variable length) | - // +-----------------------------+ - // | Padding | - // | (variable length, OPTIONAL) | - // +-----------------------------+ - // | Footer (10 bytes, OPTIONAL) | - // +-----------------------------+ - - // Header - // ID3v2/file identifier "ID3" - // ID3v2 version $04 00 - // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x) - // ID3v2 size 4 * %0xxxxxxx - - - // shortcuts - $info['id3v2']['header'] = true; - $thisfile_id3v2 = &$info['id3v2']; - $thisfile_id3v2['flags'] = array(); - $thisfile_id3v2_flags = &$thisfile_id3v2['flags']; - - - fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET); - $header = fread($this->getid3->fp, 10); - if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { - - $thisfile_id3v2['majorversion'] = ord($header{3}); - $thisfile_id3v2['minorversion'] = ord($header{4}); - - // shortcut - $id3v2_majorversion = &$thisfile_id3v2['majorversion']; - - } else { - - unset($info['id3v2']); - return false; - - } - - if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists) - - $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion']; - return false; - - } - - $id3_flags = ord($header{5}); - switch ($id3v2_majorversion) { - case 2: - // %ab000000 in v2.2 - $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation - $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression - break; - - case 3: - // %abc00000 in v2.3 - $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation - $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header - $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator - break; - - case 4: - // %abcd0000 in v2.4 - $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation - $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header - $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator - $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present - break; - } - - $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length - - $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset; - $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength']; - - - - // create 'encoding' key - used by getid3::HandleAllTags() - // in ID3v2 every field can have it's own encoding type - // so force everything to UTF-8 so it can be handled consistantly - $thisfile_id3v2['encoding'] = 'UTF-8'; - - - // Frames - - // All ID3v2 frames consists of one frame header followed by one or more - // fields containing the actual information. The header is always 10 - // bytes and laid out as follows: - // - // Frame ID $xx xx xx xx (four characters) - // Size 4 * %0xxxxxxx - // Flags $xx xx - - $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header - if (!empty($thisfile_id3v2['exthead']['length'])) { - $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4); - } - if (!empty($thisfile_id3v2_flags['isfooter'])) { - $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio - } - if ($sizeofframes > 0) { - - $framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable - - // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x) - if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) { - $framedata = $this->DeUnsynchronise($framedata); - } - // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead - // of on tag level, making it easier to skip frames, increasing the streamability - // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that - // there exists an unsynchronised frame, while the new unsynchronisation flag in - // the frame header [S:4.1.2] indicates unsynchronisation. - - - //$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present) - $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header - - - // Extended Header - if (!empty($thisfile_id3v2_flags['exthead'])) { - $extended_header_offset = 0; - - if ($id3v2_majorversion == 3) { - - // v2.3 definition: - //Extended header size $xx xx xx xx // 32-bit integer - //Extended Flags $xx xx - // %x0000000 %00000000 // v2.3 - // x - CRC data present - //Size of padding $xx xx xx xx - - $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0); - $extended_header_offset += 4; - - $thisfile_id3v2['exthead']['flag_bytes'] = 2; - $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes'])); - $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes']; - - $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000); - - $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4)); - $extended_header_offset += 4; - - if ($thisfile_id3v2['exthead']['flags']['crc']) { - $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4)); - $extended_header_offset += 4; - } - $extended_header_offset += $thisfile_id3v2['exthead']['padding_size']; - - } elseif ($id3v2_majorversion == 4) { - - // v2.4 definition: - //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer - //Number of flag bytes $01 - //Extended Flags $xx - // %0bcd0000 // v2.4 - // b - Tag is an update - // Flag data length $00 - // c - CRC data present - // Flag data length $05 - // Total frame CRC 5 * %0xxxxxxx - // d - Tag restrictions - // Flag data length $01 - - $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true); - $extended_header_offset += 4; - - $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1 - $extended_header_offset += 1; - - $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes'])); - $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes']; - - $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40); - $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20); - $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10); - - if ($thisfile_id3v2['exthead']['flags']['update']) { - $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0 - $extended_header_offset += 1; - } - - if ($thisfile_id3v2['exthead']['flags']['crc']) { - $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5 - $extended_header_offset += 1; - $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false); - $extended_header_offset += $ext_header_chunk_length; - } - - if ($thisfile_id3v2['exthead']['flags']['restrictions']) { - $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1 - $extended_header_offset += 1; - - // %ppqrrstt - $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); - $extended_header_offset += 1; - $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions - $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions - $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions - $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions - $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions - - $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']); - $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']); - $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']); - $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']); - $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']); - } - - if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) { - $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')'; - } - } - - $framedataoffset += $extended_header_offset; - $framedata = substr($framedata, $extended_header_offset); - } // end extended header - - - while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse - if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) { - // insufficient room left in ID3v2 header for actual data - must be padding - $thisfile_id3v2['padding']['start'] = $framedataoffset; - $thisfile_id3v2['padding']['length'] = strlen($framedata); - $thisfile_id3v2['padding']['valid'] = true; - for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) { - if ($framedata{$i} != "\x00") { - $thisfile_id3v2['padding']['valid'] = false; - $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; - $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'; - break; - } - } - break; // skip rest of ID3v2 header - } - if ($id3v2_majorversion == 2) { - // Frame ID $xx xx xx (three characters) - // Size $xx xx xx (24-bit integer) - // Flags $xx xx - - $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header - $framedata = substr($framedata, 6); // and leave the rest in $framedata - $frame_name = substr($frame_header, 0, 3); - $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0); - $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs - - } elseif ($id3v2_majorversion > 2) { - - // Frame ID $xx xx xx xx (four characters) - // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+) - // Flags $xx xx - - $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header - $framedata = substr($framedata, 10); // and leave the rest in $framedata - - $frame_name = substr($frame_header, 0, 4); - if ($id3v2_majorversion == 3) { - $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer - } else { // ID3v2.4+ - $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value) - } - - if ($frame_size < (strlen($framedata) + 4)) { - $nextFrameID = substr($framedata, $frame_size, 4); - if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) { - // next frame is OK - } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) { - // MP3ext known broken frames - "ok" for the purposes of this test - } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) { - $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3'; - $id3v2_majorversion = 3; - $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer - } - } - - - $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2)); - } - - if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) { - // padding encountered - - $thisfile_id3v2['padding']['start'] = $framedataoffset; - $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata); - $thisfile_id3v2['padding']['valid'] = true; - - $len = strlen($framedata); - for ($i = 0; $i < $len; $i++) { - if ($framedata{$i} != "\x00") { - $thisfile_id3v2['padding']['valid'] = false; - $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; - $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'; - break; - } - } - break; // skip rest of ID3v2 header - } - - if ($frame_name == 'COM ') { - $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]'; - $frame_name = 'COMM'; - } - if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) { - - unset($parsedFrame); - $parsedFrame['frame_name'] = $frame_name; - $parsedFrame['frame_flags_raw'] = $frame_flags; - $parsedFrame['data'] = substr($framedata, 0, $frame_size); - $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size); - $parsedFrame['dataoffset'] = $framedataoffset; - - $this->ParseID3v2Frame($parsedFrame); - $thisfile_id3v2[$frame_name][] = $parsedFrame; - - $framedata = substr($framedata, $frame_size); - - } else { // invalid frame length or FrameID - - if ($frame_size <= strlen($framedata)) { - - if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) { - - // next frame is valid, just skip the current frame - $framedata = substr($framedata, $frame_size); - $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.'; - - } else { - - // next frame is invalid too, abort processing - //unset($framedata); - $framedata = null; - $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.'; - - } - - } elseif ($frame_size == strlen($framedata)) { - - // this is the last frame, just skip - $info['warning'][] = 'This was the last ID3v2 frame.'; - - } else { - - // next frame is invalid too, abort processing - //unset($framedata); - $framedata = null; - $info['warning'][] = 'Invalid ID3v2 frame size, aborting.'; - - } - if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) { - - switch ($frame_name) { - case "\x00\x00".'MP': - case "\x00".'MP3': - case ' MP3': - case 'MP3e': - case "\x00".'MP': - case ' MP': - case 'MP3': - $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]'; - break; - - default: - $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).'; - break; - } - - } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) { - - $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).'; - - } else { - - $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).'; - - } - - } - $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion)); - - } - - } - - - // Footer - - // The footer is a copy of the header, but with a different identifier. - // ID3v2 identifier "3DI" - // ID3v2 version $04 00 - // ID3v2 flags %abcd0000 - // ID3v2 size 4 * %0xxxxxxx - - if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) { - $footer = fread($this->getid3->fp, 10); - if (substr($footer, 0, 3) == '3DI') { - $thisfile_id3v2['footer'] = true; - $thisfile_id3v2['majorversion_footer'] = ord($footer{3}); - $thisfile_id3v2['minorversion_footer'] = ord($footer{4}); - } - if ($thisfile_id3v2['majorversion_footer'] <= 4) { - $id3_flags = ord(substr($footer{5})); - $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80); - $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40); - $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20); - $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10); - - $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1); - } - } // end footer - - if (isset($thisfile_id3v2['comments']['genre'])) { - foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) { - unset($thisfile_id3v2['comments']['genre'][$key]); - $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value))); - } - } - - if (isset($thisfile_id3v2['comments']['track'])) { - foreach ($thisfile_id3v2['comments']['track'] as $key => $value) { - if (strstr($value, '/')) { - list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]); - } - } - } - - if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) { - $thisfile_id3v2['comments']['year'] = array($matches[1]); - } - - - if (!empty($thisfile_id3v2['TXXX'])) { - // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames - foreach ($thisfile_id3v2['TXXX'] as $txxx_array) { - switch ($txxx_array['description']) { - case 'replaygain_track_gain': - if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) { - $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data']))); - } - break; - case 'replaygain_track_peak': - if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) { - $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']); - } - break; - case 'replaygain_album_gain': - if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) { - $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data']))); - } - break; - } - } - } - - - // Set avdataoffset - $info['avdataoffset'] = $thisfile_id3v2['headerlength']; - if (isset($thisfile_id3v2['footer'])) { - $info['avdataoffset'] += 10; - } - - return true; - } - - - public function ParseID3v2GenreString($genrestring) { - // Parse genres into arrays of genreName and genreID - // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)' - // ID3v2.4.x: '21' $00 'Eurodisco' $00 - $clean_genres = array(); - if (strpos($genrestring, "\x00") === false) { - $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring); - } - $genre_elements = explode("\x00", $genrestring); - foreach ($genre_elements as $element) { - $element = trim($element); - if ($element) { - if (preg_match('#^[0-9]{1,3}#', $element)) { - $clean_genres[] = getid3_id3v1::LookupGenreName($element); - } else { - $clean_genres[] = str_replace('((', '(', $element); - } - } - } - return $clean_genres; - } - - - public function ParseID3v2Frame(&$parsedFrame) { - - // shortcuts - $info = &$this->getid3->info; - $id3v2_majorversion = $info['id3v2']['majorversion']; - - $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']); - if (empty($parsedFrame['framenamelong'])) { - unset($parsedFrame['framenamelong']); - } - $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']); - if (empty($parsedFrame['framenameshort'])) { - unset($parsedFrame['framenameshort']); - } - - if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard - if ($id3v2_majorversion == 3) { - // Frame Header Flags - // %abc00000 %ijk00000 - $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation - $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation - $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only - $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression - $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption - $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity - - } elseif ($id3v2_majorversion == 4) { - // Frame Header Flags - // %0abc0000 %0h00kmnp - $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation - $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation - $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only - $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity - $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression - $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption - $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation - $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator - - // Frame-level de-unsynchronisation - ID3v2.4 - if ($parsedFrame['flags']['Unsynchronisation']) { - $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']); - } - - if ($parsedFrame['flags']['DataLengthIndicator']) { - $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1); - $parsedFrame['data'] = substr($parsedFrame['data'], 4); - } - } - - // Frame-level de-compression - if ($parsedFrame['flags']['compression']) { - $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4)); - if (!function_exists('gzuncompress')) { - $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"'; - } else { - if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) { - //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) { - $parsedFrame['data'] = $decompresseddata; - unset($decompresseddata); - } else { - $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"'; - } - } - } - } - - if (!empty($parsedFrame['flags']['DataLengthIndicator'])) { - if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) { - $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data'; - } - } - - if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) { - - $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion'; - switch ($parsedFrame['frame_name']) { - case 'WCOM': - $warning .= ' (this is known to happen with files tagged by RioPort)'; - break; - - default: - break; - } - $info['warning'][] = $warning; - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier - // There may be more than one 'UFID' frame in a tag, - // but only one with the same 'Owner identifier'. - //
    - // Owner identifier $00 - // Identifier - $exploded = explode("\x00", $parsedFrame['data'], 2); - $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : ''); - $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : ''); - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame - // There may be more than one 'TXXX' frame in each tag, - // but only one with the same description. - //
    - // Text encoding $xx - // Description $00 (00) - // Value - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['description'] = $frame_description; - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data'])); - } - //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain - - - } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame - // There may only be one text information frame of its kind in an tag. - //
    - // Text encoding $xx - // Information - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with / - // This of course breaks when an artist name contains slash character, e.g. "AC/DC" - // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense - // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user - switch ($parsedFrame['encoding']) { - case 'UTF-16': - case 'UTF-16BE': - case 'UTF-16LE': - $wordsize = 2; - break; - case 'ISO-8859-1': - case 'UTF-8': - default: - $wordsize = 1; - break; - } - $Txxx_elements = array(); - $Txxx_elements_start_offset = 0; - for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) { - if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) { - $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset); - $Txxx_elements_start_offset = $i + $wordsize; - } - } - $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset); - foreach ($Txxx_elements as $Txxx_element) { - $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element); - if (!empty($string)) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string; - } - } - unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset); - } - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame - // There may be more than one 'WXXX' frame in each tag, - // but only one with the same description - //
    - // Text encoding $xx - // Description $00 (00) - // URL - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding)); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - if ($frame_terminatorpos) { - // there are null bytes after the data - this is not according to spec - // only use data up to first null byte - $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos); - } else { - // no null bytes following data, just use all data - $frame_urldata = (string) $parsedFrame['data']; - } - - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['url'] = $frame_urldata; - $parsedFrame['description'] = $frame_description; - if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']); - } - unset($parsedFrame['data']); - - - } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames - // There may only be one URL link frame of its kind in a tag, - // except when stated otherwise in the frame description - //
    - // URL - - $parsedFrame['url'] = trim($parsedFrame['data']); - if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url']; - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only) - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only) - // http://id3.org/id3v2.3.0#sec4.4 - // There may only be one 'IPL' frame in each tag - //
    - // Text encoding $xx - // People list strings - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']); - $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset); - - // http://www.getid3.org/phpBB3/viewtopic.php?t=1369 - // "this tag typically contains null terminated strings, which are associated in pairs" - // "there are users that use the tag incorrectly" - $IPLS_parts = array(); - if (strpos($parsedFrame['data_raw'], "\x00") !== false) { - $IPLS_parts_unsorted = array(); - if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) { - // UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding - $thisILPS = ''; - for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) { - $twobytes = substr($parsedFrame['data_raw'], $i, 2); - if ($twobytes === "\x00\x00") { - $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS); - $thisILPS = ''; - } else { - $thisILPS .= $twobytes; - } - } - if (strlen($thisILPS) > 2) { // 2-byte BOM - $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS); - } - } else { - // ISO-8859-1 or UTF-8 or other single-byte-null character set - $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']); - } - if (count($IPLS_parts_unsorted) == 1) { - // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson" - foreach ($IPLS_parts_unsorted as $key => $value) { - $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value); - $position = ''; - foreach ($IPLS_parts_sorted as $person) { - $IPLS_parts[] = array('position'=>$position, 'person'=>$person); - } - } - } elseif ((count($IPLS_parts_unsorted) % 2) == 0) { - $position = ''; - $person = ''; - foreach ($IPLS_parts_unsorted as $key => $value) { - if (($key % 2) == 0) { - $position = $value; - } else { - $person = $value; - $IPLS_parts[] = array('position'=>$position, 'person'=>$person); - $position = ''; - $person = ''; - } - } - } else { - foreach ($IPLS_parts_unsorted as $key => $value) { - $IPLS_parts[] = array($value); - } - } - - } else { - $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']); - } - $parsedFrame['data'] = $IPLS_parts; - - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data']; - } - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier - // There may only be one 'MCDI' frame in each tag - //
    - // CD TOC - - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data']; - } - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes - // There may only be one 'ETCO' frame in each tag - //
    - // Time stamp format $xx - // Where time stamp format is: - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - // Followed by a list of key events in the following format: - // Type of event $xx - // Time stamp $xx (xx ...) - // The 'Time stamp' is set to zero if directly at the beginning of the sound - // or after the previous event. All events MUST be sorted in chronological order. - - $frame_offset = 0; - $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - - while ($frame_offset < strlen($parsedFrame['data'])) { - $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1); - $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']); - $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - $frame_offset += 4; - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table - // There may only be one 'MLLT' frame in each tag - //
    - // MPEG frames between reference $xx xx - // Bytes between reference $xx xx xx - // Milliseconds between reference $xx xx xx - // Bits for bytes deviation $xx - // Bits for milliseconds dev. $xx - // Then for every reference the following data is included; - // Deviation in bytes %xxx.... - // Deviation in milliseconds %xxx.... - - $frame_offset = 0; - $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2)); - $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3)); - $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3)); - $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1)); - $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1)); - $parsedFrame['data'] = substr($parsedFrame['data'], 10); - while ($frame_offset < strlen($parsedFrame['data'])) { - $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); - } - $reference_counter = 0; - while (strlen($deviationbitstream) > 0) { - $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation'])); - $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation'])); - $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']); - $reference_counter++; - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes - // There may only be one 'SYTC' frame in each tag - //
    - // Time stamp format $xx - // Tempo data - // Where time stamp format is: - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - - $frame_offset = 0; - $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $timestamp_counter = 0; - while ($frame_offset < strlen($parsedFrame['data'])) { - $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ($parsedFrame[$timestamp_counter]['tempo'] == 255) { - $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1)); - } - $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - $frame_offset += 4; - $timestamp_counter++; - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription - // There may be more than one 'Unsynchronised lyrics/text transcription' frame - // in each tag, but only one with the same language and content descriptor. - //
    - // Text encoding $xx - // Language $xx xx xx - // Content descriptor $00 (00) - // Lyrics/text - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_language = substr($parsedFrame['data'], $frame_offset, 3); - $frame_offset += 3; - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['data'] = $parsedFrame['data']; - $parsedFrame['language'] = $frame_language; - $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); - $parsedFrame['description'] = $frame_description; - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text - // There may be more than one 'SYLT' frame in each tag, - // but only one with the same language and content descriptor. - //
    - // Text encoding $xx - // Language $xx xx xx - // Time stamp format $xx - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - // Content type $xx - // Content descriptor $00 (00) - // Terminated text to be synced (typically a syllable) - // Sync identifier (terminator to above string) $00 (00) - // Time stamp $xx (xx ...) - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_language = substr($parsedFrame['data'], $frame_offset, 3); - $frame_offset += 3; - $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']); - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['language'] = $frame_language; - $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); - - $timestampindex = 0; - $frame_remainingdata = substr($parsedFrame['data'], $frame_offset); - while (strlen($frame_remainingdata)) { - $frame_offset = 0; - $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding)); - if ($frame_terminatorpos === false) { - $frame_remainingdata = ''; - } else { - if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); - - $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) { - // timestamp probably omitted for first data item - } else { - $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4)); - $frame_remainingdata = substr($frame_remainingdata, 4); - } - $timestampindex++; - } - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments - // There may be more than one comment frame in each tag, - // but only one with the same language and content descriptor. - //
    - // Text encoding $xx - // Language $xx xx xx - // Short content descrip. $00 (00) - // The actual text - - if (strlen($parsedFrame['data']) < 5) { - - $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset']; - - } else { - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_language = substr($parsedFrame['data'], $frame_offset, 3); - $frame_offset += 3; - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['language'] = $frame_language; - $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); - $parsedFrame['description'] = $frame_description; - $parsedFrame['data'] = $frame_text; - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); - } - - } - - } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) - // There may be more than one 'RVA2' frame in each tag, - // but only one with the same identification string - //
    - // Identification $00 - // The 'identification' string is used to identify the situation and/or - // device where this adjustment should apply. The following is then - // repeated for every channel: - // Type of channel $xx - // Volume adjustment $xx xx - // Bits representing peak $xx - // Peak volume $xx (xx ...) - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00"); - $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos); - if (ord($frame_idstring) === 0) { - $frame_idstring = ''; - } - $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00")); - $parsedFrame['description'] = $frame_idstring; - $RVA2channelcounter = 0; - while (strlen($frame_remainingdata) >= 5) { - $frame_offset = 0; - $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1)); - $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid; - $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid); - $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed - $frame_offset += 2; - $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1)); - if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) { - $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value'; - break; - } - $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8); - $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume)); - $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume); - $RVA2channelcounter++; - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only) - // There may only be one 'RVA' frame in each tag - //
    - // ID3v2.2 => Increment/decrement %000000ba - // ID3v2.3 => Increment/decrement %00fedcba - // Bits used for volume descr. $xx - // Relative volume change, right $xx xx (xx ...) // a - // Relative volume change, left $xx xx (xx ...) // b - // Peak volume right $xx xx (xx ...) - // Peak volume left $xx xx (xx ...) - // ID3v2.3 only, optional (not present in ID3v2.2): - // Relative volume change, right back $xx xx (xx ...) // c - // Relative volume change, left back $xx xx (xx ...) // d - // Peak volume right back $xx xx (xx ...) - // Peak volume left back $xx xx (xx ...) - // ID3v2.3 only, optional (not present in ID3v2.2): - // Relative volume change, center $xx xx (xx ...) // e - // Peak volume center $xx xx (xx ...) - // ID3v2.3 only, optional (not present in ID3v2.2): - // Relative volume change, bass $xx xx (xx ...) // f - // Peak volume bass $xx xx (xx ...) - - $frame_offset = 0; - $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1); - $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1); - $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8); - $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['right'] === false) { - $parsedFrame['volumechange']['right'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['left'] === false) { - $parsedFrame['volumechange']['left'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - if ($id3v2_majorversion == 3) { - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); - if (strlen($parsedFrame['data']) > 0) { - $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1); - $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1); - $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['rightrear'] === false) { - $parsedFrame['volumechange']['rightrear'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['leftrear'] === false) { - $parsedFrame['volumechange']['leftrear'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - } - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); - if (strlen($parsedFrame['data']) > 0) { - $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1); - $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['center'] === false) { - $parsedFrame['volumechange']['center'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - } - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); - if (strlen($parsedFrame['data']) > 0) { - $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1); - $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - if ($parsedFrame['incdec']['bass'] === false) { - $parsedFrame['volumechange']['bass'] *= -1; - } - $frame_offset += $frame_bytesvolume; - $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); - $frame_offset += $frame_bytesvolume; - } - } - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) - // There may be more than one 'EQU2' frame in each tag, - // but only one with the same identification string - //
    - // Interpolation method $xx - // $00 Band - // $01 Linear - // Identification $00 - // The following is then repeated for every adjustment point - // Frequency $xx xx - // Volume adjustment $xx xx - - $frame_offset = 0; - $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_idstring) === 0) { - $frame_idstring = ''; - } - $parsedFrame['description'] = $frame_idstring; - $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00")); - while (strlen($frame_remainingdata)) { - $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2; - $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true); - $frame_remainingdata = substr($frame_remainingdata, 4); - } - $parsedFrame['interpolationmethod'] = $frame_interpolationmethod; - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only) - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only) - // There may only be one 'EQUA' frame in each tag - //
    - // Adjustment bits $xx - // This is followed by 2 bytes + ('adjustment bits' rounded up to the - // nearest byte) for every equalisation band in the following format, - // giving a frequency range of 0 - 32767Hz: - // Increment/decrement %x (MSB of the Frequency) - // Frequency (lower 15 bits) - // Adjustment $xx (xx ...) - - $frame_offset = 0; - $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1); - $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8); - - $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset); - while (strlen($frame_remainingdata) > 0) { - $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2)); - $frame_incdec = (bool) substr($frame_frequencystr, 0, 1); - $frame_frequency = bindec(substr($frame_frequencystr, 1, 15)); - $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec; - $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes)); - if ($parsedFrame[$frame_frequency]['incdec'] === false) { - $parsedFrame[$frame_frequency]['adjustment'] *= -1; - } - $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes); - } - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb - // There may only be one 'RVRB' frame in each tag. - //
    - // Reverb left (ms) $xx xx - // Reverb right (ms) $xx xx - // Reverb bounces, left $xx - // Reverb bounces, right $xx - // Reverb feedback, left to left $xx - // Reverb feedback, left to right $xx - // Reverb feedback, right to right $xx - // Reverb feedback, right to left $xx - // Premix left to right $xx - // Premix right to left $xx - - $frame_offset = 0; - $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture - // There may be several pictures attached to one file, - // each in their individual 'APIC' frame, but only one - // with the same content descriptor - //
    - // Text encoding $xx - // ID3v2.3+ => MIME type $00 - // ID3v2.2 => Image format $xx xx xx - // Picture type $xx - // Description $00 (00) - // Picture data - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - - if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) { - $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3); - if (strtolower($frame_imagetype) == 'ima') { - // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted - // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net) - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { - $frame_mimetype = ''; - } - $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype))); - if ($frame_imagetype == 'JPEG') { - $frame_imagetype = 'JPG'; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - } else { - $frame_offset += 3; - } - } - if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) { - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { - $frame_mimetype = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - } - - $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - - if ($frame_offset >= $parsedFrame['datalength']) { - $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset); - } else { - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - if ($id3v2_majorversion == 2) { - $parsedFrame['imagetype'] = $frame_imagetype; - } else { - $parsedFrame['mime'] = $frame_mimetype; - } - $parsedFrame['picturetypeid'] = $frame_picturetype; - $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype); - $parsedFrame['description'] = $frame_description; - $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); - $parsedFrame['datalength'] = strlen($parsedFrame['data']); - - $parsedFrame['image_mime'] = ''; - $imageinfo = array(); - $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo); - if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { - $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]); - if ($imagechunkcheck[0]) { - $parsedFrame['image_width'] = $imagechunkcheck[0]; - } - if ($imagechunkcheck[1]) { - $parsedFrame['image_height'] = $imagechunkcheck[1]; - } - } - - do { - if ($this->getid3->option_save_attachments === false) { - // skip entirely - unset($parsedFrame['data']); - break; - } - if ($this->getid3->option_save_attachments === true) { - // great -/* - } elseif (is_int($this->getid3->option_save_attachments)) { - if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) { - // too big, skip - $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)'; - unset($parsedFrame['data']); - break; - } -*/ - } elseif (is_string($this->getid3->option_save_attachments)) { - $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); - if (!is_dir($dir) || !is_writable($dir)) { - // cannot write, skip - $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)'; - unset($parsedFrame['data']); - break; - } - } - // if we get this far, must be OK - if (is_string($this->getid3->option_save_attachments)) { - $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset; - if (!file_exists($destination_filename) || is_writable($destination_filename)) { - file_put_contents($destination_filename, $parsedFrame['data']); - } else { - $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)'; - } - $parsedFrame['data_filename'] = $destination_filename; - unset($parsedFrame['data']); - } else { - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - if (!isset($info['id3v2']['comments']['picture'])) { - $info['id3v2']['comments']['picture'] = array(); - } - $info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']); - } - } - } while (false); - } - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object - // There may be more than one 'GEOB' frame in each tag, - // but only one with the same content descriptor - //
    - // Text encoding $xx - // MIME type $00 - // Filename $00 (00) - // Content description $00 (00) - // Encapsulated object - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_mimetype) === 0) { - $frame_mimetype = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_filename) === 0) { - $frame_filename = ''; - } - $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); - - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); - - $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset); - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['mime'] = $frame_mimetype; - $parsedFrame['filename'] = $frame_filename; - $parsedFrame['description'] = $frame_description; - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter - // There may only be one 'PCNT' frame in each tag. - // When the counter reaches all one's, one byte is inserted in - // front of the counter thus making the counter eight bits bigger - //
    - // Counter $xx xx xx xx (xx ...) - - $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter - // There may be more than one 'POPM' frame in each tag, - // but only one with the same email address - //
    - // Email to user $00 - // Rating $xx - // Counter $xx xx xx xx (xx ...) - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_emailaddress) === 0) { - $frame_emailaddress = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset)); - $parsedFrame['email'] = $frame_emailaddress; - $parsedFrame['rating'] = $frame_rating; - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size - // There may only be one 'RBUF' frame in each tag - //
    - // Buffer size $xx xx xx - // Embedded info flag %0000000x - // Offset to next tag $xx xx xx xx - - $frame_offset = 0; - $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3)); - $frame_offset += 3; - - $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1); - $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only) - // There may be more than one 'CRM' frame in a tag, - // but only one with the same 'owner identifier' - //
    - // Owner identifier $00 (00) - // Content/explanation $00 (00) - // Encrypted datablock - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $parsedFrame['ownerid'] = $frame_ownerid; - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - $parsedFrame['description'] = $frame_description; - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption - // There may be more than one 'AENC' frames in a tag, - // but only one with the same 'Owner identifier' - //
    - // Owner identifier $00 - // Preview start $xx xx - // Preview length $xx xx - // Encryption info - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { - $frame_ownerid == ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - $parsedFrame['ownerid'] = $frame_ownerid; - $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset); - unset($parsedFrame['data']); - - - } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information - (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information - // There may be more than one 'LINK' frame in a tag, - // but only one with the same contents - //
    - // ID3v2.3+ => Frame identifier $xx xx xx xx - // ID3v2.2 => Frame identifier $xx xx xx - // URL $00 - // ID and additional data - - $frame_offset = 0; - if ($id3v2_majorversion == 2) { - $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3); - $frame_offset += 3; - } else { - $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4); - $frame_offset += 4; - } - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_url) === 0) { - $frame_url = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - $parsedFrame['url'] = $frame_url; - - $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset); - if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']); - } - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) - // There may only be one 'POSS' frame in each tag - //
    - // Time stamp format $xx - // Position $xx (xx ...) - - $frame_offset = 0; - $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset)); - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only) - // There may be more than one 'Terms of use' frame in a tag, - // but only one with the same 'Language' - //
    - // Text encoding $xx - // Language $xx xx xx - // The actual text - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $frame_language = substr($parsedFrame['data'], $frame_offset, 3); - $frame_offset += 3; - $parsedFrame['language'] = $frame_language; - $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { - $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); - } - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only) - // There may only be one 'OWNE' frame in a tag - //
    - // Text encoding $xx - // Price paid $00 - // Date of purch. - // Seller - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3); - $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']); - $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3); - - $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8); - if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) { - $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4)); - } - $frame_offset += 8; - - $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset); - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only) - // There may be more than one 'commercial frame' in a tag, - // but no two may be identical - //
    - // Text encoding $xx - // Price string $00 - // Valid until - // Contact URL $00 - // Received as $xx - // Name of seller $00 (00) - // Description $00 (00) - // Picture MIME type $00 - // Seller logo - - $frame_offset = 0; - $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { - $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; - } - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - $frame_offset = $frame_terminatorpos + strlen("\x00"); - $frame_rawpricearray = explode('/', $frame_pricestring); - foreach ($frame_rawpricearray as $key => $val) { - $frame_currencyid = substr($val, 0, 3); - $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid); - $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3); - } - - $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8); - $frame_offset += 8; - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_sellername) === 0) { - $frame_sellername = ''; - } - $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); - - $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); - if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { - $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 - } - $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_description) === 0) { - $frame_description = ''; - } - $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); - - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset); - - $parsedFrame['encodingid'] = $frame_textencoding; - $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); - - $parsedFrame['pricevaliduntil'] = $frame_datestring; - $parsedFrame['contacturl'] = $frame_contacturl; - $parsedFrame['receivedasid'] = $frame_receivedasid; - $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid); - $parsedFrame['sellername'] = $frame_sellername; - $parsedFrame['description'] = $frame_description; - $parsedFrame['mime'] = $frame_mimetype; - $parsedFrame['logo'] = $frame_sellerlogo; - unset($parsedFrame['data']); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only) - // There may be several 'ENCR' frames in a tag, - // but only one containing the same symbol - // and only one containing the same owner identifier - //
    - // Owner identifier $00 - // Method symbol $xx - // Encryption data - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { - $frame_ownerid = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $parsedFrame['ownerid'] = $frame_ownerid; - $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only) - - // There may be several 'GRID' frames in a tag, - // but only one containing the same symbol - // and only one containing the same owner identifier - //
    - // Owner identifier $00 - // Group symbol $xx - // Group dependent data - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { - $frame_ownerid = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $parsedFrame['ownerid'] = $frame_ownerid; - $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only) - // The tag may contain more than one 'PRIV' frame - // but only with different contents - //
    - // Owner identifier $00 - // The private data - - $frame_offset = 0; - $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); - $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); - if (ord($frame_ownerid) === 0) { - $frame_ownerid = ''; - } - $frame_offset = $frame_terminatorpos + strlen("\x00"); - - $parsedFrame['ownerid'] = $frame_ownerid; - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - - - } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only) - // There may be more than one 'signature frame' in a tag, - // but no two may be identical - //
    - // Group symbol $xx - // Signature - - $frame_offset = 0; - $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); - - - } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only) - // There may only be one 'seek frame' in a tag - //
    - // Minimum offset to next tag $xx xx xx xx - - $frame_offset = 0; - $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - - - } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only) - // There may only be one 'audio seek point index' frame in a tag - //
    - // Indexed data start (S) $xx xx xx xx - // Indexed data length (L) $xx xx xx xx - // Number of index points (N) $xx xx - // Bits per index point (b) $xx - // Then for every index point the following data is included: - // Fraction at index (Fi) $xx (xx) - - $frame_offset = 0; - $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - $frame_offset += 4; - $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); - $frame_offset += 4; - $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); - $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8); - for ($i = 0; $i < $frame_indexpoints; $i++) { - $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint)); - $frame_offset += $frame_bytesperpoint; - } - unset($parsedFrame['data']); - - } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment - // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html - // There may only be one 'RGAD' frame in a tag - //
    - // Peak Amplitude $xx $xx $xx $xx - // Radio Replay Gain Adjustment %aaabbbcd %dddddddd - // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd - // a - name code - // b - originator code - // c - sign bit - // d - replay gain adjustment - - $frame_offset = 0; - $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4)); - $frame_offset += 4; - $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); - $frame_offset += 2; - $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3)); - $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3)); - $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1)); - $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9)); - $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3)); - $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3)); - $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1)); - $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9)); - $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']); - $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']); - $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']); - $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']); - $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']); - $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']); - - $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude']; - $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator']; - $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment']; - $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator']; - $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment']; - - unset($parsedFrame['data']); - - } - - return true; - } - - - public function DeUnsynchronise($data) { - return str_replace("\xFF\x00", "\xFF", $data); - } - - public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) { - static $LookupExtendedHeaderRestrictionsTagSizeLimits = array( - 0x00 => 'No more than 128 frames and 1 MB total tag size', - 0x01 => 'No more than 64 frames and 128 KB total tag size', - 0x02 => 'No more than 32 frames and 40 KB total tag size', - 0x03 => 'No more than 32 frames and 4 KB total tag size', - ); - return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : ''); - } - - public function LookupExtendedHeaderRestrictionsTextEncodings($index) { - static $LookupExtendedHeaderRestrictionsTextEncodings = array( - 0x00 => 'No restrictions', - 0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8', - ); - return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : ''); - } - - public function LookupExtendedHeaderRestrictionsTextFieldSize($index) { - static $LookupExtendedHeaderRestrictionsTextFieldSize = array( - 0x00 => 'No restrictions', - 0x01 => 'No string is longer than 1024 characters', - 0x02 => 'No string is longer than 128 characters', - 0x03 => 'No string is longer than 30 characters', - ); - return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : ''); - } - - public function LookupExtendedHeaderRestrictionsImageEncoding($index) { - static $LookupExtendedHeaderRestrictionsImageEncoding = array( - 0x00 => 'No restrictions', - 0x01 => 'Images are encoded only with PNG or JPEG', - ); - return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : ''); - } - - public function LookupExtendedHeaderRestrictionsImageSizeSize($index) { - static $LookupExtendedHeaderRestrictionsImageSizeSize = array( - 0x00 => 'No restrictions', - 0x01 => 'All images are 256x256 pixels or smaller', - 0x02 => 'All images are 64x64 pixels or smaller', - 0x03 => 'All images are exactly 64x64 pixels, unless required otherwise', - ); - return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : ''); - } - - public function LookupCurrencyUnits($currencyid) { - - $begin = __LINE__; - - /** This is not a comment! - - - AED Dirhams - AFA Afghanis - ALL Leke - AMD Drams - ANG Guilders - AOA Kwanza - ARS Pesos - ATS Schillings - AUD Dollars - AWG Guilders - AZM Manats - BAM Convertible Marka - BBD Dollars - BDT Taka - BEF Francs - BGL Leva - BHD Dinars - BIF Francs - BMD Dollars - BND Dollars - BOB Bolivianos - BRL Brazil Real - BSD Dollars - BTN Ngultrum - BWP Pulas - BYR Rubles - BZD Dollars - CAD Dollars - CDF Congolese Francs - CHF Francs - CLP Pesos - CNY Yuan Renminbi - COP Pesos - CRC Colones - CUP Pesos - CVE Escudos - CYP Pounds - CZK Koruny - DEM Deutsche Marks - DJF Francs - DKK Kroner - DOP Pesos - DZD Algeria Dinars - EEK Krooni - EGP Pounds - ERN Nakfa - ESP Pesetas - ETB Birr - EUR Euro - FIM Markkaa - FJD Dollars - FKP Pounds - FRF Francs - GBP Pounds - GEL Lari - GGP Pounds - GHC Cedis - GIP Pounds - GMD Dalasi - GNF Francs - GRD Drachmae - GTQ Quetzales - GYD Dollars - HKD Dollars - HNL Lempiras - HRK Kuna - HTG Gourdes - HUF Forints - IDR Rupiahs - IEP Pounds - ILS New Shekels - IMP Pounds - INR Rupees - IQD Dinars - IRR Rials - ISK Kronur - ITL Lire - JEP Pounds - JMD Dollars - JOD Dinars - JPY Yen - KES Shillings - KGS Soms - KHR Riels - KMF Francs - KPW Won - KWD Dinars - KYD Dollars - KZT Tenge - LAK Kips - LBP Pounds - LKR Rupees - LRD Dollars - LSL Maloti - LTL Litai - LUF Francs - LVL Lati - LYD Dinars - MAD Dirhams - MDL Lei - MGF Malagasy Francs - MKD Denars - MMK Kyats - MNT Tugriks - MOP Patacas - MRO Ouguiyas - MTL Liri - MUR Rupees - MVR Rufiyaa - MWK Kwachas - MXN Pesos - MYR Ringgits - MZM Meticais - NAD Dollars - NGN Nairas - NIO Gold Cordobas - NLG Guilders - NOK Krone - NPR Nepal Rupees - NZD Dollars - OMR Rials - PAB Balboa - PEN Nuevos Soles - PGK Kina - PHP Pesos - PKR Rupees - PLN Zlotych - PTE Escudos - PYG Guarani - QAR Rials - ROL Lei - RUR Rubles - RWF Rwanda Francs - SAR Riyals - SBD Dollars - SCR Rupees - SDD Dinars - SEK Kronor - SGD Dollars - SHP Pounds - SIT Tolars - SKK Koruny - SLL Leones - SOS Shillings - SPL Luigini - SRG Guilders - STD Dobras - SVC Colones - SYP Pounds - SZL Emalangeni - THB Baht - TJR Rubles - TMM Manats - TND Dinars - TOP Pa'anga - TRL Liras - TTD Dollars - TVD Tuvalu Dollars - TWD New Dollars - TZS Shillings - UAH Hryvnia - UGX Shillings - USD Dollars - UYU Pesos - UZS Sums - VAL Lire - VEB Bolivares - VND Dong - VUV Vatu - WST Tala - XAF Francs - XAG Ounces - XAU Ounces - XCD Dollars - XDR Special Drawing Rights - XPD Ounces - XPF Francs - XPT Ounces - YER Rials - YUM New Dinars - ZAR Rand - ZMK Kwacha - ZWD Zimbabwe Dollars - - */ - - return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units'); - } - - - public function LookupCurrencyCountry($currencyid) { - - $begin = __LINE__; - - /** This is not a comment! - - AED United Arab Emirates - AFA Afghanistan - ALL Albania - AMD Armenia - ANG Netherlands Antilles - AOA Angola - ARS Argentina - ATS Austria - AUD Australia - AWG Aruba - AZM Azerbaijan - BAM Bosnia and Herzegovina - BBD Barbados - BDT Bangladesh - BEF Belgium - BGL Bulgaria - BHD Bahrain - BIF Burundi - BMD Bermuda - BND Brunei Darussalam - BOB Bolivia - BRL Brazil - BSD Bahamas - BTN Bhutan - BWP Botswana - BYR Belarus - BZD Belize - CAD Canada - CDF Congo/Kinshasa - CHF Switzerland - CLP Chile - CNY China - COP Colombia - CRC Costa Rica - CUP Cuba - CVE Cape Verde - CYP Cyprus - CZK Czech Republic - DEM Germany - DJF Djibouti - DKK Denmark - DOP Dominican Republic - DZD Algeria - EEK Estonia - EGP Egypt - ERN Eritrea - ESP Spain - ETB Ethiopia - EUR Euro Member Countries - FIM Finland - FJD Fiji - FKP Falkland Islands (Malvinas) - FRF France - GBP United Kingdom - GEL Georgia - GGP Guernsey - GHC Ghana - GIP Gibraltar - GMD Gambia - GNF Guinea - GRD Greece - GTQ Guatemala - GYD Guyana - HKD Hong Kong - HNL Honduras - HRK Croatia - HTG Haiti - HUF Hungary - IDR Indonesia - IEP Ireland (Eire) - ILS Israel - IMP Isle of Man - INR India - IQD Iraq - IRR Iran - ISK Iceland - ITL Italy - JEP Jersey - JMD Jamaica - JOD Jordan - JPY Japan - KES Kenya - KGS Kyrgyzstan - KHR Cambodia - KMF Comoros - KPW Korea - KWD Kuwait - KYD Cayman Islands - KZT Kazakstan - LAK Laos - LBP Lebanon - LKR Sri Lanka - LRD Liberia - LSL Lesotho - LTL Lithuania - LUF Luxembourg - LVL Latvia - LYD Libya - MAD Morocco - MDL Moldova - MGF Madagascar - MKD Macedonia - MMK Myanmar (Burma) - MNT Mongolia - MOP Macau - MRO Mauritania - MTL Malta - MUR Mauritius - MVR Maldives (Maldive Islands) - MWK Malawi - MXN Mexico - MYR Malaysia - MZM Mozambique - NAD Namibia - NGN Nigeria - NIO Nicaragua - NLG Netherlands (Holland) - NOK Norway - NPR Nepal - NZD New Zealand - OMR Oman - PAB Panama - PEN Peru - PGK Papua New Guinea - PHP Philippines - PKR Pakistan - PLN Poland - PTE Portugal - PYG Paraguay - QAR Qatar - ROL Romania - RUR Russia - RWF Rwanda - SAR Saudi Arabia - SBD Solomon Islands - SCR Seychelles - SDD Sudan - SEK Sweden - SGD Singapore - SHP Saint Helena - SIT Slovenia - SKK Slovakia - SLL Sierra Leone - SOS Somalia - SPL Seborga - SRG Suriname - STD São Tome and Principe - SVC El Salvador - SYP Syria - SZL Swaziland - THB Thailand - TJR Tajikistan - TMM Turkmenistan - TND Tunisia - TOP Tonga - TRL Turkey - TTD Trinidad and Tobago - TVD Tuvalu - TWD Taiwan - TZS Tanzania - UAH Ukraine - UGX Uganda - USD United States of America - UYU Uruguay - UZS Uzbekistan - VAL Vatican City - VEB Venezuela - VND Viet Nam - VUV Vanuatu - WST Samoa - XAF Communauté Financière Africaine - XAG Silver - XAU Gold - XCD East Caribbean - XDR International Monetary Fund - XPD Palladium - XPF Comptoirs Français du Pacifique - XPT Platinum - YER Yemen - YUM Yugoslavia - ZAR South Africa - ZMK Zambia - ZWD Zimbabwe - - */ - - return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country'); - } - - - - public static function LanguageLookup($languagecode, $casesensitive=false) { - - if (!$casesensitive) { - $languagecode = strtolower($languagecode); - } - - // http://www.id3.org/id3v2.4.0-structure.txt - // [4. ID3v2 frame overview] - // The three byte language field, present in several frames, is used to - // describe the language of the frame's content, according to ISO-639-2 - // [ISO-639-2]. The language should be represented in lower case. If the - // language is not known the string "XXX" should be used. - - - // ISO 639-2 - http://www.id3.org/iso639-2.html - - $begin = __LINE__; - - /** This is not a comment! - - XXX unknown - xxx unknown - aar Afar - abk Abkhazian - ace Achinese - ach Acoli - ada Adangme - afa Afro-Asiatic (Other) - afh Afrihili - afr Afrikaans - aka Akan - akk Akkadian - alb Albanian - ale Aleut - alg Algonquian Languages - amh Amharic - ang English, Old (ca. 450-1100) - apa Apache Languages - ara Arabic - arc Aramaic - arm Armenian - arn Araucanian - arp Arapaho - art Artificial (Other) - arw Arawak - asm Assamese - ath Athapascan Languages - ava Avaric - ave Avestan - awa Awadhi - aym Aymara - aze Azerbaijani - bad Banda - bai Bamileke Languages - bak Bashkir - bal Baluchi - bam Bambara - ban Balinese - baq Basque - bas Basa - bat Baltic (Other) - bej Beja - bel Byelorussian - bem Bemba - ben Bengali - ber Berber (Other) - bho Bhojpuri - bih Bihari - bik Bikol - bin Bini - bis Bislama - bla Siksika - bnt Bantu (Other) - bod Tibetan - bra Braj - bre Breton - bua Buriat - bug Buginese - bul Bulgarian - bur Burmese - cad Caddo - cai Central American Indian (Other) - car Carib - cat Catalan - cau Caucasian (Other) - ceb Cebuano - cel Celtic (Other) - ces Czech - cha Chamorro - chb Chibcha - che Chechen - chg Chagatai - chi Chinese - chm Mari - chn Chinook jargon - cho Choctaw - chr Cherokee - chu Church Slavic - chv Chuvash - chy Cheyenne - cop Coptic - cor Cornish - cos Corsican - cpe Creoles and Pidgins, English-based (Other) - cpf Creoles and Pidgins, French-based (Other) - cpp Creoles and Pidgins, Portuguese-based (Other) - cre Cree - crp Creoles and Pidgins (Other) - cus Cushitic (Other) - cym Welsh - cze Czech - dak Dakota - dan Danish - del Delaware - deu German - din Dinka - div Divehi - doi Dogri - dra Dravidian (Other) - dua Duala - dum Dutch, Middle (ca. 1050-1350) - dut Dutch - dyu Dyula - dzo Dzongkha - efi Efik - egy Egyptian (Ancient) - eka Ekajuk - ell Greek, Modern (1453-) - elx Elamite - eng English - enm English, Middle (ca. 1100-1500) - epo Esperanto - esk Eskimo (Other) - esl Spanish - est Estonian - eus Basque - ewe Ewe - ewo Ewondo - fan Fang - fao Faroese - fas Persian - fat Fanti - fij Fijian - fin Finnish - fiu Finno-Ugrian (Other) - fon Fon - fra French - fre French - frm French, Middle (ca. 1400-1600) - fro French, Old (842- ca. 1400) - fry Frisian - ful Fulah - gaa Ga - gae Gaelic (Scots) - gai Irish - gay Gayo - gdh Gaelic (Scots) - gem Germanic (Other) - geo Georgian - ger German - gez Geez - gil Gilbertese - glg Gallegan - gmh German, Middle High (ca. 1050-1500) - goh German, Old High (ca. 750-1050) - gon Gondi - got Gothic - grb Grebo - grc Greek, Ancient (to 1453) - gre Greek, Modern (1453-) - grn Guarani - guj Gujarati - hai Haida - hau Hausa - haw Hawaiian - heb Hebrew - her Herero - hil Hiligaynon - him Himachali - hin Hindi - hmo Hiri Motu - hun Hungarian - hup Hupa - hye Armenian - iba Iban - ibo Igbo - ice Icelandic - ijo Ijo - iku Inuktitut - ilo Iloko - ina Interlingua (International Auxiliary language Association) - inc Indic (Other) - ind Indonesian - ine Indo-European (Other) - ine Interlingue - ipk Inupiak - ira Iranian (Other) - iri Irish - iro Iroquoian uages - isl Icelandic - ita Italian - jav Javanese - jaw Javanese - jpn Japanese - jpr Judeo-Persian - jrb Judeo-Arabic - kaa Kara-Kalpak - kab Kabyle - kac Kachin - kal Greenlandic - kam Kamba - kan Kannada - kar Karen - kas Kashmiri - kat Georgian - kau Kanuri - kaw Kawi - kaz Kazakh - kha Khasi - khi Khoisan (Other) - khm Khmer - kho Khotanese - kik Kikuyu - kin Kinyarwanda - kir Kirghiz - kok Konkani - kom Komi - kon Kongo - kor Korean - kpe Kpelle - kro Kru - kru Kurukh - kua Kuanyama - kum Kumyk - kur Kurdish - kus Kusaie - kut Kutenai - lad Ladino - lah Lahnda - lam Lamba - lao Lao - lat Latin - lav Latvian - lez Lezghian - lin Lingala - lit Lithuanian - lol Mongo - loz Lozi - ltz Letzeburgesch - lub Luba-Katanga - lug Ganda - lui Luiseno - lun Lunda - luo Luo (Kenya and Tanzania) - mac Macedonian - mad Madurese - mag Magahi - mah Marshall - mai Maithili - mak Macedonian - mak Makasar - mal Malayalam - man Mandingo - mao Maori - map Austronesian (Other) - mar Marathi - mas Masai - max Manx - may Malay - men Mende - mga Irish, Middle (900 - 1200) - mic Micmac - min Minangkabau - mis Miscellaneous (Other) - mkh Mon-Kmer (Other) - mlg Malagasy - mlt Maltese - mni Manipuri - mno Manobo Languages - moh Mohawk - mol Moldavian - mon Mongolian - mos Mossi - mri Maori - msa Malay - mul Multiple Languages - mun Munda Languages - mus Creek - mwr Marwari - mya Burmese - myn Mayan Languages - nah Aztec - nai North American Indian (Other) - nau Nauru - nav Navajo - nbl Ndebele, South - nde Ndebele, North - ndo Ndongo - nep Nepali - new Newari - nic Niger-Kordofanian (Other) - niu Niuean - nla Dutch - nno Norwegian (Nynorsk) - non Norse, Old - nor Norwegian - nso Sotho, Northern - nub Nubian Languages - nya Nyanja - nym Nyamwezi - nyn Nyankole - nyo Nyoro - nzi Nzima - oci Langue d'Oc (post 1500) - oji Ojibwa - ori Oriya - orm Oromo - osa Osage - oss Ossetic - ota Turkish, Ottoman (1500 - 1928) - oto Otomian Languages - paa Papuan-Australian (Other) - pag Pangasinan - pal Pahlavi - pam Pampanga - pan Panjabi - pap Papiamento - pau Palauan - peo Persian, Old (ca 600 - 400 B.C.) - per Persian - phn Phoenician - pli Pali - pol Polish - pon Ponape - por Portuguese - pra Prakrit uages - pro Provencal, Old (to 1500) - pus Pushto - que Quechua - raj Rajasthani - rar Rarotongan - roa Romance (Other) - roh Rhaeto-Romance - rom Romany - ron Romanian - rum Romanian - run Rundi - rus Russian - sad Sandawe - sag Sango - sah Yakut - sai South American Indian (Other) - sal Salishan Languages - sam Samaritan Aramaic - san Sanskrit - sco Scots - scr Serbo-Croatian - sel Selkup - sem Semitic (Other) - sga Irish, Old (to 900) - shn Shan - sid Sidamo - sin Singhalese - sio Siouan Languages - sit Sino-Tibetan (Other) - sla Slavic (Other) - slk Slovak - slo Slovak - slv Slovenian - smi Sami Languages - smo Samoan - sna Shona - snd Sindhi - sog Sogdian - som Somali - son Songhai - sot Sotho, Southern - spa Spanish - sqi Albanian - srd Sardinian - srr Serer - ssa Nilo-Saharan (Other) - ssw Siswant - ssw Swazi - suk Sukuma - sun Sudanese - sus Susu - sux Sumerian - sve Swedish - swa Swahili - swe Swedish - syr Syriac - tah Tahitian - tam Tamil - tat Tatar - tel Telugu - tem Timne - ter Tereno - tgk Tajik - tgl Tagalog - tha Thai - tib Tibetan - tig Tigre - tir Tigrinya - tiv Tivi - tli Tlingit - tmh Tamashek - tog Tonga (Nyasa) - ton Tonga (Tonga Islands) - tru Truk - tsi Tsimshian - tsn Tswana - tso Tsonga - tuk Turkmen - tum Tumbuka - tur Turkish - tut Altaic (Other) - twi Twi - tyv Tuvinian - uga Ugaritic - uig Uighur - ukr Ukrainian - umb Umbundu - und Undetermined - urd Urdu - uzb Uzbek - vai Vai - ven Venda - vie Vietnamese - vol Volapük - vot Votic - wak Wakashan Languages - wal Walamo - war Waray - was Washo - wel Welsh - wen Sorbian Languages - wol Wolof - xho Xhosa - yao Yao - yap Yap - yid Yiddish - yor Yoruba - zap Zapotec - zen Zenaga - zha Zhuang - zho Chinese - zul Zulu - zun Zuni - - */ - - return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode'); - } - - - public static function ETCOEventLookup($index) { - if (($index >= 0x17) && ($index <= 0xDF)) { - return 'reserved for future use'; - } - if (($index >= 0xE0) && ($index <= 0xEF)) { - return 'not predefined synch 0-F'; - } - if (($index >= 0xF0) && ($index <= 0xFC)) { - return 'reserved for future use'; - } - - static $EventLookup = array( - 0x00 => 'padding (has no meaning)', - 0x01 => 'end of initial silence', - 0x02 => 'intro start', - 0x03 => 'main part start', - 0x04 => 'outro start', - 0x05 => 'outro end', - 0x06 => 'verse start', - 0x07 => 'refrain start', - 0x08 => 'interlude start', - 0x09 => 'theme start', - 0x0A => 'variation start', - 0x0B => 'key change', - 0x0C => 'time change', - 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)', - 0x0E => 'sustained noise', - 0x0F => 'sustained noise end', - 0x10 => 'intro end', - 0x11 => 'main part end', - 0x12 => 'verse end', - 0x13 => 'refrain end', - 0x14 => 'theme end', - 0x15 => 'profanity', - 0x16 => 'profanity end', - 0xFD => 'audio end (start of silence)', - 0xFE => 'audio file ends', - 0xFF => 'one more byte of events follows' - ); - - return (isset($EventLookup[$index]) ? $EventLookup[$index] : ''); - } - - public static function SYTLContentTypeLookup($index) { - static $SYTLContentTypeLookup = array( - 0x00 => 'other', - 0x01 => 'lyrics', - 0x02 => 'text transcription', - 0x03 => 'movement/part name', // (e.g. 'Adagio') - 0x04 => 'events', // (e.g. 'Don Quijote enters the stage') - 0x05 => 'chord', // (e.g. 'Bb F Fsus') - 0x06 => 'trivia/\'pop up\' information', - 0x07 => 'URLs to webpages', - 0x08 => 'URLs to images' - ); - - return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : ''); - } - - public static function APICPictureTypeLookup($index, $returnarray=false) { - static $APICPictureTypeLookup = array( - 0x00 => 'Other', - 0x01 => '32x32 pixels \'file icon\' (PNG only)', - 0x02 => 'Other file icon', - 0x03 => 'Cover (front)', - 0x04 => 'Cover (back)', - 0x05 => 'Leaflet page', - 0x06 => 'Media (e.g. label side of CD)', - 0x07 => 'Lead artist/lead performer/soloist', - 0x08 => 'Artist/performer', - 0x09 => 'Conductor', - 0x0A => 'Band/Orchestra', - 0x0B => 'Composer', - 0x0C => 'Lyricist/text writer', - 0x0D => 'Recording Location', - 0x0E => 'During recording', - 0x0F => 'During performance', - 0x10 => 'Movie/video screen capture', - 0x11 => 'A bright coloured fish', - 0x12 => 'Illustration', - 0x13 => 'Band/artist logotype', - 0x14 => 'Publisher/Studio logotype' - ); - if ($returnarray) { - return $APICPictureTypeLookup; - } - return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : ''); - } - - public static function COMRReceivedAsLookup($index) { - static $COMRReceivedAsLookup = array( - 0x00 => 'Other', - 0x01 => 'Standard CD album with other songs', - 0x02 => 'Compressed audio on CD', - 0x03 => 'File over the Internet', - 0x04 => 'Stream over the Internet', - 0x05 => 'As note sheets', - 0x06 => 'As note sheets in a book with other sheets', - 0x07 => 'Music on other media', - 0x08 => 'Non-musical merchandise' - ); - - return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : ''); - } - - public static function RVA2ChannelTypeLookup($index) { - static $RVA2ChannelTypeLookup = array( - 0x00 => 'Other', - 0x01 => 'Master volume', - 0x02 => 'Front right', - 0x03 => 'Front left', - 0x04 => 'Back right', - 0x05 => 'Back left', - 0x06 => 'Front centre', - 0x07 => 'Back centre', - 0x08 => 'Subwoofer' - ); - - return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : ''); - } - - public static function FrameNameLongLookup($framename) { - - $begin = __LINE__; - - /** This is not a comment! - - AENC Audio encryption - APIC Attached picture - ASPI Audio seek point index - BUF Recommended buffer size - CNT Play counter - COM Comments - COMM Comments - COMR Commercial frame - CRA Audio encryption - CRM Encrypted meta frame - ENCR Encryption method registration - EQU Equalisation - EQU2 Equalisation (2) - EQUA Equalisation - ETC Event timing codes - ETCO Event timing codes - GEO General encapsulated object - GEOB General encapsulated object - GRID Group identification registration - IPL Involved people list - IPLS Involved people list - LINK Linked information - LNK Linked information - MCDI Music CD identifier - MCI Music CD Identifier - MLL MPEG location lookup table - MLLT MPEG location lookup table - OWNE Ownership frame - PCNT Play counter - PIC Attached picture - POP Popularimeter - POPM Popularimeter - POSS Position synchronisation frame - PRIV Private frame - RBUF Recommended buffer size - REV Reverb - RVA Relative volume adjustment - RVA2 Relative volume adjustment (2) - RVAD Relative volume adjustment - RVRB Reverb - SEEK Seek frame - SIGN Signature frame - SLT Synchronised lyric/text - STC Synced tempo codes - SYLT Synchronised lyric/text - SYTC Synchronised tempo codes - TAL Album/Movie/Show title - TALB Album/Movie/Show title - TBP BPM (Beats Per Minute) - TBPM BPM (beats per minute) - TCM Composer - TCMP Part of a compilation - TCO Content type - TCOM Composer - TCON Content type - TCOP Copyright message - TCP Part of a compilation - TCR Copyright message - TDA Date - TDAT Date - TDEN Encoding time - TDLY Playlist delay - TDOR Original release time - TDRC Recording time - TDRL Release time - TDTG Tagging time - TDY Playlist delay - TEN Encoded by - TENC Encoded by - TEXT Lyricist/Text writer - TFLT File type - TFT File type - TIM Time - TIME Time - TIPL Involved people list - TIT1 Content group description - TIT2 Title/songname/content description - TIT3 Subtitle/Description refinement - TKE Initial key - TKEY Initial key - TLA Language(s) - TLAN Language(s) - TLE Length - TLEN Length - TMCL Musician credits list - TMED Media type - TMOO Mood - TMT Media type - TOA Original artist(s)/performer(s) - TOAL Original album/movie/show title - TOF Original filename - TOFN Original filename - TOL Original Lyricist(s)/text writer(s) - TOLY Original lyricist(s)/text writer(s) - TOPE Original artist(s)/performer(s) - TOR Original release year - TORY Original release year - TOT Original album/Movie/Show title - TOWN File owner/licensee - TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group - TP2 Band/Orchestra/Accompaniment - TP3 Conductor/Performer refinement - TP4 Interpreted, remixed, or otherwise modified by - TPA Part of a set - TPB Publisher - TPE1 Lead performer(s)/Soloist(s) - TPE2 Band/orchestra/accompaniment - TPE3 Conductor/performer refinement - TPE4 Interpreted, remixed, or otherwise modified by - TPOS Part of a set - TPRO Produced notice - TPUB Publisher - TRC ISRC (International Standard Recording Code) - TRCK Track number/Position in set - TRD Recording dates - TRDA Recording dates - TRK Track number/Position in set - TRSN Internet radio station name - TRSO Internet radio station owner - TS2 Album-Artist sort order - TSA Album sort order - TSC Composer sort order - TSI Size - TSIZ Size - TSO2 Album-Artist sort order - TSOA Album sort order - TSOC Composer sort order - TSOP Performer sort order - TSOT Title sort order - TSP Performer sort order - TSRC ISRC (international standard recording code) - TSS Software/hardware and settings used for encoding - TSSE Software/Hardware and settings used for encoding - TSST Set subtitle - TST Title sort order - TT1 Content group description - TT2 Title/Songname/Content description - TT3 Subtitle/Description refinement - TXT Lyricist/text writer - TXX User defined text information frame - TXXX User defined text information frame - TYE Year - TYER Year - UFI Unique file identifier - UFID Unique file identifier - ULT Unsychronised lyric/text transcription - USER Terms of use - USLT Unsynchronised lyric/text transcription - WAF Official audio file webpage - WAR Official artist/performer webpage - WAS Official audio source webpage - WCM Commercial information - WCOM Commercial information - WCOP Copyright/Legal information - WCP Copyright/Legal information - WOAF Official audio file webpage - WOAR Official artist/performer webpage - WOAS Official audio source webpage - WORS Official Internet radio station homepage - WPAY Payment - WPB Publishers official webpage - WPUB Publishers official webpage - WXX User defined URL link frame - WXXX User defined URL link frame - TFEA Featured Artist - TSTU Recording Studio - rgad Replay Gain Adjustment - - */ - - return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long'); - - // Last three: - // from Helium2 [www.helium2.com] - // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html - } - - - public static function FrameNameShortLookup($framename) { - - $begin = __LINE__; - - /** This is not a comment! - - AENC audio_encryption - APIC attached_picture - ASPI audio_seek_point_index - BUF recommended_buffer_size - CNT play_counter - COM comment - COMM comment - COMR commercial_frame - CRA audio_encryption - CRM encrypted_meta_frame - ENCR encryption_method_registration - EQU equalisation - EQU2 equalisation - EQUA equalisation - ETC event_timing_codes - ETCO event_timing_codes - GEO general_encapsulated_object - GEOB general_encapsulated_object - GRID group_identification_registration - IPL involved_people_list - IPLS involved_people_list - LINK linked_information - LNK linked_information - MCDI music_cd_identifier - MCI music_cd_identifier - MLL mpeg_location_lookup_table - MLLT mpeg_location_lookup_table - OWNE ownership_frame - PCNT play_counter - PIC attached_picture - POP popularimeter - POPM popularimeter - POSS position_synchronisation_frame - PRIV private_frame - RBUF recommended_buffer_size - REV reverb - RVA relative_volume_adjustment - RVA2 relative_volume_adjustment - RVAD relative_volume_adjustment - RVRB reverb - SEEK seek_frame - SIGN signature_frame - SLT synchronised_lyric - STC synced_tempo_codes - SYLT synchronised_lyric - SYTC synchronised_tempo_codes - TAL album - TALB album - TBP bpm - TBPM bpm - TCM composer - TCMP part_of_a_compilation - TCO genre - TCOM composer - TCON genre - TCOP copyright_message - TCP part_of_a_compilation - TCR copyright_message - TDA date - TDAT date - TDEN encoding_time - TDLY playlist_delay - TDOR original_release_time - TDRC recording_time - TDRL release_time - TDTG tagging_time - TDY playlist_delay - TEN encoded_by - TENC encoded_by - TEXT lyricist - TFLT file_type - TFT file_type - TIM time - TIME time - TIPL involved_people_list - TIT1 content_group_description - TIT2 title - TIT3 subtitle - TKE initial_key - TKEY initial_key - TLA language - TLAN language - TLE length - TLEN length - TMCL musician_credits_list - TMED media_type - TMOO mood - TMT media_type - TOA original_artist - TOAL original_album - TOF original_filename - TOFN original_filename - TOL original_lyricist - TOLY original_lyricist - TOPE original_artist - TOR original_year - TORY original_year - TOT original_album - TOWN file_owner - TP1 artist - TP2 band - TP3 conductor - TP4 remixer - TPA part_of_a_set - TPB publisher - TPE1 artist - TPE2 band - TPE3 conductor - TPE4 remixer - TPOS part_of_a_set - TPRO produced_notice - TPUB publisher - TRC isrc - TRCK track_number - TRD recording_dates - TRDA recording_dates - TRK track_number - TRSN internet_radio_station_name - TRSO internet_radio_station_owner - TS2 album_artist_sort_order - TSA album_sort_order - TSC composer_sort_order - TSI size - TSIZ size - TSO2 album_artist_sort_order - TSOA album_sort_order - TSOC composer_sort_order - TSOP performer_sort_order - TSOT title_sort_order - TSP performer_sort_order - TSRC isrc - TSS encoder_settings - TSSE encoder_settings - TSST set_subtitle - TST title_sort_order - TT1 content_group_description - TT2 title - TT3 subtitle - TXT lyricist - TXX text - TXXX text - TYE year - TYER year - UFI unique_file_identifier - UFID unique_file_identifier - ULT unsychronised_lyric - USER terms_of_use - USLT unsynchronised_lyric - WAF url_file - WAR url_artist - WAS url_source - WCM commercial_information - WCOM commercial_information - WCOP copyright - WCP copyright - WOAF url_file - WOAR url_artist - WOAS url_source - WORS url_station - WPAY url_payment - WPB url_publisher - WPUB url_publisher - WXX url_user - WXXX url_user - TFEA featured_artist - TSTU recording_studio - rgad replay_gain_adjustment - - */ - - return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short'); - } - - public static function TextEncodingTerminatorLookup($encoding) { - // http://www.id3.org/id3v2.4.0-structure.txt - // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: - static $TextEncodingTerminatorLookup = array( - 0 => "\x00", // $00 ISO-8859-1. Terminated with $00. - 1 => "\x00\x00", // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. - 2 => "\x00\x00", // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. - 3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00. - 255 => "\x00\x00" - ); - return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : ''); - } - - public static function TextEncodingNameLookup($encoding) { - // http://www.id3.org/id3v2.4.0-structure.txt - // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: - static $TextEncodingNameLookup = array( - 0 => 'ISO-8859-1', // $00 ISO-8859-1. Terminated with $00. - 1 => 'UTF-16', // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. - 2 => 'UTF-16BE', // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. - 3 => 'UTF-8', // $03 UTF-8 encoded Unicode. Terminated with $00. - 255 => 'UTF-16BE' - ); - return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1'); - } - - public static function IsValidID3v2FrameName($framename, $id3v2majorversion) { - switch ($id3v2majorversion) { - case 2: - return preg_match('#[A-Z][A-Z0-9]{2}#', $framename); - break; - - case 3: - case 4: - return preg_match('#[A-Z][A-Z0-9]{3}#', $framename); - break; - } - return false; - } - - public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { - for ($i = 0; $i < strlen($numberstring); $i++) { - if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) { - if (($numberstring{$i} == '.') && $allowdecimal) { - // allowed - } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) { - // allowed - } else { - return false; - } - } - } - return true; - } - - public static function IsValidDateStampString($datestamp) { - if (strlen($datestamp) != 8) { - return false; - } - if (!self::IsANumber($datestamp, false)) { - return false; - } - $year = substr($datestamp, 0, 4); - $month = substr($datestamp, 4, 2); - $day = substr($datestamp, 6, 2); - if (($year == 0) || ($month == 0) || ($day == 0)) { - return false; - } - if ($month > 12) { - return false; - } - if ($day > 31) { - return false; - } - if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) { - return false; - } - if (($day > 29) && ($month == 2)) { - return false; - } - return true; - } - - public static function ID3v2HeaderLength($majorversion) { - return (($majorversion == 2) ? 6 : 10); - } - -} - + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// module.tag.id3v2.php // +// module for analyzing ID3v2 tags // +// dependencies: module.tag.id3v1.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); + +class getid3_id3v2 extends getid3_handler +{ + public $StartingOffset = 0; + + public function Analyze() { + $info = &$this->getid3->info; + + // Overall tag structure: + // +-----------------------------+ + // | Header (10 bytes) | + // +-----------------------------+ + // | Extended Header | + // | (variable length, OPTIONAL) | + // +-----------------------------+ + // | Frames (variable length) | + // +-----------------------------+ + // | Padding | + // | (variable length, OPTIONAL) | + // +-----------------------------+ + // | Footer (10 bytes, OPTIONAL) | + // +-----------------------------+ + + // Header + // ID3v2/file identifier "ID3" + // ID3v2 version $04 00 + // ID3v2 flags (%ab000000 in v2.2, %abc00000 in v2.3, %abcd0000 in v2.4.x) + // ID3v2 size 4 * %0xxxxxxx + + + // shortcuts + $info['id3v2']['header'] = true; + $thisfile_id3v2 = &$info['id3v2']; + $thisfile_id3v2['flags'] = array(); + $thisfile_id3v2_flags = &$thisfile_id3v2['flags']; + + + fseek($this->getid3->fp, $this->StartingOffset, SEEK_SET); + $header = fread($this->getid3->fp, 10); + if (substr($header, 0, 3) == 'ID3' && strlen($header) == 10) { + + $thisfile_id3v2['majorversion'] = ord($header{3}); + $thisfile_id3v2['minorversion'] = ord($header{4}); + + // shortcut + $id3v2_majorversion = &$thisfile_id3v2['majorversion']; + + } else { + + unset($info['id3v2']); + return false; + + } + + if ($id3v2_majorversion > 4) { // this script probably won't correctly parse ID3v2.5.x and above (if it ever exists) + + $info['error'][] = 'this script only parses up to ID3v2.4.x - this tag is ID3v2.'.$id3v2_majorversion.'.'.$thisfile_id3v2['minorversion']; + return false; + + } + + $id3_flags = ord($header{5}); + switch ($id3v2_majorversion) { + case 2: + // %ab000000 in v2.2 + $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation + $thisfile_id3v2_flags['compression'] = (bool) ($id3_flags & 0x40); // b - Compression + break; + + case 3: + // %abc00000 in v2.3 + $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation + $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header + $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator + break; + + case 4: + // %abcd0000 in v2.4 + $thisfile_id3v2_flags['unsynch'] = (bool) ($id3_flags & 0x80); // a - Unsynchronisation + $thisfile_id3v2_flags['exthead'] = (bool) ($id3_flags & 0x40); // b - Extended header + $thisfile_id3v2_flags['experim'] = (bool) ($id3_flags & 0x20); // c - Experimental indicator + $thisfile_id3v2_flags['isfooter'] = (bool) ($id3_flags & 0x10); // d - Footer present + break; + } + + $thisfile_id3v2['headerlength'] = getid3_lib::BigEndian2Int(substr($header, 6, 4), 1) + 10; // length of ID3v2 tag in 10-byte header doesn't include 10-byte header length + + $thisfile_id3v2['tag_offset_start'] = $this->StartingOffset; + $thisfile_id3v2['tag_offset_end'] = $thisfile_id3v2['tag_offset_start'] + $thisfile_id3v2['headerlength']; + + + + // create 'encoding' key - used by getid3::HandleAllTags() + // in ID3v2 every field can have it's own encoding type + // so force everything to UTF-8 so it can be handled consistantly + $thisfile_id3v2['encoding'] = 'UTF-8'; + + + // Frames + + // All ID3v2 frames consists of one frame header followed by one or more + // fields containing the actual information. The header is always 10 + // bytes and laid out as follows: + // + // Frame ID $xx xx xx xx (four characters) + // Size 4 * %0xxxxxxx + // Flags $xx xx + + $sizeofframes = $thisfile_id3v2['headerlength'] - 10; // not including 10-byte initial header + if (!empty($thisfile_id3v2['exthead']['length'])) { + $sizeofframes -= ($thisfile_id3v2['exthead']['length'] + 4); + } + if (!empty($thisfile_id3v2_flags['isfooter'])) { + $sizeofframes -= 10; // footer takes last 10 bytes of ID3v2 header, after frame data, before audio + } + if ($sizeofframes > 0) { + + $framedata = fread($this->getid3->fp, $sizeofframes); // read all frames from file into $framedata variable + + // if entire frame data is unsynched, de-unsynch it now (ID3v2.3.x) + if (!empty($thisfile_id3v2_flags['unsynch']) && ($id3v2_majorversion <= 3)) { + $framedata = $this->DeUnsynchronise($framedata); + } + // [in ID3v2.4.0] Unsynchronisation [S:6.1] is done on frame level, instead + // of on tag level, making it easier to skip frames, increasing the streamability + // of the tag. The unsynchronisation flag in the header [S:3.1] indicates that + // there exists an unsynchronised frame, while the new unsynchronisation flag in + // the frame header [S:4.1.2] indicates unsynchronisation. + + + //$framedataoffset = 10 + ($thisfile_id3v2['exthead']['length'] ? $thisfile_id3v2['exthead']['length'] + 4 : 0); // how many bytes into the stream - start from after the 10-byte header (and extended header length+4, if present) + $framedataoffset = 10; // how many bytes into the stream - start from after the 10-byte header + + + // Extended Header + if (!empty($thisfile_id3v2_flags['exthead'])) { + $extended_header_offset = 0; + + if ($id3v2_majorversion == 3) { + + // v2.3 definition: + //Extended header size $xx xx xx xx // 32-bit integer + //Extended Flags $xx xx + // %x0000000 %00000000 // v2.3 + // x - CRC data present + //Size of padding $xx xx xx xx + + $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), 0); + $extended_header_offset += 4; + + $thisfile_id3v2['exthead']['flag_bytes'] = 2; + $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes'])); + $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes']; + + $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x8000); + + $thisfile_id3v2['exthead']['padding_size'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4)); + $extended_header_offset += 4; + + if ($thisfile_id3v2['exthead']['flags']['crc']) { + $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4)); + $extended_header_offset += 4; + } + $extended_header_offset += $thisfile_id3v2['exthead']['padding_size']; + + } elseif ($id3v2_majorversion == 4) { + + // v2.4 definition: + //Extended header size 4 * %0xxxxxxx // 28-bit synchsafe integer + //Number of flag bytes $01 + //Extended Flags $xx + // %0bcd0000 // v2.4 + // b - Tag is an update + // Flag data length $00 + // c - CRC data present + // Flag data length $05 + // Total frame CRC 5 * %0xxxxxxx + // d - Tag restrictions + // Flag data length $01 + + $thisfile_id3v2['exthead']['length'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 4), true); + $extended_header_offset += 4; + + $thisfile_id3v2['exthead']['flag_bytes'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should always be 1 + $extended_header_offset += 1; + + $thisfile_id3v2['exthead']['flag_raw'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $thisfile_id3v2['exthead']['flag_bytes'])); + $extended_header_offset += $thisfile_id3v2['exthead']['flag_bytes']; + + $thisfile_id3v2['exthead']['flags']['update'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x40); + $thisfile_id3v2['exthead']['flags']['crc'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x20); + $thisfile_id3v2['exthead']['flags']['restrictions'] = (bool) ($thisfile_id3v2['exthead']['flag_raw'] & 0x10); + + if ($thisfile_id3v2['exthead']['flags']['update']) { + $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 0 + $extended_header_offset += 1; + } + + if ($thisfile_id3v2['exthead']['flags']['crc']) { + $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 5 + $extended_header_offset += 1; + $thisfile_id3v2['exthead']['flag_data']['crc'] = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, $ext_header_chunk_length), true, false); + $extended_header_offset += $ext_header_chunk_length; + } + + if ($thisfile_id3v2['exthead']['flags']['restrictions']) { + $ext_header_chunk_length = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); // should be 1 + $extended_header_offset += 1; + + // %ppqrrstt + $restrictions_raw = getid3_lib::BigEndian2Int(substr($framedata, $extended_header_offset, 1)); + $extended_header_offset += 1; + $thisfile_id3v2['exthead']['flags']['restrictions']['tagsize'] = ($restrictions_raw & 0xC0) >> 6; // p - Tag size restrictions + $thisfile_id3v2['exthead']['flags']['restrictions']['textenc'] = ($restrictions_raw & 0x20) >> 5; // q - Text encoding restrictions + $thisfile_id3v2['exthead']['flags']['restrictions']['textsize'] = ($restrictions_raw & 0x18) >> 3; // r - Text fields size restrictions + $thisfile_id3v2['exthead']['flags']['restrictions']['imgenc'] = ($restrictions_raw & 0x04) >> 2; // s - Image encoding restrictions + $thisfile_id3v2['exthead']['flags']['restrictions']['imgsize'] = ($restrictions_raw & 0x03) >> 0; // t - Image size restrictions + + $thisfile_id3v2['exthead']['flags']['restrictions_text']['tagsize'] = $this->LookupExtendedHeaderRestrictionsTagSizeLimits($thisfile_id3v2['exthead']['flags']['restrictions']['tagsize']); + $thisfile_id3v2['exthead']['flags']['restrictions_text']['textenc'] = $this->LookupExtendedHeaderRestrictionsTextEncodings($thisfile_id3v2['exthead']['flags']['restrictions']['textenc']); + $thisfile_id3v2['exthead']['flags']['restrictions_text']['textsize'] = $this->LookupExtendedHeaderRestrictionsTextFieldSize($thisfile_id3v2['exthead']['flags']['restrictions']['textsize']); + $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgenc'] = $this->LookupExtendedHeaderRestrictionsImageEncoding($thisfile_id3v2['exthead']['flags']['restrictions']['imgenc']); + $thisfile_id3v2['exthead']['flags']['restrictions_text']['imgsize'] = $this->LookupExtendedHeaderRestrictionsImageSizeSize($thisfile_id3v2['exthead']['flags']['restrictions']['imgsize']); + } + + if ($thisfile_id3v2['exthead']['length'] != $extended_header_offset) { + $info['warning'][] = 'ID3v2.4 extended header length mismatch (expecting '.intval($thisfile_id3v2['exthead']['length']).', found '.intval($extended_header_offset).')'; + } + } + + $framedataoffset += $extended_header_offset; + $framedata = substr($framedata, $extended_header_offset); + } // end extended header + + + while (isset($framedata) && (strlen($framedata) > 0)) { // cycle through until no more frame data is left to parse + if (strlen($framedata) <= $this->ID3v2HeaderLength($id3v2_majorversion)) { + // insufficient room left in ID3v2 header for actual data - must be padding + $thisfile_id3v2['padding']['start'] = $framedataoffset; + $thisfile_id3v2['padding']['length'] = strlen($framedata); + $thisfile_id3v2['padding']['valid'] = true; + for ($i = 0; $i < $thisfile_id3v2['padding']['length']; $i++) { + if ($framedata{$i} != "\x00") { + $thisfile_id3v2['padding']['valid'] = false; + $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; + $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'; + break; + } + } + break; // skip rest of ID3v2 header + } + if ($id3v2_majorversion == 2) { + // Frame ID $xx xx xx (three characters) + // Size $xx xx xx (24-bit integer) + // Flags $xx xx + + $frame_header = substr($framedata, 0, 6); // take next 6 bytes for header + $framedata = substr($framedata, 6); // and leave the rest in $framedata + $frame_name = substr($frame_header, 0, 3); + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 3, 3), 0); + $frame_flags = 0; // not used for anything in ID3v2.2, just set to avoid E_NOTICEs + + } elseif ($id3v2_majorversion > 2) { + + // Frame ID $xx xx xx xx (four characters) + // Size $xx xx xx xx (32-bit integer in v2.3, 28-bit synchsafe in v2.4+) + // Flags $xx xx + + $frame_header = substr($framedata, 0, 10); // take next 10 bytes for header + $framedata = substr($framedata, 10); // and leave the rest in $framedata + + $frame_name = substr($frame_header, 0, 4); + if ($id3v2_majorversion == 3) { + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer + } else { // ID3v2.4+ + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 1); // 32-bit synchsafe integer (28-bit value) + } + + if ($frame_size < (strlen($framedata) + 4)) { + $nextFrameID = substr($framedata, $frame_size, 4); + if ($this->IsValidID3v2FrameName($nextFrameID, $id3v2_majorversion)) { + // next frame is OK + } elseif (($frame_name == "\x00".'MP3') || ($frame_name == "\x00\x00".'MP') || ($frame_name == ' MP3') || ($frame_name == 'MP3e')) { + // MP3ext known broken frames - "ok" for the purposes of this test + } elseif (($id3v2_majorversion == 4) && ($this->IsValidID3v2FrameName(substr($framedata, getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0), 4), 3))) { + $info['warning'][] = 'ID3v2 tag written as ID3v2.4, but with non-synchsafe integers (ID3v2.3 style). Older versions of (Helium2; iTunes) are known culprits of this. Tag has been parsed as ID3v2.3'; + $id3v2_majorversion = 3; + $frame_size = getid3_lib::BigEndian2Int(substr($frame_header, 4, 4), 0); // 32-bit integer + } + } + + + $frame_flags = getid3_lib::BigEndian2Int(substr($frame_header, 8, 2)); + } + + if ((($id3v2_majorversion == 2) && ($frame_name == "\x00\x00\x00")) || ($frame_name == "\x00\x00\x00\x00")) { + // padding encountered + + $thisfile_id3v2['padding']['start'] = $framedataoffset; + $thisfile_id3v2['padding']['length'] = strlen($frame_header) + strlen($framedata); + $thisfile_id3v2['padding']['valid'] = true; + + $len = strlen($framedata); + for ($i = 0; $i < $len; $i++) { + if ($framedata{$i} != "\x00") { + $thisfile_id3v2['padding']['valid'] = false; + $thisfile_id3v2['padding']['errorpos'] = $thisfile_id3v2['padding']['start'] + $i; + $info['warning'][] = 'Invalid ID3v2 padding found at offset '.$thisfile_id3v2['padding']['errorpos'].' (the remaining '.($thisfile_id3v2['padding']['length'] - $i).' bytes are considered invalid)'; + break; + } + } + break; // skip rest of ID3v2 header + } + + if ($frame_name == 'COM ') { + $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by iTunes (versions "X v2.0.3", "v3.0.1" are known-guilty, probably others too)]'; + $frame_name = 'COMM'; + } + if (($frame_size <= strlen($framedata)) && ($this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion))) { + + unset($parsedFrame); + $parsedFrame['frame_name'] = $frame_name; + $parsedFrame['frame_flags_raw'] = $frame_flags; + $parsedFrame['data'] = substr($framedata, 0, $frame_size); + $parsedFrame['datalength'] = getid3_lib::CastAsInt($frame_size); + $parsedFrame['dataoffset'] = $framedataoffset; + + $this->ParseID3v2Frame($parsedFrame); + $thisfile_id3v2[$frame_name][] = $parsedFrame; + + $framedata = substr($framedata, $frame_size); + + } else { // invalid frame length or FrameID + + if ($frame_size <= strlen($framedata)) { + + if ($this->IsValidID3v2FrameName(substr($framedata, $frame_size, 4), $id3v2_majorversion)) { + + // next frame is valid, just skip the current frame + $framedata = substr($framedata, $frame_size); + $info['warning'][] = 'Next ID3v2 frame is valid, skipping current frame.'; + + } else { + + // next frame is invalid too, abort processing + //unset($framedata); + $framedata = null; + $info['error'][] = 'Next ID3v2 frame is also invalid, aborting processing.'; + + } + + } elseif ($frame_size == strlen($framedata)) { + + // this is the last frame, just skip + $info['warning'][] = 'This was the last ID3v2 frame.'; + + } else { + + // next frame is invalid too, abort processing + //unset($framedata); + $framedata = null; + $info['warning'][] = 'Invalid ID3v2 frame size, aborting.'; + + } + if (!$this->IsValidID3v2FrameName($frame_name, $id3v2_majorversion)) { + + switch ($frame_name) { + case "\x00\x00".'MP': + case "\x00".'MP3': + case ' MP3': + case 'MP3e': + case "\x00".'MP': + case ' MP': + case 'MP3': + $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))). [Note: this particular error has been known to happen with tags edited by "MP3ext (www.mutschler.de/mp3ext/)"]'; + break; + + default: + $info['warning'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: !IsValidID3v2FrameName("'.str_replace("\x00", ' ', $frame_name).'", '.$id3v2_majorversion.'))).'; + break; + } + + } elseif (!isset($framedata) || ($frame_size > strlen($framedata))) { + + $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag). (ERROR: $frame_size ('.$frame_size.') > strlen($framedata) ('.(isset($framedata) ? strlen($framedata) : 'null').')).'; + + } else { + + $info['error'][] = 'error parsing "'.$frame_name.'" ('.$framedataoffset.' bytes into the ID3v2.'.$id3v2_majorversion.' tag).'; + + } + + } + $framedataoffset += ($frame_size + $this->ID3v2HeaderLength($id3v2_majorversion)); + + } + + } + + + // Footer + + // The footer is a copy of the header, but with a different identifier. + // ID3v2 identifier "3DI" + // ID3v2 version $04 00 + // ID3v2 flags %abcd0000 + // ID3v2 size 4 * %0xxxxxxx + + if (isset($thisfile_id3v2_flags['isfooter']) && $thisfile_id3v2_flags['isfooter']) { + $footer = fread($this->getid3->fp, 10); + if (substr($footer, 0, 3) == '3DI') { + $thisfile_id3v2['footer'] = true; + $thisfile_id3v2['majorversion_footer'] = ord($footer{3}); + $thisfile_id3v2['minorversion_footer'] = ord($footer{4}); + } + if ($thisfile_id3v2['majorversion_footer'] <= 4) { + $id3_flags = ord(substr($footer{5})); + $thisfile_id3v2_flags['unsynch_footer'] = (bool) ($id3_flags & 0x80); + $thisfile_id3v2_flags['extfoot_footer'] = (bool) ($id3_flags & 0x40); + $thisfile_id3v2_flags['experim_footer'] = (bool) ($id3_flags & 0x20); + $thisfile_id3v2_flags['isfooter_footer'] = (bool) ($id3_flags & 0x10); + + $thisfile_id3v2['footerlength'] = getid3_lib::BigEndian2Int(substr($footer, 6, 4), 1); + } + } // end footer + + if (isset($thisfile_id3v2['comments']['genre'])) { + foreach ($thisfile_id3v2['comments']['genre'] as $key => $value) { + unset($thisfile_id3v2['comments']['genre'][$key]); + $thisfile_id3v2['comments'] = getid3_lib::array_merge_noclobber($thisfile_id3v2['comments'], array('genre'=>$this->ParseID3v2GenreString($value))); + } + } + + if (isset($thisfile_id3v2['comments']['track'])) { + foreach ($thisfile_id3v2['comments']['track'] as $key => $value) { + if (strstr($value, '/')) { + list($thisfile_id3v2['comments']['tracknum'][$key], $thisfile_id3v2['comments']['totaltracks'][$key]) = explode('/', $thisfile_id3v2['comments']['track'][$key]); + } + } + } + + if (!isset($thisfile_id3v2['comments']['year']) && !empty($thisfile_id3v2['comments']['recording_time'][0]) && preg_match('#^([0-9]{4})#', trim($thisfile_id3v2['comments']['recording_time'][0]), $matches)) { + $thisfile_id3v2['comments']['year'] = array($matches[1]); + } + + + if (!empty($thisfile_id3v2['TXXX'])) { + // MediaMonkey does this, maybe others: write a blank RGAD frame, but put replay-gain adjustment values in TXXX frames + foreach ($thisfile_id3v2['TXXX'] as $txxx_array) { + switch ($txxx_array['description']) { + case 'replaygain_track_gain': + if (empty($info['replay_gain']['track']['adjustment']) && !empty($txxx_array['data'])) { + $info['replay_gain']['track']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data']))); + } + break; + case 'replaygain_track_peak': + if (empty($info['replay_gain']['track']['peak']) && !empty($txxx_array['data'])) { + $info['replay_gain']['track']['peak'] = floatval($txxx_array['data']); + } + break; + case 'replaygain_album_gain': + if (empty($info['replay_gain']['album']['adjustment']) && !empty($txxx_array['data'])) { + $info['replay_gain']['album']['adjustment'] = floatval(trim(str_replace('dB', '', $txxx_array['data']))); + } + break; + } + } + } + + + // Set avdataoffset + $info['avdataoffset'] = $thisfile_id3v2['headerlength']; + if (isset($thisfile_id3v2['footer'])) { + $info['avdataoffset'] += 10; + } + + return true; + } + + + public function ParseID3v2GenreString($genrestring) { + // Parse genres into arrays of genreName and genreID + // ID3v2.2.x, ID3v2.3.x: '(21)' or '(4)Eurodisco' or '(51)(39)' or '(55)((I think...)' + // ID3v2.4.x: '21' $00 'Eurodisco' $00 + $clean_genres = array(); + if (strpos($genrestring, "\x00") === false) { + $genrestring = preg_replace('#\(([0-9]{1,3})\)#', '$1'."\x00", $genrestring); + } + $genre_elements = explode("\x00", $genrestring); + foreach ($genre_elements as $element) { + $element = trim($element); + if ($element) { + if (preg_match('#^[0-9]{1,3}#', $element)) { + $clean_genres[] = getid3_id3v1::LookupGenreName($element); + } else { + $clean_genres[] = str_replace('((', '(', $element); + } + } + } + return $clean_genres; + } + + + public function ParseID3v2Frame(&$parsedFrame) { + + // shortcuts + $info = &$this->getid3->info; + $id3v2_majorversion = $info['id3v2']['majorversion']; + + $parsedFrame['framenamelong'] = $this->FrameNameLongLookup($parsedFrame['frame_name']); + if (empty($parsedFrame['framenamelong'])) { + unset($parsedFrame['framenamelong']); + } + $parsedFrame['framenameshort'] = $this->FrameNameShortLookup($parsedFrame['frame_name']); + if (empty($parsedFrame['framenameshort'])) { + unset($parsedFrame['framenameshort']); + } + + if ($id3v2_majorversion >= 3) { // frame flags are not part of the ID3v2.2 standard + if ($id3v2_majorversion == 3) { + // Frame Header Flags + // %abc00000 %ijk00000 + $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x8000); // a - Tag alter preservation + $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // b - File alter preservation + $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // c - Read only + $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0080); // i - Compression + $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // j - Encryption + $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0020); // k - Grouping identity + + } elseif ($id3v2_majorversion == 4) { + // Frame Header Flags + // %0abc0000 %0h00kmnp + $parsedFrame['flags']['TagAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x4000); // a - Tag alter preservation + $parsedFrame['flags']['FileAlterPreservation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x2000); // b - File alter preservation + $parsedFrame['flags']['ReadOnly'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x1000); // c - Read only + $parsedFrame['flags']['GroupingIdentity'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0040); // h - Grouping identity + $parsedFrame['flags']['compression'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0008); // k - Compression + $parsedFrame['flags']['Encryption'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0004); // m - Encryption + $parsedFrame['flags']['Unsynchronisation'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0002); // n - Unsynchronisation + $parsedFrame['flags']['DataLengthIndicator'] = (bool) ($parsedFrame['frame_flags_raw'] & 0x0001); // p - Data length indicator + + // Frame-level de-unsynchronisation - ID3v2.4 + if ($parsedFrame['flags']['Unsynchronisation']) { + $parsedFrame['data'] = $this->DeUnsynchronise($parsedFrame['data']); + } + + if ($parsedFrame['flags']['DataLengthIndicator']) { + $parsedFrame['data_length_indicator'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4), 1); + $parsedFrame['data'] = substr($parsedFrame['data'], 4); + } + } + + // Frame-level de-compression + if ($parsedFrame['flags']['compression']) { + $parsedFrame['decompressed_size'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 4)); + if (!function_exists('gzuncompress')) { + $info['warning'][] = 'gzuncompress() support required to decompress ID3v2 frame "'.$parsedFrame['frame_name'].'"'; + } else { + if ($decompresseddata = @gzuncompress(substr($parsedFrame['data'], 4))) { + //if ($decompresseddata = @gzuncompress($parsedFrame['data'])) { + $parsedFrame['data'] = $decompresseddata; + unset($decompresseddata); + } else { + $info['warning'][] = 'gzuncompress() failed on compressed contents of ID3v2 frame "'.$parsedFrame['frame_name'].'"'; + } + } + } + } + + if (!empty($parsedFrame['flags']['DataLengthIndicator'])) { + if ($parsedFrame['data_length_indicator'] != strlen($parsedFrame['data'])) { + $info['warning'][] = 'ID3v2 frame "'.$parsedFrame['frame_name'].'" should be '.$parsedFrame['data_length_indicator'].' bytes long according to DataLengthIndicator, but found '.strlen($parsedFrame['data']).' bytes of data'; + } + } + + if (isset($parsedFrame['datalength']) && ($parsedFrame['datalength'] == 0)) { + + $warning = 'Frame "'.$parsedFrame['frame_name'].'" at offset '.$parsedFrame['dataoffset'].' has no data portion'; + switch ($parsedFrame['frame_name']) { + case 'WCOM': + $warning .= ' (this is known to happen with files tagged by RioPort)'; + break; + + default: + break; + } + $info['warning'][] = $warning; + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'UFID')) || // 4.1 UFID Unique file identifier + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'UFI'))) { // 4.1 UFI Unique file identifier + // There may be more than one 'UFID' frame in a tag, + // but only one with the same 'Owner identifier'. + //
    + // Owner identifier $00 + // Identifier + $exploded = explode("\x00", $parsedFrame['data'], 2); + $parsedFrame['ownerid'] = (isset($exploded[0]) ? $exploded[0] : ''); + $parsedFrame['data'] = (isset($exploded[1]) ? $exploded[1] : ''); + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'TXXX')) || // 4.2.2 TXXX User defined text information frame + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'TXX'))) { // 4.2.2 TXX User defined text information frame + // There may be more than one 'TXXX' frame in each tag, + // but only one with the same description. + //
    + // Text encoding $xx + // Description $00 (00) + // Value + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['description'] = $frame_description; + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = trim(getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data'])); + } + //unset($parsedFrame['data']); do not unset, may be needed elsewhere, e.g. for replaygain + + + } elseif ($parsedFrame['frame_name']{0} == 'T') { // 4.2. T??[?] Text information frame + // There may only be one text information frame of its kind in an tag. + //
    + // Text encoding $xx + // Information + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + // ID3v2.3 specs say that TPE1 (and others) can contain multiple artist values separated with / + // This of course breaks when an artist name contains slash character, e.g. "AC/DC" + // MP3tag (maybe others) implement alternative system where multiple artists are null-separated, which makes more sense + // getID3 will split null-separated artists into multiple artists and leave slash-separated ones to the user + switch ($parsedFrame['encoding']) { + case 'UTF-16': + case 'UTF-16BE': + case 'UTF-16LE': + $wordsize = 2; + break; + case 'ISO-8859-1': + case 'UTF-8': + default: + $wordsize = 1; + break; + } + $Txxx_elements = array(); + $Txxx_elements_start_offset = 0; + for ($i = 0; $i < strlen($parsedFrame['data']); $i += $wordsize) { + if (substr($parsedFrame['data'], $i, $wordsize) == str_repeat("\x00", $wordsize)) { + $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset); + $Txxx_elements_start_offset = $i + $wordsize; + } + } + $Txxx_elements[] = substr($parsedFrame['data'], $Txxx_elements_start_offset, $i - $Txxx_elements_start_offset); + foreach ($Txxx_elements as $Txxx_element) { + $string = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $Txxx_element); + if (!empty($string)) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $string; + } + } + unset($string, $wordsize, $i, $Txxx_elements, $Txxx_element, $Txxx_elements_start_offset); + } + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'WXXX')) || // 4.3.2 WXXX User defined URL link frame + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'WXX'))) { // 4.3.2 WXX User defined URL link frame + // There may be more than one 'WXXX' frame in each tag, + // but only one with the same description + //
    + // Text encoding $xx + // Description $00 (00) + // URL + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding)); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + if ($frame_terminatorpos) { + // there are null bytes after the data - this is not according to spec + // only use data up to first null byte + $frame_urldata = (string) substr($parsedFrame['data'], 0, $frame_terminatorpos); + } else { + // no null bytes following data, just use all data + $frame_urldata = (string) $parsedFrame['data']; + } + + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['url'] = $frame_urldata; + $parsedFrame['description'] = $frame_description; + if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['url']); + } + unset($parsedFrame['data']); + + + } elseif ($parsedFrame['frame_name']{0} == 'W') { // 4.3. W??? URL link frames + // There may only be one URL link frame of its kind in a tag, + // except when stated otherwise in the frame description + //
    + // URL + + $parsedFrame['url'] = trim($parsedFrame['data']); + if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['url']; + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'IPLS')) || // 4.4 IPLS Involved people list (ID3v2.3 only) + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'IPL'))) { // 4.4 IPL Involved people list (ID3v2.2 only) + // http://id3.org/id3v2.3.0#sec4.4 + // There may only be one 'IPL' frame in each tag + //
    + // Text encoding $xx + // People list strings + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($parsedFrame['encodingid']); + $parsedFrame['data_raw'] = (string) substr($parsedFrame['data'], $frame_offset); + + // http://www.getid3.org/phpBB3/viewtopic.php?t=1369 + // "this tag typically contains null terminated strings, which are associated in pairs" + // "there are users that use the tag incorrectly" + $IPLS_parts = array(); + if (strpos($parsedFrame['data_raw'], "\x00") !== false) { + $IPLS_parts_unsorted = array(); + if (((strlen($parsedFrame['data_raw']) % 2) == 0) && ((substr($parsedFrame['data_raw'], 0, 2) == "\xFF\xFE") || (substr($parsedFrame['data_raw'], 0, 2) == "\xFE\xFF"))) { + // UTF-16, be careful looking for null bytes since most 2-byte characters may contain one; you need to find twin null bytes, and on even padding + $thisILPS = ''; + for ($i = 0; $i < strlen($parsedFrame['data_raw']); $i += 2) { + $twobytes = substr($parsedFrame['data_raw'], $i, 2); + if ($twobytes === "\x00\x00") { + $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS); + $thisILPS = ''; + } else { + $thisILPS .= $twobytes; + } + } + if (strlen($thisILPS) > 2) { // 2-byte BOM + $IPLS_parts_unsorted[] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $thisILPS); + } + } else { + // ISO-8859-1 or UTF-8 or other single-byte-null character set + $IPLS_parts_unsorted = explode("\x00", $parsedFrame['data_raw']); + } + if (count($IPLS_parts_unsorted) == 1) { + // just a list of names, e.g. "Dino Baptiste, Jimmy Copley, John Gordon, Bernie Marsden, Sharon Watson" + foreach ($IPLS_parts_unsorted as $key => $value) { + $IPLS_parts_sorted = preg_split('#[;,\\r\\n\\t]#', $value); + $position = ''; + foreach ($IPLS_parts_sorted as $person) { + $IPLS_parts[] = array('position'=>$position, 'person'=>$person); + } + } + } elseif ((count($IPLS_parts_unsorted) % 2) == 0) { + $position = ''; + $person = ''; + foreach ($IPLS_parts_unsorted as $key => $value) { + if (($key % 2) == 0) { + $position = $value; + } else { + $person = $value; + $IPLS_parts[] = array('position'=>$position, 'person'=>$person); + $position = ''; + $person = ''; + } + } + } else { + foreach ($IPLS_parts_unsorted as $key => $value) { + $IPLS_parts[] = array($value); + } + } + + } else { + $IPLS_parts = preg_split('#[;,\\r\\n\\t]#', $parsedFrame['data_raw']); + } + $parsedFrame['data'] = $IPLS_parts; + + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data']; + } + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MCDI')) || // 4.4 MCDI Music CD identifier + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MCI'))) { // 4.5 MCI Music CD identifier + // There may only be one 'MCDI' frame in each tag + //
    + // CD TOC + + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = $parsedFrame['data']; + } + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ETCO')) || // 4.5 ETCO Event timing codes + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ETC'))) { // 4.6 ETC Event timing codes + // There may only be one 'ETCO' frame in each tag + //
    + // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + + $frame_offset = 0; + $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + + while ($frame_offset < strlen($parsedFrame['data'])) { + $parsedFrame['typeid'] = substr($parsedFrame['data'], $frame_offset++, 1); + $parsedFrame['type'] = $this->ETCOEventLookup($parsedFrame['typeid']); + $parsedFrame['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + $frame_offset += 4; + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'MLLT')) || // 4.6 MLLT MPEG location lookup table + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'MLL'))) { // 4.7 MLL MPEG location lookup table + // There may only be one 'MLLT' frame in each tag + //
    + // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + + $frame_offset = 0; + $parsedFrame['framesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 0, 2)); + $parsedFrame['bytesbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 2, 3)); + $parsedFrame['msbetweenreferences'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 5, 3)); + $parsedFrame['bitsforbytesdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 8, 1)); + $parsedFrame['bitsformsdeviation'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], 9, 1)); + $parsedFrame['data'] = substr($parsedFrame['data'], 10); + while ($frame_offset < strlen($parsedFrame['data'])) { + $deviationbitstream .= getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); + } + $reference_counter = 0; + while (strlen($deviationbitstream) > 0) { + $parsedFrame[$reference_counter]['bytedeviation'] = bindec(substr($deviationbitstream, 0, $parsedFrame['bitsforbytesdeviation'])); + $parsedFrame[$reference_counter]['msdeviation'] = bindec(substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'], $parsedFrame['bitsformsdeviation'])); + $deviationbitstream = substr($deviationbitstream, $parsedFrame['bitsforbytesdeviation'] + $parsedFrame['bitsformsdeviation']); + $reference_counter++; + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYTC')) || // 4.7 SYTC Synchronised tempo codes + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'STC'))) { // 4.8 STC Synchronised tempo codes + // There may only be one 'SYTC' frame in each tag + //
    + // Time stamp format $xx + // Tempo data + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + + $frame_offset = 0; + $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $timestamp_counter = 0; + while ($frame_offset < strlen($parsedFrame['data'])) { + $parsedFrame[$timestamp_counter]['tempo'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ($parsedFrame[$timestamp_counter]['tempo'] == 255) { + $parsedFrame[$timestamp_counter]['tempo'] += ord(substr($parsedFrame['data'], $frame_offset++, 1)); + } + $parsedFrame[$timestamp_counter]['timestamp'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + $frame_offset += 4; + $timestamp_counter++; + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USLT')) || // 4.8 USLT Unsynchronised lyric/text transcription + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'ULT'))) { // 4.9 ULT Unsynchronised lyric/text transcription + // There may be more than one 'Unsynchronised lyrics/text transcription' frame + // in each tag, but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_language = substr($parsedFrame['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['data'] = $parsedFrame['data']; + $parsedFrame['language'] = $frame_language; + $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); + $parsedFrame['description'] = $frame_description; + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'SYLT')) || // 4.9 SYLT Synchronised lyric/text + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'SLT'))) { // 4.10 SLT Synchronised lyric/text + // There may be more than one 'SYLT' frame in each tag, + // but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_language = substr($parsedFrame['data'], $frame_offset, 3); + $frame_offset += 3; + $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['contenttypeid'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['contenttype'] = $this->SYTLContentTypeLookup($parsedFrame['contenttypeid']); + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['language'] = $frame_language; + $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); + + $timestampindex = 0; + $frame_remainingdata = substr($parsedFrame['data'], $frame_offset); + while (strlen($frame_remainingdata)) { + $frame_offset = 0; + $frame_terminatorpos = strpos($frame_remainingdata, $this->TextEncodingTerminatorLookup($frame_textencoding)); + if ($frame_terminatorpos === false) { + $frame_remainingdata = ''; + } else { + if (ord(substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $parsedFrame['lyrics'][$timestampindex]['data'] = substr($frame_remainingdata, $frame_offset, $frame_terminatorpos - $frame_offset); + + $frame_remainingdata = substr($frame_remainingdata, $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + if (($timestampindex == 0) && (ord($frame_remainingdata{0}) != 0)) { + // timestamp probably omitted for first data item + } else { + $parsedFrame['lyrics'][$timestampindex]['timestamp'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 4)); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $timestampindex++; + } + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMM')) || // 4.10 COMM Comments + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'COM'))) { // 4.11 COM Comments + // There may be more than one comment frame in each tag, + // but only one with the same language and content descriptor. + //
    + // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + + if (strlen($parsedFrame['data']) < 5) { + + $info['warning'][] = 'Invalid data (too short) for "'.$parsedFrame['frame_name'].'" frame at offset '.$parsedFrame['dataoffset']; + + } else { + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_language = substr($parsedFrame['data'], $frame_offset, 3); + $frame_offset += 3; + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_text = (string) substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['language'] = $frame_language; + $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); + $parsedFrame['description'] = $frame_description; + $parsedFrame['data'] = $frame_text; + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); + } + + } + + } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'RVA2')) { // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + // There may be more than one 'RVA2' frame in each tag, + // but only one with the same identification string + //
    + // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00"); + $frame_idstring = substr($parsedFrame['data'], 0, $frame_terminatorpos); + if (ord($frame_idstring) === 0) { + $frame_idstring = ''; + } + $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00")); + $parsedFrame['description'] = $frame_idstring; + $RVA2channelcounter = 0; + while (strlen($frame_remainingdata) >= 5) { + $frame_offset = 0; + $frame_channeltypeid = ord(substr($frame_remainingdata, $frame_offset++, 1)); + $parsedFrame[$RVA2channelcounter]['channeltypeid'] = $frame_channeltypeid; + $parsedFrame[$RVA2channelcounter]['channeltype'] = $this->RVA2ChannelTypeLookup($frame_channeltypeid); + $parsedFrame[$RVA2channelcounter]['volumeadjust'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, 2), false, true); // 16-bit signed + $frame_offset += 2; + $parsedFrame[$RVA2channelcounter]['bitspeakvolume'] = ord(substr($frame_remainingdata, $frame_offset++, 1)); + if (($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] < 1) || ($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] > 4)) { + $info['warning'][] = 'ID3v2::RVA2 frame['.$RVA2channelcounter.'] contains invalid '.$parsedFrame[$RVA2channelcounter]['bitspeakvolume'].'-byte bits-representing-peak value'; + break; + } + $frame_bytespeakvolume = ceil($parsedFrame[$RVA2channelcounter]['bitspeakvolume'] / 8); + $parsedFrame[$RVA2channelcounter]['peakvolume'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, $frame_offset, $frame_bytespeakvolume)); + $frame_remainingdata = substr($frame_remainingdata, $frame_offset + $frame_bytespeakvolume); + $RVA2channelcounter++; + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'RVAD')) || // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'RVA'))) { // 4.12 RVA Relative volume adjustment (ID3v2.2 only) + // There may only be one 'RVA' frame in each tag + //
    + // ID3v2.2 => Increment/decrement %000000ba + // ID3v2.3 => Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // ID3v2.3 only, optional (not present in ID3v2.2): + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + + $frame_offset = 0; + $frame_incrdecrflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['incdec']['right'] = (bool) substr($frame_incrdecrflags, 6, 1); + $parsedFrame['incdec']['left'] = (bool) substr($frame_incrdecrflags, 7, 1); + $parsedFrame['bitsvolume'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $frame_bytesvolume = ceil($parsedFrame['bitsvolume'] / 8); + $parsedFrame['volumechange']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['right'] === false) { + $parsedFrame['volumechange']['right'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['volumechange']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['left'] === false) { + $parsedFrame['volumechange']['left'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + if ($id3v2_majorversion == 3) { + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); + if (strlen($parsedFrame['data']) > 0) { + $parsedFrame['incdec']['rightrear'] = (bool) substr($frame_incrdecrflags, 4, 1); + $parsedFrame['incdec']['leftrear'] = (bool) substr($frame_incrdecrflags, 5, 1); + $parsedFrame['volumechange']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['rightrear'] === false) { + $parsedFrame['volumechange']['rightrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['volumechange']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['leftrear'] === false) { + $parsedFrame['volumechange']['leftrear'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['rightrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['leftrear'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); + if (strlen($parsedFrame['data']) > 0) { + $parsedFrame['incdec']['center'] = (bool) substr($frame_incrdecrflags, 3, 1); + $parsedFrame['volumechange']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['center'] === false) { + $parsedFrame['volumechange']['center'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['center'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_offset); + if (strlen($parsedFrame['data']) > 0) { + $parsedFrame['incdec']['bass'] = (bool) substr($frame_incrdecrflags, 2, 1); + $parsedFrame['volumechange']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + if ($parsedFrame['incdec']['bass'] === false) { + $parsedFrame['volumechange']['bass'] *= -1; + } + $frame_offset += $frame_bytesvolume; + $parsedFrame['peakvolume']['bass'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesvolume)); + $frame_offset += $frame_bytesvolume; + } + } + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'EQU2')) { // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + // There may be more than one 'EQU2' frame in each tag, + // but only one with the same identification string + //
    + // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + + $frame_offset = 0; + $frame_interpolationmethod = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_idstring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_idstring) === 0) { + $frame_idstring = ''; + } + $parsedFrame['description'] = $frame_idstring; + $frame_remainingdata = substr($parsedFrame['data'], $frame_terminatorpos + strlen("\x00")); + while (strlen($frame_remainingdata)) { + $frame_frequency = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 0, 2)) / 2; + $parsedFrame['data'][$frame_frequency] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, 2), false, true); + $frame_remainingdata = substr($frame_remainingdata, 4); + } + $parsedFrame['interpolationmethod'] = $frame_interpolationmethod; + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion == 3) && ($parsedFrame['frame_name'] == 'EQUA')) || // 4.12 EQUA Equalisation (ID3v2.3 only) + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'EQU'))) { // 4.13 EQU Equalisation (ID3v2.2 only) + // There may only be one 'EQUA' frame in each tag + //
    + // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + + $frame_offset = 0; + $parsedFrame['adjustmentbits'] = substr($parsedFrame['data'], $frame_offset++, 1); + $frame_adjustmentbytes = ceil($parsedFrame['adjustmentbits'] / 8); + + $frame_remainingdata = (string) substr($parsedFrame['data'], $frame_offset); + while (strlen($frame_remainingdata) > 0) { + $frame_frequencystr = getid3_lib::BigEndian2Bin(substr($frame_remainingdata, 0, 2)); + $frame_incdec = (bool) substr($frame_frequencystr, 0, 1); + $frame_frequency = bindec(substr($frame_frequencystr, 1, 15)); + $parsedFrame[$frame_frequency]['incdec'] = $frame_incdec; + $parsedFrame[$frame_frequency]['adjustment'] = getid3_lib::BigEndian2Int(substr($frame_remainingdata, 2, $frame_adjustmentbytes)); + if ($parsedFrame[$frame_frequency]['incdec'] === false) { + $parsedFrame[$frame_frequency]['adjustment'] *= -1; + } + $frame_remainingdata = substr($frame_remainingdata, 2 + $frame_adjustmentbytes); + } + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RVRB')) || // 4.13 RVRB Reverb + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'REV'))) { // 4.14 REV Reverb + // There may only be one 'RVRB' frame in each tag. + //
    + // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + + $frame_offset = 0; + $parsedFrame['left'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['right'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['bouncesL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['bouncesR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['feedbackLL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['feedbackLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['feedbackRR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['feedbackRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['premixLR'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['premixRL'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'APIC')) || // 4.14 APIC Attached picture + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'PIC'))) { // 4.15 PIC Attached picture + // There may be several pictures attached to one file, + // each in their individual 'APIC' frame, but only one + // with the same content descriptor + //
    + // Text encoding $xx + // ID3v2.3+ => MIME type $00 + // ID3v2.2 => Image format $xx xx xx + // Picture type $xx + // Description $00 (00) + // Picture data + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + + if ($id3v2_majorversion == 2 && strlen($parsedFrame['data']) > $frame_offset) { + $frame_imagetype = substr($parsedFrame['data'], $frame_offset, 3); + if (strtolower($frame_imagetype) == 'ima') { + // complete hack for mp3Rage (www.chaoticsoftware.com) that puts ID3v2.3-formatted + // MIME type instead of 3-char ID3v2.2-format image type (thanks xbhoffØpacbell*net) + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_imagetype = strtoupper(str_replace('image/', '', strtolower($frame_mimetype))); + if ($frame_imagetype == 'JPEG') { + $frame_imagetype = 'JPG'; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + } else { + $frame_offset += 3; + } + } + if ($id3v2_majorversion > 2 && strlen($parsedFrame['data']) > $frame_offset) { + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + } + + $frame_picturetype = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + + if ($frame_offset >= $parsedFrame['datalength']) { + $info['warning'][] = 'data portion of APIC frame is missing at offset '.($parsedFrame['dataoffset'] + 8 + $frame_offset); + } else { + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + if ($id3v2_majorversion == 2) { + $parsedFrame['imagetype'] = $frame_imagetype; + } else { + $parsedFrame['mime'] = $frame_mimetype; + } + $parsedFrame['picturetypeid'] = $frame_picturetype; + $parsedFrame['picturetype'] = $this->APICPictureTypeLookup($frame_picturetype); + $parsedFrame['description'] = $frame_description; + $parsedFrame['data'] = substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding))); + $parsedFrame['datalength'] = strlen($parsedFrame['data']); + + $parsedFrame['image_mime'] = ''; + $imageinfo = array(); + $imagechunkcheck = getid3_lib::GetDataImageSize($parsedFrame['data'], $imageinfo); + if (($imagechunkcheck[2] >= 1) && ($imagechunkcheck[2] <= 3)) { + $parsedFrame['image_mime'] = 'image/'.getid3_lib::ImageTypesLookup($imagechunkcheck[2]); + if ($imagechunkcheck[0]) { + $parsedFrame['image_width'] = $imagechunkcheck[0]; + } + if ($imagechunkcheck[1]) { + $parsedFrame['image_height'] = $imagechunkcheck[1]; + } + } + + do { + if ($this->getid3->option_save_attachments === false) { + // skip entirely + unset($parsedFrame['data']); + break; + } + if ($this->getid3->option_save_attachments === true) { + // great +/* + } elseif (is_int($this->getid3->option_save_attachments)) { + if ($this->getid3->option_save_attachments < $parsedFrame['data_length']) { + // too big, skip + $info['warning'][] = 'attachment at '.$frame_offset.' is too large to process inline ('.number_format($parsedFrame['data_length']).' bytes)'; + unset($parsedFrame['data']); + break; + } +*/ + } elseif (is_string($this->getid3->option_save_attachments)) { + $dir = rtrim(str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $this->getid3->option_save_attachments), DIRECTORY_SEPARATOR); + if (!is_dir($dir) || !is_writable($dir)) { + // cannot write, skip + $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$dir.'" (not writable)'; + unset($parsedFrame['data']); + break; + } + } + // if we get this far, must be OK + if (is_string($this->getid3->option_save_attachments)) { + $destination_filename = $dir.DIRECTORY_SEPARATOR.md5($info['filenamepath']).'_'.$frame_offset; + if (!file_exists($destination_filename) || is_writable($destination_filename)) { + file_put_contents($destination_filename, $parsedFrame['data']); + } else { + $info['warning'][] = 'attachment at '.$frame_offset.' cannot be saved to "'.$destination_filename.'" (not writable)'; + } + $parsedFrame['data_filename'] = $destination_filename; + unset($parsedFrame['data']); + } else { + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + if (!isset($info['id3v2']['comments']['picture'])) { + $info['id3v2']['comments']['picture'] = array(); + } + $info['id3v2']['comments']['picture'][] = array('data'=>$parsedFrame['data'], 'image_mime'=>$parsedFrame['image_mime']); + } + } + } while (false); + } + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GEOB')) || // 4.15 GEOB General encapsulated object + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'GEO'))) { // 4.16 GEO General encapsulated object + // There may be more than one 'GEOB' frame in each tag, + // but only one with the same content descriptor + //
    + // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_mimetype) === 0) { + $frame_mimetype = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_filename = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_filename) === 0) { + $frame_filename = ''; + } + $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); + + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); + + $parsedFrame['objectdata'] = (string) substr($parsedFrame['data'], $frame_offset); + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['mime'] = $frame_mimetype; + $parsedFrame['filename'] = $frame_filename; + $parsedFrame['description'] = $frame_description; + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PCNT')) || // 4.16 PCNT Play counter + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CNT'))) { // 4.17 CNT Play counter + // There may only be one 'PCNT' frame in each tag. + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + //
    + // Counter $xx xx xx xx (xx ...) + + $parsedFrame['data'] = getid3_lib::BigEndian2Int($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POPM')) || // 4.17 POPM Popularimeter + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'POP'))) { // 4.18 POP Popularimeter + // There may be more than one 'POPM' frame in each tag, + // but only one with the same email address + //
    + // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_emailaddress = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_emailaddress) === 0) { + $frame_emailaddress = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + $frame_rating = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['counter'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset)); + $parsedFrame['email'] = $frame_emailaddress; + $parsedFrame['rating'] = $frame_rating; + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RBUF')) || // 4.18 RBUF Recommended buffer size + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'BUF'))) { // 4.19 BUF Recommended buffer size + // There may only be one 'RBUF' frame in each tag + //
    + // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + + $frame_offset = 0; + $parsedFrame['buffersize'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 3)); + $frame_offset += 3; + + $frame_embeddedinfoflags = getid3_lib::BigEndian2Bin(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['flags']['embededinfo'] = (bool) substr($frame_embeddedinfoflags, 7, 1); + $parsedFrame['nexttagoffset'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRM')) { // 4.20 Encrypted meta frame (ID3v2.2 only) + // There may be more than one 'CRM' frame in a tag, + // but only one with the same 'owner identifier' + //
    + // Owner identifier $00 (00) + // Content/explanation $00 (00) + // Encrypted datablock + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $parsedFrame['ownerid'] = $frame_ownerid; + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + $parsedFrame['description'] = $frame_description; + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'AENC')) || // 4.19 AENC Audio encryption + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'CRA'))) { // 4.21 CRA Audio encryption + // There may be more than one 'AENC' frames in a tag, + // but only one with the same 'Owner identifier' + //
    + // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid == ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + $parsedFrame['ownerid'] = $frame_ownerid; + $parsedFrame['previewstart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['previewlength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['encryptioninfo'] = (string) substr($parsedFrame['data'], $frame_offset); + unset($parsedFrame['data']); + + + } elseif ((($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'LINK')) || // 4.20 LINK Linked information + (($id3v2_majorversion == 2) && ($parsedFrame['frame_name'] == 'LNK'))) { // 4.22 LNK Linked information + // There may be more than one 'LINK' frame in a tag, + // but only one with the same contents + //
    + // ID3v2.3+ => Frame identifier $xx xx xx xx + // ID3v2.2 => Frame identifier $xx xx xx + // URL $00 + // ID and additional data + + $frame_offset = 0; + if ($id3v2_majorversion == 2) { + $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 3); + $frame_offset += 3; + } else { + $parsedFrame['frameid'] = substr($parsedFrame['data'], $frame_offset, 4); + $frame_offset += 4; + } + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_url = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_url) === 0) { + $frame_url = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + $parsedFrame['url'] = $frame_url; + + $parsedFrame['additionaldata'] = (string) substr($parsedFrame['data'], $frame_offset); + if (!empty($parsedFrame['framenameshort']) && $parsedFrame['url']) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = utf8_encode($parsedFrame['url']); + } + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'POSS')) { // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + // There may only be one 'POSS' frame in each tag + // + // Time stamp format $xx + // Position $xx (xx ...) + + $frame_offset = 0; + $parsedFrame['timestampformat'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['position'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset)); + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'USER')) { // 4.22 USER Terms of use (ID3v2.3+ only) + // There may be more than one 'Terms of use' frame in a tag, + // but only one with the same 'Language' + //
    + // Text encoding $xx + // Language $xx xx xx + // The actual text + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $frame_language = substr($parsedFrame['data'], $frame_offset, 3); + $frame_offset += 3; + $parsedFrame['language'] = $frame_language; + $parsedFrame['languagename'] = $this->LanguageLookup($frame_language, false); + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + if (!empty($parsedFrame['framenameshort']) && !empty($parsedFrame['data'])) { + $info['id3v2']['comments'][$parsedFrame['framenameshort']][] = getid3_lib::iconv_fallback($parsedFrame['encoding'], $info['id3v2']['encoding'], $parsedFrame['data']); + } + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'OWNE')) { // 4.23 OWNE Ownership frame (ID3v2.3+ only) + // There may only be one 'OWNE' frame in a tag + //
    + // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_pricepaid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $parsedFrame['pricepaid']['currencyid'] = substr($frame_pricepaid, 0, 3); + $parsedFrame['pricepaid']['currency'] = $this->LookupCurrencyUnits($parsedFrame['pricepaid']['currencyid']); + $parsedFrame['pricepaid']['value'] = substr($frame_pricepaid, 3); + + $parsedFrame['purchasedate'] = substr($parsedFrame['data'], $frame_offset, 8); + if (!$this->IsValidDateStampString($parsedFrame['purchasedate'])) { + $parsedFrame['purchasedateunix'] = mktime (0, 0, 0, substr($parsedFrame['purchasedate'], 4, 2), substr($parsedFrame['purchasedate'], 6, 2), substr($parsedFrame['purchasedate'], 0, 4)); + } + $frame_offset += 8; + + $parsedFrame['seller'] = (string) substr($parsedFrame['data'], $frame_offset); + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'COMR')) { // 4.24 COMR Commercial frame (ID3v2.3+ only) + // There may be more than one 'commercial frame' in a tag, + // but no two may be identical + //
    + // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + + $frame_offset = 0; + $frame_textencoding = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + if ((($id3v2_majorversion <= 3) && ($frame_textencoding > 1)) || (($id3v2_majorversion == 4) && ($frame_textencoding > 3))) { + $info['warning'][] = 'Invalid text encoding byte ('.$frame_textencoding.') in frame "'.$parsedFrame['frame_name'].'" - defaulting to ISO-8859-1 encoding'; + } + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_pricestring = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen("\x00"); + $frame_rawpricearray = explode('/', $frame_pricestring); + foreach ($frame_rawpricearray as $key => $val) { + $frame_currencyid = substr($val, 0, 3); + $parsedFrame['price'][$frame_currencyid]['currency'] = $this->LookupCurrencyUnits($frame_currencyid); + $parsedFrame['price'][$frame_currencyid]['value'] = substr($val, 3); + } + + $frame_datestring = substr($parsedFrame['data'], $frame_offset, 8); + $frame_offset += 8; + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_contacturl = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $frame_receivedasid = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_sellername = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_sellername) === 0) { + $frame_sellername = ''; + } + $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); + + $frame_terminatorpos = strpos($parsedFrame['data'], $this->TextEncodingTerminatorLookup($frame_textencoding), $frame_offset); + if (ord(substr($parsedFrame['data'], $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)), 1)) === 0) { + $frame_terminatorpos++; // strpos() fooled because 2nd byte of Unicode chars are often 0x00 + } + $frame_description = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_description) === 0) { + $frame_description = ''; + } + $frame_offset = $frame_terminatorpos + strlen($this->TextEncodingTerminatorLookup($frame_textencoding)); + + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_mimetype = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $frame_sellerlogo = substr($parsedFrame['data'], $frame_offset); + + $parsedFrame['encodingid'] = $frame_textencoding; + $parsedFrame['encoding'] = $this->TextEncodingNameLookup($frame_textencoding); + + $parsedFrame['pricevaliduntil'] = $frame_datestring; + $parsedFrame['contacturl'] = $frame_contacturl; + $parsedFrame['receivedasid'] = $frame_receivedasid; + $parsedFrame['receivedas'] = $this->COMRReceivedAsLookup($frame_receivedasid); + $parsedFrame['sellername'] = $frame_sellername; + $parsedFrame['description'] = $frame_description; + $parsedFrame['mime'] = $frame_mimetype; + $parsedFrame['logo'] = $frame_sellerlogo; + unset($parsedFrame['data']); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'ENCR')) { // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + // There may be several 'ENCR' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
    + // Owner identifier $00 + // Method symbol $xx + // Encryption data + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $parsedFrame['ownerid'] = $frame_ownerid; + $parsedFrame['methodsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'GRID')) { // 4.26 GRID Group identification registration (ID3v2.3+ only) + + // There may be several 'GRID' frames in a tag, + // but only one containing the same symbol + // and only one containing the same owner identifier + //
    + // Owner identifier $00 + // Group symbol $xx + // Group dependent data + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $parsedFrame['ownerid'] = $frame_ownerid; + $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'PRIV')) { // 4.27 PRIV Private frame (ID3v2.3+ only) + // The tag may contain more than one 'PRIV' frame + // but only with different contents + //
    + // Owner identifier $00 + // The private data + + $frame_offset = 0; + $frame_terminatorpos = strpos($parsedFrame['data'], "\x00", $frame_offset); + $frame_ownerid = substr($parsedFrame['data'], $frame_offset, $frame_terminatorpos - $frame_offset); + if (ord($frame_ownerid) === 0) { + $frame_ownerid = ''; + } + $frame_offset = $frame_terminatorpos + strlen("\x00"); + + $parsedFrame['ownerid'] = $frame_ownerid; + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + + + } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SIGN')) { // 4.28 SIGN Signature frame (ID3v2.4+ only) + // There may be more than one 'signature frame' in a tag, + // but no two may be identical + //
    + // Group symbol $xx + // Signature + + $frame_offset = 0; + $parsedFrame['groupsymbol'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $parsedFrame['data'] = (string) substr($parsedFrame['data'], $frame_offset); + + + } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'SEEK')) { // 4.29 SEEK Seek frame (ID3v2.4+ only) + // There may only be one 'seek frame' in a tag + //
    + // Minimum offset to next tag $xx xx xx xx + + $frame_offset = 0; + $parsedFrame['data'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + + + } elseif (($id3v2_majorversion >= 4) && ($parsedFrame['frame_name'] == 'ASPI')) { // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + // There may only be one 'audio seek point index' frame in a tag + //
    + // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + + $frame_offset = 0; + $parsedFrame['datastart'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + $frame_offset += 4; + $parsedFrame['indexeddatalength'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 4)); + $frame_offset += 4; + $parsedFrame['indexpoints'] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['bitsperpoint'] = ord(substr($parsedFrame['data'], $frame_offset++, 1)); + $frame_bytesperpoint = ceil($parsedFrame['bitsperpoint'] / 8); + for ($i = 0; $i < $frame_indexpoints; $i++) { + $parsedFrame['indexes'][$i] = getid3_lib::BigEndian2Int(substr($parsedFrame['data'], $frame_offset, $frame_bytesperpoint)); + $frame_offset += $frame_bytesperpoint; + } + unset($parsedFrame['data']); + + } elseif (($id3v2_majorversion >= 3) && ($parsedFrame['frame_name'] == 'RGAD')) { // Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + // There may only be one 'RGAD' frame in a tag + //
    + // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + $frame_offset = 0; + $parsedFrame['peakamplitude'] = getid3_lib::BigEndian2Float(substr($parsedFrame['data'], $frame_offset, 4)); + $frame_offset += 4; + $rg_track_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $rg_album_adjustment = getid3_lib::Dec2Bin(substr($parsedFrame['data'], $frame_offset, 2)); + $frame_offset += 2; + $parsedFrame['raw']['track']['name'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 0, 3)); + $parsedFrame['raw']['track']['originator'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 3, 3)); + $parsedFrame['raw']['track']['signbit'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 6, 1)); + $parsedFrame['raw']['track']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_track_adjustment, 7, 9)); + $parsedFrame['raw']['album']['name'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 0, 3)); + $parsedFrame['raw']['album']['originator'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 3, 3)); + $parsedFrame['raw']['album']['signbit'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 6, 1)); + $parsedFrame['raw']['album']['adjustment'] = getid3_lib::Bin2Dec(substr($rg_album_adjustment, 7, 9)); + $parsedFrame['track']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['track']['name']); + $parsedFrame['track']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['track']['originator']); + $parsedFrame['track']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['track']['adjustment'], $parsedFrame['raw']['track']['signbit']); + $parsedFrame['album']['name'] = getid3_lib::RGADnameLookup($parsedFrame['raw']['album']['name']); + $parsedFrame['album']['originator'] = getid3_lib::RGADoriginatorLookup($parsedFrame['raw']['album']['originator']); + $parsedFrame['album']['adjustment'] = getid3_lib::RGADadjustmentLookup($parsedFrame['raw']['album']['adjustment'], $parsedFrame['raw']['album']['signbit']); + + $info['replay_gain']['track']['peak'] = $parsedFrame['peakamplitude']; + $info['replay_gain']['track']['originator'] = $parsedFrame['track']['originator']; + $info['replay_gain']['track']['adjustment'] = $parsedFrame['track']['adjustment']; + $info['replay_gain']['album']['originator'] = $parsedFrame['album']['originator']; + $info['replay_gain']['album']['adjustment'] = $parsedFrame['album']['adjustment']; + + unset($parsedFrame['data']); + + } + + return true; + } + + + public function DeUnsynchronise($data) { + return str_replace("\xFF\x00", "\xFF", $data); + } + + public function LookupExtendedHeaderRestrictionsTagSizeLimits($index) { + static $LookupExtendedHeaderRestrictionsTagSizeLimits = array( + 0x00 => 'No more than 128 frames and 1 MB total tag size', + 0x01 => 'No more than 64 frames and 128 KB total tag size', + 0x02 => 'No more than 32 frames and 40 KB total tag size', + 0x03 => 'No more than 32 frames and 4 KB total tag size', + ); + return (isset($LookupExtendedHeaderRestrictionsTagSizeLimits[$index]) ? $LookupExtendedHeaderRestrictionsTagSizeLimits[$index] : ''); + } + + public function LookupExtendedHeaderRestrictionsTextEncodings($index) { + static $LookupExtendedHeaderRestrictionsTextEncodings = array( + 0x00 => 'No restrictions', + 0x01 => 'Strings are only encoded with ISO-8859-1 or UTF-8', + ); + return (isset($LookupExtendedHeaderRestrictionsTextEncodings[$index]) ? $LookupExtendedHeaderRestrictionsTextEncodings[$index] : ''); + } + + public function LookupExtendedHeaderRestrictionsTextFieldSize($index) { + static $LookupExtendedHeaderRestrictionsTextFieldSize = array( + 0x00 => 'No restrictions', + 0x01 => 'No string is longer than 1024 characters', + 0x02 => 'No string is longer than 128 characters', + 0x03 => 'No string is longer than 30 characters', + ); + return (isset($LookupExtendedHeaderRestrictionsTextFieldSize[$index]) ? $LookupExtendedHeaderRestrictionsTextFieldSize[$index] : ''); + } + + public function LookupExtendedHeaderRestrictionsImageEncoding($index) { + static $LookupExtendedHeaderRestrictionsImageEncoding = array( + 0x00 => 'No restrictions', + 0x01 => 'Images are encoded only with PNG or JPEG', + ); + return (isset($LookupExtendedHeaderRestrictionsImageEncoding[$index]) ? $LookupExtendedHeaderRestrictionsImageEncoding[$index] : ''); + } + + public function LookupExtendedHeaderRestrictionsImageSizeSize($index) { + static $LookupExtendedHeaderRestrictionsImageSizeSize = array( + 0x00 => 'No restrictions', + 0x01 => 'All images are 256x256 pixels or smaller', + 0x02 => 'All images are 64x64 pixels or smaller', + 0x03 => 'All images are exactly 64x64 pixels, unless required otherwise', + ); + return (isset($LookupExtendedHeaderRestrictionsImageSizeSize[$index]) ? $LookupExtendedHeaderRestrictionsImageSizeSize[$index] : ''); + } + + public function LookupCurrencyUnits($currencyid) { + + $begin = __LINE__; + + /** This is not a comment! + + + AED Dirhams + AFA Afghanis + ALL Leke + AMD Drams + ANG Guilders + AOA Kwanza + ARS Pesos + ATS Schillings + AUD Dollars + AWG Guilders + AZM Manats + BAM Convertible Marka + BBD Dollars + BDT Taka + BEF Francs + BGL Leva + BHD Dinars + BIF Francs + BMD Dollars + BND Dollars + BOB Bolivianos + BRL Brazil Real + BSD Dollars + BTN Ngultrum + BWP Pulas + BYR Rubles + BZD Dollars + CAD Dollars + CDF Congolese Francs + CHF Francs + CLP Pesos + CNY Yuan Renminbi + COP Pesos + CRC Colones + CUP Pesos + CVE Escudos + CYP Pounds + CZK Koruny + DEM Deutsche Marks + DJF Francs + DKK Kroner + DOP Pesos + DZD Algeria Dinars + EEK Krooni + EGP Pounds + ERN Nakfa + ESP Pesetas + ETB Birr + EUR Euro + FIM Markkaa + FJD Dollars + FKP Pounds + FRF Francs + GBP Pounds + GEL Lari + GGP Pounds + GHC Cedis + GIP Pounds + GMD Dalasi + GNF Francs + GRD Drachmae + GTQ Quetzales + GYD Dollars + HKD Dollars + HNL Lempiras + HRK Kuna + HTG Gourdes + HUF Forints + IDR Rupiahs + IEP Pounds + ILS New Shekels + IMP Pounds + INR Rupees + IQD Dinars + IRR Rials + ISK Kronur + ITL Lire + JEP Pounds + JMD Dollars + JOD Dinars + JPY Yen + KES Shillings + KGS Soms + KHR Riels + KMF Francs + KPW Won + KWD Dinars + KYD Dollars + KZT Tenge + LAK Kips + LBP Pounds + LKR Rupees + LRD Dollars + LSL Maloti + LTL Litai + LUF Francs + LVL Lati + LYD Dinars + MAD Dirhams + MDL Lei + MGF Malagasy Francs + MKD Denars + MMK Kyats + MNT Tugriks + MOP Patacas + MRO Ouguiyas + MTL Liri + MUR Rupees + MVR Rufiyaa + MWK Kwachas + MXN Pesos + MYR Ringgits + MZM Meticais + NAD Dollars + NGN Nairas + NIO Gold Cordobas + NLG Guilders + NOK Krone + NPR Nepal Rupees + NZD Dollars + OMR Rials + PAB Balboa + PEN Nuevos Soles + PGK Kina + PHP Pesos + PKR Rupees + PLN Zlotych + PTE Escudos + PYG Guarani + QAR Rials + ROL Lei + RUR Rubles + RWF Rwanda Francs + SAR Riyals + SBD Dollars + SCR Rupees + SDD Dinars + SEK Kronor + SGD Dollars + SHP Pounds + SIT Tolars + SKK Koruny + SLL Leones + SOS Shillings + SPL Luigini + SRG Guilders + STD Dobras + SVC Colones + SYP Pounds + SZL Emalangeni + THB Baht + TJR Rubles + TMM Manats + TND Dinars + TOP Pa'anga + TRL Liras + TTD Dollars + TVD Tuvalu Dollars + TWD New Dollars + TZS Shillings + UAH Hryvnia + UGX Shillings + USD Dollars + UYU Pesos + UZS Sums + VAL Lire + VEB Bolivares + VND Dong + VUV Vatu + WST Tala + XAF Francs + XAG Ounces + XAU Ounces + XCD Dollars + XDR Special Drawing Rights + XPD Ounces + XPF Francs + XPT Ounces + YER Rials + YUM New Dinars + ZAR Rand + ZMK Kwacha + ZWD Zimbabwe Dollars + + */ + + return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-units'); + } + + + public function LookupCurrencyCountry($currencyid) { + + $begin = __LINE__; + + /** This is not a comment! + + AED United Arab Emirates + AFA Afghanistan + ALL Albania + AMD Armenia + ANG Netherlands Antilles + AOA Angola + ARS Argentina + ATS Austria + AUD Australia + AWG Aruba + AZM Azerbaijan + BAM Bosnia and Herzegovina + BBD Barbados + BDT Bangladesh + BEF Belgium + BGL Bulgaria + BHD Bahrain + BIF Burundi + BMD Bermuda + BND Brunei Darussalam + BOB Bolivia + BRL Brazil + BSD Bahamas + BTN Bhutan + BWP Botswana + BYR Belarus + BZD Belize + CAD Canada + CDF Congo/Kinshasa + CHF Switzerland + CLP Chile + CNY China + COP Colombia + CRC Costa Rica + CUP Cuba + CVE Cape Verde + CYP Cyprus + CZK Czech Republic + DEM Germany + DJF Djibouti + DKK Denmark + DOP Dominican Republic + DZD Algeria + EEK Estonia + EGP Egypt + ERN Eritrea + ESP Spain + ETB Ethiopia + EUR Euro Member Countries + FIM Finland + FJD Fiji + FKP Falkland Islands (Malvinas) + FRF France + GBP United Kingdom + GEL Georgia + GGP Guernsey + GHC Ghana + GIP Gibraltar + GMD Gambia + GNF Guinea + GRD Greece + GTQ Guatemala + GYD Guyana + HKD Hong Kong + HNL Honduras + HRK Croatia + HTG Haiti + HUF Hungary + IDR Indonesia + IEP Ireland (Eire) + ILS Israel + IMP Isle of Man + INR India + IQD Iraq + IRR Iran + ISK Iceland + ITL Italy + JEP Jersey + JMD Jamaica + JOD Jordan + JPY Japan + KES Kenya + KGS Kyrgyzstan + KHR Cambodia + KMF Comoros + KPW Korea + KWD Kuwait + KYD Cayman Islands + KZT Kazakstan + LAK Laos + LBP Lebanon + LKR Sri Lanka + LRD Liberia + LSL Lesotho + LTL Lithuania + LUF Luxembourg + LVL Latvia + LYD Libya + MAD Morocco + MDL Moldova + MGF Madagascar + MKD Macedonia + MMK Myanmar (Burma) + MNT Mongolia + MOP Macau + MRO Mauritania + MTL Malta + MUR Mauritius + MVR Maldives (Maldive Islands) + MWK Malawi + MXN Mexico + MYR Malaysia + MZM Mozambique + NAD Namibia + NGN Nigeria + NIO Nicaragua + NLG Netherlands (Holland) + NOK Norway + NPR Nepal + NZD New Zealand + OMR Oman + PAB Panama + PEN Peru + PGK Papua New Guinea + PHP Philippines + PKR Pakistan + PLN Poland + PTE Portugal + PYG Paraguay + QAR Qatar + ROL Romania + RUR Russia + RWF Rwanda + SAR Saudi Arabia + SBD Solomon Islands + SCR Seychelles + SDD Sudan + SEK Sweden + SGD Singapore + SHP Saint Helena + SIT Slovenia + SKK Slovakia + SLL Sierra Leone + SOS Somalia + SPL Seborga + SRG Suriname + STD São Tome and Principe + SVC El Salvador + SYP Syria + SZL Swaziland + THB Thailand + TJR Tajikistan + TMM Turkmenistan + TND Tunisia + TOP Tonga + TRL Turkey + TTD Trinidad and Tobago + TVD Tuvalu + TWD Taiwan + TZS Tanzania + UAH Ukraine + UGX Uganda + USD United States of America + UYU Uruguay + UZS Uzbekistan + VAL Vatican City + VEB Venezuela + VND Viet Nam + VUV Vanuatu + WST Samoa + XAF Communauté Financière Africaine + XAG Silver + XAU Gold + XCD East Caribbean + XDR International Monetary Fund + XPD Palladium + XPF Comptoirs Français du Pacifique + XPT Platinum + YER Yemen + YUM Yugoslavia + ZAR South Africa + ZMK Zambia + ZWD Zimbabwe + + */ + + return getid3_lib::EmbeddedLookup($currencyid, $begin, __LINE__, __FILE__, 'id3v2-currency-country'); + } + + + + public static function LanguageLookup($languagecode, $casesensitive=false) { + + if (!$casesensitive) { + $languagecode = strtolower($languagecode); + } + + // http://www.id3.org/id3v2.4.0-structure.txt + // [4. ID3v2 frame overview] + // The three byte language field, present in several frames, is used to + // describe the language of the frame's content, according to ISO-639-2 + // [ISO-639-2]. The language should be represented in lower case. If the + // language is not known the string "XXX" should be used. + + + // ISO 639-2 - http://www.id3.org/iso639-2.html + + $begin = __LINE__; + + /** This is not a comment! + + XXX unknown + xxx unknown + aar Afar + abk Abkhazian + ace Achinese + ach Acoli + ada Adangme + afa Afro-Asiatic (Other) + afh Afrihili + afr Afrikaans + aka Akan + akk Akkadian + alb Albanian + ale Aleut + alg Algonquian Languages + amh Amharic + ang English, Old (ca. 450-1100) + apa Apache Languages + ara Arabic + arc Aramaic + arm Armenian + arn Araucanian + arp Arapaho + art Artificial (Other) + arw Arawak + asm Assamese + ath Athapascan Languages + ava Avaric + ave Avestan + awa Awadhi + aym Aymara + aze Azerbaijani + bad Banda + bai Bamileke Languages + bak Bashkir + bal Baluchi + bam Bambara + ban Balinese + baq Basque + bas Basa + bat Baltic (Other) + bej Beja + bel Byelorussian + bem Bemba + ben Bengali + ber Berber (Other) + bho Bhojpuri + bih Bihari + bik Bikol + bin Bini + bis Bislama + bla Siksika + bnt Bantu (Other) + bod Tibetan + bra Braj + bre Breton + bua Buriat + bug Buginese + bul Bulgarian + bur Burmese + cad Caddo + cai Central American Indian (Other) + car Carib + cat Catalan + cau Caucasian (Other) + ceb Cebuano + cel Celtic (Other) + ces Czech + cha Chamorro + chb Chibcha + che Chechen + chg Chagatai + chi Chinese + chm Mari + chn Chinook jargon + cho Choctaw + chr Cherokee + chu Church Slavic + chv Chuvash + chy Cheyenne + cop Coptic + cor Cornish + cos Corsican + cpe Creoles and Pidgins, English-based (Other) + cpf Creoles and Pidgins, French-based (Other) + cpp Creoles and Pidgins, Portuguese-based (Other) + cre Cree + crp Creoles and Pidgins (Other) + cus Cushitic (Other) + cym Welsh + cze Czech + dak Dakota + dan Danish + del Delaware + deu German + din Dinka + div Divehi + doi Dogri + dra Dravidian (Other) + dua Duala + dum Dutch, Middle (ca. 1050-1350) + dut Dutch + dyu Dyula + dzo Dzongkha + efi Efik + egy Egyptian (Ancient) + eka Ekajuk + ell Greek, Modern (1453-) + elx Elamite + eng English + enm English, Middle (ca. 1100-1500) + epo Esperanto + esk Eskimo (Other) + esl Spanish + est Estonian + eus Basque + ewe Ewe + ewo Ewondo + fan Fang + fao Faroese + fas Persian + fat Fanti + fij Fijian + fin Finnish + fiu Finno-Ugrian (Other) + fon Fon + fra French + fre French + frm French, Middle (ca. 1400-1600) + fro French, Old (842- ca. 1400) + fry Frisian + ful Fulah + gaa Ga + gae Gaelic (Scots) + gai Irish + gay Gayo + gdh Gaelic (Scots) + gem Germanic (Other) + geo Georgian + ger German + gez Geez + gil Gilbertese + glg Gallegan + gmh German, Middle High (ca. 1050-1500) + goh German, Old High (ca. 750-1050) + gon Gondi + got Gothic + grb Grebo + grc Greek, Ancient (to 1453) + gre Greek, Modern (1453-) + grn Guarani + guj Gujarati + hai Haida + hau Hausa + haw Hawaiian + heb Hebrew + her Herero + hil Hiligaynon + him Himachali + hin Hindi + hmo Hiri Motu + hun Hungarian + hup Hupa + hye Armenian + iba Iban + ibo Igbo + ice Icelandic + ijo Ijo + iku Inuktitut + ilo Iloko + ina Interlingua (International Auxiliary language Association) + inc Indic (Other) + ind Indonesian + ine Indo-European (Other) + ine Interlingue + ipk Inupiak + ira Iranian (Other) + iri Irish + iro Iroquoian uages + isl Icelandic + ita Italian + jav Javanese + jaw Javanese + jpn Japanese + jpr Judeo-Persian + jrb Judeo-Arabic + kaa Kara-Kalpak + kab Kabyle + kac Kachin + kal Greenlandic + kam Kamba + kan Kannada + kar Karen + kas Kashmiri + kat Georgian + kau Kanuri + kaw Kawi + kaz Kazakh + kha Khasi + khi Khoisan (Other) + khm Khmer + kho Khotanese + kik Kikuyu + kin Kinyarwanda + kir Kirghiz + kok Konkani + kom Komi + kon Kongo + kor Korean + kpe Kpelle + kro Kru + kru Kurukh + kua Kuanyama + kum Kumyk + kur Kurdish + kus Kusaie + kut Kutenai + lad Ladino + lah Lahnda + lam Lamba + lao Lao + lat Latin + lav Latvian + lez Lezghian + lin Lingala + lit Lithuanian + lol Mongo + loz Lozi + ltz Letzeburgesch + lub Luba-Katanga + lug Ganda + lui Luiseno + lun Lunda + luo Luo (Kenya and Tanzania) + mac Macedonian + mad Madurese + mag Magahi + mah Marshall + mai Maithili + mak Macedonian + mak Makasar + mal Malayalam + man Mandingo + mao Maori + map Austronesian (Other) + mar Marathi + mas Masai + max Manx + may Malay + men Mende + mga Irish, Middle (900 - 1200) + mic Micmac + min Minangkabau + mis Miscellaneous (Other) + mkh Mon-Kmer (Other) + mlg Malagasy + mlt Maltese + mni Manipuri + mno Manobo Languages + moh Mohawk + mol Moldavian + mon Mongolian + mos Mossi + mri Maori + msa Malay + mul Multiple Languages + mun Munda Languages + mus Creek + mwr Marwari + mya Burmese + myn Mayan Languages + nah Aztec + nai North American Indian (Other) + nau Nauru + nav Navajo + nbl Ndebele, South + nde Ndebele, North + ndo Ndongo + nep Nepali + new Newari + nic Niger-Kordofanian (Other) + niu Niuean + nla Dutch + nno Norwegian (Nynorsk) + non Norse, Old + nor Norwegian + nso Sotho, Northern + nub Nubian Languages + nya Nyanja + nym Nyamwezi + nyn Nyankole + nyo Nyoro + nzi Nzima + oci Langue d'Oc (post 1500) + oji Ojibwa + ori Oriya + orm Oromo + osa Osage + oss Ossetic + ota Turkish, Ottoman (1500 - 1928) + oto Otomian Languages + paa Papuan-Australian (Other) + pag Pangasinan + pal Pahlavi + pam Pampanga + pan Panjabi + pap Papiamento + pau Palauan + peo Persian, Old (ca 600 - 400 B.C.) + per Persian + phn Phoenician + pli Pali + pol Polish + pon Ponape + por Portuguese + pra Prakrit uages + pro Provencal, Old (to 1500) + pus Pushto + que Quechua + raj Rajasthani + rar Rarotongan + roa Romance (Other) + roh Rhaeto-Romance + rom Romany + ron Romanian + rum Romanian + run Rundi + rus Russian + sad Sandawe + sag Sango + sah Yakut + sai South American Indian (Other) + sal Salishan Languages + sam Samaritan Aramaic + san Sanskrit + sco Scots + scr Serbo-Croatian + sel Selkup + sem Semitic (Other) + sga Irish, Old (to 900) + shn Shan + sid Sidamo + sin Singhalese + sio Siouan Languages + sit Sino-Tibetan (Other) + sla Slavic (Other) + slk Slovak + slo Slovak + slv Slovenian + smi Sami Languages + smo Samoan + sna Shona + snd Sindhi + sog Sogdian + som Somali + son Songhai + sot Sotho, Southern + spa Spanish + sqi Albanian + srd Sardinian + srr Serer + ssa Nilo-Saharan (Other) + ssw Siswant + ssw Swazi + suk Sukuma + sun Sudanese + sus Susu + sux Sumerian + sve Swedish + swa Swahili + swe Swedish + syr Syriac + tah Tahitian + tam Tamil + tat Tatar + tel Telugu + tem Timne + ter Tereno + tgk Tajik + tgl Tagalog + tha Thai + tib Tibetan + tig Tigre + tir Tigrinya + tiv Tivi + tli Tlingit + tmh Tamashek + tog Tonga (Nyasa) + ton Tonga (Tonga Islands) + tru Truk + tsi Tsimshian + tsn Tswana + tso Tsonga + tuk Turkmen + tum Tumbuka + tur Turkish + tut Altaic (Other) + twi Twi + tyv Tuvinian + uga Ugaritic + uig Uighur + ukr Ukrainian + umb Umbundu + und Undetermined + urd Urdu + uzb Uzbek + vai Vai + ven Venda + vie Vietnamese + vol Volapük + vot Votic + wak Wakashan Languages + wal Walamo + war Waray + was Washo + wel Welsh + wen Sorbian Languages + wol Wolof + xho Xhosa + yao Yao + yap Yap + yid Yiddish + yor Yoruba + zap Zapotec + zen Zenaga + zha Zhuang + zho Chinese + zul Zulu + zun Zuni + + */ + + return getid3_lib::EmbeddedLookup($languagecode, $begin, __LINE__, __FILE__, 'id3v2-languagecode'); + } + + + public static function ETCOEventLookup($index) { + if (($index >= 0x17) && ($index <= 0xDF)) { + return 'reserved for future use'; + } + if (($index >= 0xE0) && ($index <= 0xEF)) { + return 'not predefined synch 0-F'; + } + if (($index >= 0xF0) && ($index <= 0xFC)) { + return 'reserved for future use'; + } + + static $EventLookup = array( + 0x00 => 'padding (has no meaning)', + 0x01 => 'end of initial silence', + 0x02 => 'intro start', + 0x03 => 'main part start', + 0x04 => 'outro start', + 0x05 => 'outro end', + 0x06 => 'verse start', + 0x07 => 'refrain start', + 0x08 => 'interlude start', + 0x09 => 'theme start', + 0x0A => 'variation start', + 0x0B => 'key change', + 0x0C => 'time change', + 0x0D => 'momentary unwanted noise (Snap, Crackle & Pop)', + 0x0E => 'sustained noise', + 0x0F => 'sustained noise end', + 0x10 => 'intro end', + 0x11 => 'main part end', + 0x12 => 'verse end', + 0x13 => 'refrain end', + 0x14 => 'theme end', + 0x15 => 'profanity', + 0x16 => 'profanity end', + 0xFD => 'audio end (start of silence)', + 0xFE => 'audio file ends', + 0xFF => 'one more byte of events follows' + ); + + return (isset($EventLookup[$index]) ? $EventLookup[$index] : ''); + } + + public static function SYTLContentTypeLookup($index) { + static $SYTLContentTypeLookup = array( + 0x00 => 'other', + 0x01 => 'lyrics', + 0x02 => 'text transcription', + 0x03 => 'movement/part name', // (e.g. 'Adagio') + 0x04 => 'events', // (e.g. 'Don Quijote enters the stage') + 0x05 => 'chord', // (e.g. 'Bb F Fsus') + 0x06 => 'trivia/\'pop up\' information', + 0x07 => 'URLs to webpages', + 0x08 => 'URLs to images' + ); + + return (isset($SYTLContentTypeLookup[$index]) ? $SYTLContentTypeLookup[$index] : ''); + } + + public static function APICPictureTypeLookup($index, $returnarray=false) { + static $APICPictureTypeLookup = array( + 0x00 => 'Other', + 0x01 => '32x32 pixels \'file icon\' (PNG only)', + 0x02 => 'Other file icon', + 0x03 => 'Cover (front)', + 0x04 => 'Cover (back)', + 0x05 => 'Leaflet page', + 0x06 => 'Media (e.g. label side of CD)', + 0x07 => 'Lead artist/lead performer/soloist', + 0x08 => 'Artist/performer', + 0x09 => 'Conductor', + 0x0A => 'Band/Orchestra', + 0x0B => 'Composer', + 0x0C => 'Lyricist/text writer', + 0x0D => 'Recording Location', + 0x0E => 'During recording', + 0x0F => 'During performance', + 0x10 => 'Movie/video screen capture', + 0x11 => 'A bright coloured fish', + 0x12 => 'Illustration', + 0x13 => 'Band/artist logotype', + 0x14 => 'Publisher/Studio logotype' + ); + if ($returnarray) { + return $APICPictureTypeLookup; + } + return (isset($APICPictureTypeLookup[$index]) ? $APICPictureTypeLookup[$index] : ''); + } + + public static function COMRReceivedAsLookup($index) { + static $COMRReceivedAsLookup = array( + 0x00 => 'Other', + 0x01 => 'Standard CD album with other songs', + 0x02 => 'Compressed audio on CD', + 0x03 => 'File over the Internet', + 0x04 => 'Stream over the Internet', + 0x05 => 'As note sheets', + 0x06 => 'As note sheets in a book with other sheets', + 0x07 => 'Music on other media', + 0x08 => 'Non-musical merchandise' + ); + + return (isset($COMRReceivedAsLookup[$index]) ? $COMRReceivedAsLookup[$index] : ''); + } + + public static function RVA2ChannelTypeLookup($index) { + static $RVA2ChannelTypeLookup = array( + 0x00 => 'Other', + 0x01 => 'Master volume', + 0x02 => 'Front right', + 0x03 => 'Front left', + 0x04 => 'Back right', + 0x05 => 'Back left', + 0x06 => 'Front centre', + 0x07 => 'Back centre', + 0x08 => 'Subwoofer' + ); + + return (isset($RVA2ChannelTypeLookup[$index]) ? $RVA2ChannelTypeLookup[$index] : ''); + } + + public static function FrameNameLongLookup($framename) { + + $begin = __LINE__; + + /** This is not a comment! + + AENC Audio encryption + APIC Attached picture + ASPI Audio seek point index + BUF Recommended buffer size + CNT Play counter + COM Comments + COMM Comments + COMR Commercial frame + CRA Audio encryption + CRM Encrypted meta frame + ENCR Encryption method registration + EQU Equalisation + EQU2 Equalisation (2) + EQUA Equalisation + ETC Event timing codes + ETCO Event timing codes + GEO General encapsulated object + GEOB General encapsulated object + GRID Group identification registration + IPL Involved people list + IPLS Involved people list + LINK Linked information + LNK Linked information + MCDI Music CD identifier + MCI Music CD Identifier + MLL MPEG location lookup table + MLLT MPEG location lookup table + OWNE Ownership frame + PCNT Play counter + PIC Attached picture + POP Popularimeter + POPM Popularimeter + POSS Position synchronisation frame + PRIV Private frame + RBUF Recommended buffer size + REV Reverb + RVA Relative volume adjustment + RVA2 Relative volume adjustment (2) + RVAD Relative volume adjustment + RVRB Reverb + SEEK Seek frame + SIGN Signature frame + SLT Synchronised lyric/text + STC Synced tempo codes + SYLT Synchronised lyric/text + SYTC Synchronised tempo codes + TAL Album/Movie/Show title + TALB Album/Movie/Show title + TBP BPM (Beats Per Minute) + TBPM BPM (beats per minute) + TCM Composer + TCMP Part of a compilation + TCO Content type + TCOM Composer + TCON Content type + TCOP Copyright message + TCP Part of a compilation + TCR Copyright message + TDA Date + TDAT Date + TDEN Encoding time + TDLY Playlist delay + TDOR Original release time + TDRC Recording time + TDRL Release time + TDTG Tagging time + TDY Playlist delay + TEN Encoded by + TENC Encoded by + TEXT Lyricist/Text writer + TFLT File type + TFT File type + TIM Time + TIME Time + TIPL Involved people list + TIT1 Content group description + TIT2 Title/songname/content description + TIT3 Subtitle/Description refinement + TKE Initial key + TKEY Initial key + TLA Language(s) + TLAN Language(s) + TLE Length + TLEN Length + TMCL Musician credits list + TMED Media type + TMOO Mood + TMT Media type + TOA Original artist(s)/performer(s) + TOAL Original album/movie/show title + TOF Original filename + TOFN Original filename + TOL Original Lyricist(s)/text writer(s) + TOLY Original lyricist(s)/text writer(s) + TOPE Original artist(s)/performer(s) + TOR Original release year + TORY Original release year + TOT Original album/Movie/Show title + TOWN File owner/licensee + TP1 Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group + TP2 Band/Orchestra/Accompaniment + TP3 Conductor/Performer refinement + TP4 Interpreted, remixed, or otherwise modified by + TPA Part of a set + TPB Publisher + TPE1 Lead performer(s)/Soloist(s) + TPE2 Band/orchestra/accompaniment + TPE3 Conductor/performer refinement + TPE4 Interpreted, remixed, or otherwise modified by + TPOS Part of a set + TPRO Produced notice + TPUB Publisher + TRC ISRC (International Standard Recording Code) + TRCK Track number/Position in set + TRD Recording dates + TRDA Recording dates + TRK Track number/Position in set + TRSN Internet radio station name + TRSO Internet radio station owner + TS2 Album-Artist sort order + TSA Album sort order + TSC Composer sort order + TSI Size + TSIZ Size + TSO2 Album-Artist sort order + TSOA Album sort order + TSOC Composer sort order + TSOP Performer sort order + TSOT Title sort order + TSP Performer sort order + TSRC ISRC (international standard recording code) + TSS Software/hardware and settings used for encoding + TSSE Software/Hardware and settings used for encoding + TSST Set subtitle + TST Title sort order + TT1 Content group description + TT2 Title/Songname/Content description + TT3 Subtitle/Description refinement + TXT Lyricist/text writer + TXX User defined text information frame + TXXX User defined text information frame + TYE Year + TYER Year + UFI Unique file identifier + UFID Unique file identifier + ULT Unsychronised lyric/text transcription + USER Terms of use + USLT Unsynchronised lyric/text transcription + WAF Official audio file webpage + WAR Official artist/performer webpage + WAS Official audio source webpage + WCM Commercial information + WCOM Commercial information + WCOP Copyright/Legal information + WCP Copyright/Legal information + WOAF Official audio file webpage + WOAR Official artist/performer webpage + WOAS Official audio source webpage + WORS Official Internet radio station homepage + WPAY Payment + WPB Publishers official webpage + WPUB Publishers official webpage + WXX User defined URL link frame + WXXX User defined URL link frame + TFEA Featured Artist + TSTU Recording Studio + rgad Replay Gain Adjustment + + */ + + return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_long'); + + // Last three: + // from Helium2 [www.helium2.com] + // from http://privatewww.essex.ac.uk/~djmrob/replaygain/file_format_id3v2.html + } + + + public static function FrameNameShortLookup($framename) { + + $begin = __LINE__; + + /** This is not a comment! + + AENC audio_encryption + APIC attached_picture + ASPI audio_seek_point_index + BUF recommended_buffer_size + CNT play_counter + COM comment + COMM comment + COMR commercial_frame + CRA audio_encryption + CRM encrypted_meta_frame + ENCR encryption_method_registration + EQU equalisation + EQU2 equalisation + EQUA equalisation + ETC event_timing_codes + ETCO event_timing_codes + GEO general_encapsulated_object + GEOB general_encapsulated_object + GRID group_identification_registration + IPL involved_people_list + IPLS involved_people_list + LINK linked_information + LNK linked_information + MCDI music_cd_identifier + MCI music_cd_identifier + MLL mpeg_location_lookup_table + MLLT mpeg_location_lookup_table + OWNE ownership_frame + PCNT play_counter + PIC attached_picture + POP popularimeter + POPM popularimeter + POSS position_synchronisation_frame + PRIV private_frame + RBUF recommended_buffer_size + REV reverb + RVA relative_volume_adjustment + RVA2 relative_volume_adjustment + RVAD relative_volume_adjustment + RVRB reverb + SEEK seek_frame + SIGN signature_frame + SLT synchronised_lyric + STC synced_tempo_codes + SYLT synchronised_lyric + SYTC synchronised_tempo_codes + TAL album + TALB album + TBP bpm + TBPM bpm + TCM composer + TCMP part_of_a_compilation + TCO genre + TCOM composer + TCON genre + TCOP copyright_message + TCP part_of_a_compilation + TCR copyright_message + TDA date + TDAT date + TDEN encoding_time + TDLY playlist_delay + TDOR original_release_time + TDRC recording_time + TDRL release_time + TDTG tagging_time + TDY playlist_delay + TEN encoded_by + TENC encoded_by + TEXT lyricist + TFLT file_type + TFT file_type + TIM time + TIME time + TIPL involved_people_list + TIT1 content_group_description + TIT2 title + TIT3 subtitle + TKE initial_key + TKEY initial_key + TLA language + TLAN language + TLE length + TLEN length + TMCL musician_credits_list + TMED media_type + TMOO mood + TMT media_type + TOA original_artist + TOAL original_album + TOF original_filename + TOFN original_filename + TOL original_lyricist + TOLY original_lyricist + TOPE original_artist + TOR original_year + TORY original_year + TOT original_album + TOWN file_owner + TP1 artist + TP2 band + TP3 conductor + TP4 remixer + TPA part_of_a_set + TPB publisher + TPE1 artist + TPE2 band + TPE3 conductor + TPE4 remixer + TPOS part_of_a_set + TPRO produced_notice + TPUB publisher + TRC isrc + TRCK track_number + TRD recording_dates + TRDA recording_dates + TRK track_number + TRSN internet_radio_station_name + TRSO internet_radio_station_owner + TS2 album_artist_sort_order + TSA album_sort_order + TSC composer_sort_order + TSI size + TSIZ size + TSO2 album_artist_sort_order + TSOA album_sort_order + TSOC composer_sort_order + TSOP performer_sort_order + TSOT title_sort_order + TSP performer_sort_order + TSRC isrc + TSS encoder_settings + TSSE encoder_settings + TSST set_subtitle + TST title_sort_order + TT1 content_group_description + TT2 title + TT3 subtitle + TXT lyricist + TXX text + TXXX text + TYE year + TYER year + UFI unique_file_identifier + UFID unique_file_identifier + ULT unsychronised_lyric + USER terms_of_use + USLT unsynchronised_lyric + WAF url_file + WAR url_artist + WAS url_source + WCM commercial_information + WCOM commercial_information + WCOP copyright + WCP copyright + WOAF url_file + WOAR url_artist + WOAS url_source + WORS url_station + WPAY url_payment + WPB url_publisher + WPUB url_publisher + WXX url_user + WXXX url_user + TFEA featured_artist + TSTU recording_studio + rgad replay_gain_adjustment + + */ + + return getid3_lib::EmbeddedLookup($framename, $begin, __LINE__, __FILE__, 'id3v2-framename_short'); + } + + public static function TextEncodingTerminatorLookup($encoding) { + // http://www.id3.org/id3v2.4.0-structure.txt + // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: + static $TextEncodingTerminatorLookup = array( + 0 => "\x00", // $00 ISO-8859-1. Terminated with $00. + 1 => "\x00\x00", // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. + 2 => "\x00\x00", // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. + 3 => "\x00", // $03 UTF-8 encoded Unicode. Terminated with $00. + 255 => "\x00\x00" + ); + return (isset($TextEncodingTerminatorLookup[$encoding]) ? $TextEncodingTerminatorLookup[$encoding] : ''); + } + + public static function TextEncodingNameLookup($encoding) { + // http://www.id3.org/id3v2.4.0-structure.txt + // Frames that allow different types of text encoding contains a text encoding description byte. Possible encodings: + static $TextEncodingNameLookup = array( + 0 => 'ISO-8859-1', // $00 ISO-8859-1. Terminated with $00. + 1 => 'UTF-16', // $01 UTF-16 encoded Unicode with BOM. All strings in the same frame SHALL have the same byteorder. Terminated with $00 00. + 2 => 'UTF-16BE', // $02 UTF-16BE encoded Unicode without BOM. Terminated with $00 00. + 3 => 'UTF-8', // $03 UTF-8 encoded Unicode. Terminated with $00. + 255 => 'UTF-16BE' + ); + return (isset($TextEncodingNameLookup[$encoding]) ? $TextEncodingNameLookup[$encoding] : 'ISO-8859-1'); + } + + public static function IsValidID3v2FrameName($framename, $id3v2majorversion) { + switch ($id3v2majorversion) { + case 2: + return preg_match('#[A-Z][A-Z0-9]{2}#', $framename); + break; + + case 3: + case 4: + return preg_match('#[A-Z][A-Z0-9]{3}#', $framename); + break; + } + return false; + } + + public static function IsANumber($numberstring, $allowdecimal=false, $allownegative=false) { + for ($i = 0; $i < strlen($numberstring); $i++) { + if ((chr($numberstring{$i}) < chr('0')) || (chr($numberstring{$i}) > chr('9'))) { + if (($numberstring{$i} == '.') && $allowdecimal) { + // allowed + } elseif (($numberstring{$i} == '-') && $allownegative && ($i == 0)) { + // allowed + } else { + return false; + } + } + } + return true; + } + + public static function IsValidDateStampString($datestamp) { + if (strlen($datestamp) != 8) { + return false; + } + if (!self::IsANumber($datestamp, false)) { + return false; + } + $year = substr($datestamp, 0, 4); + $month = substr($datestamp, 4, 2); + $day = substr($datestamp, 6, 2); + if (($year == 0) || ($month == 0) || ($day == 0)) { + return false; + } + if ($month > 12) { + return false; + } + if ($day > 31) { + return false; + } + if (($day > 30) && (($month == 4) || ($month == 6) || ($month == 9) || ($month == 11))) { + return false; + } + if (($day > 29) && ($month == 2)) { + return false; + } + return true; + } + + public static function ID3v2HeaderLength($majorversion) { + return (($majorversion == 2) ? 6 : 10); + } + +} + diff --git a/app/libs/vendor/getid3/module.tag.lyrics3.php b/app/libs/vendor/getid3/module.tag.lyrics3.php index 772c0d9c..108d7aee 100644 --- a/app/libs/vendor/getid3/module.tag.lyrics3.php +++ b/app/libs/vendor/getid3/module.tag.lyrics3.php @@ -1,294 +1,294 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -/// // -// module.tag.lyrics3.php // -// module for analyzing Lyrics3 tags // -// dependencies: module.tag.apetag.php (optional) // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_lyrics3 extends getid3_handler -{ - - public function Analyze() { - $info = &$this->getid3->info; - - // http://www.volweb.cz/str/tags.htm - - if (!getid3_lib::intValueSupported($info['filesize'])) { - $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - - fseek($this->getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size] - $lyrics3_id3v1 = fread($this->getid3->fp, 128 + 9 + 6); - $lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size - $lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200 - $id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1 - - if ($lyrics3end == 'LYRICSEND') { - // Lyrics3v1, ID3v1, no APE - - $lyrics3size = 5100; - $lyrics3offset = $info['filesize'] - 128 - $lyrics3size; - $lyrics3version = 1; - - } elseif ($lyrics3end == 'LYRICS200') { - // Lyrics3v2, ID3v1, no APE - - // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' - $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); - $lyrics3offset = $info['filesize'] - 128 - $lyrics3size; - $lyrics3version = 2; - - } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) { - // Lyrics3v1, no ID3v1, no APE - - $lyrics3size = 5100; - $lyrics3offset = $info['filesize'] - $lyrics3size; - $lyrics3version = 1; - $lyrics3offset = $info['filesize'] - $lyrics3size; - - } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) { - - // Lyrics3v2, no ID3v1, no APE - - $lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' - $lyrics3offset = $info['filesize'] - $lyrics3size; - $lyrics3version = 2; - - } else { - - if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) { - - fseek($this->getid3->fp, $info['ape']['tag_offset_start'] - 15, SEEK_SET); - $lyrics3lsz = fread($this->getid3->fp, 6); - $lyrics3end = fread($this->getid3->fp, 9); - - if ($lyrics3end == 'LYRICSEND') { - // Lyrics3v1, APE, maybe ID3v1 - - $lyrics3size = 5100; - $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size; - $info['avdataend'] = $lyrics3offset; - $lyrics3version = 1; - $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability'; - - } elseif ($lyrics3end == 'LYRICS200') { - // Lyrics3v2, APE, maybe ID3v1 - - $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' - $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size; - $lyrics3version = 2; - $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability'; - - } - - } - - } - - if (isset($lyrics3offset)) { - $info['avdataend'] = $lyrics3offset; - $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size); - - if (!isset($info['ape'])) { - $GETID3_ERRORARRAY = &$info['warning']; - if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) { - $getid3_temp = new getID3(); - $getid3_temp->openfile($this->getid3->filename); - $getid3_apetag = new getid3_apetag($getid3_temp); - $getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start']; - $getid3_apetag->Analyze(); - if (!empty($getid3_temp->info['ape'])) { - $info['ape'] = $getid3_temp->info['ape']; - } - if (!empty($getid3_temp->info['replay_gain'])) { - $info['replay_gain'] = $getid3_temp->info['replay_gain']; - } - unset($getid3_temp, $getid3_apetag); - } - } - - } - - return true; - } - - public function getLyrics3Data($endoffset, $version, $length) { - // http://www.volweb.cz/str/tags.htm - - $info = &$this->getid3->info; - - if (!getid3_lib::intValueSupported($endoffset)) { - $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - - fseek($this->getid3->fp, $endoffset, SEEK_SET); - if ($length <= 0) { - return false; - } - $rawdata = fread($this->getid3->fp, $length); - - $ParsedLyrics3['raw']['lyrics3version'] = $version; - $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; - $ParsedLyrics3['tag_offset_start'] = $endoffset; - $ParsedLyrics3['tag_offset_end'] = $endoffset + $length - 1; - - if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') { - if (strpos($rawdata, 'LYRICSBEGIN') !== false) { - - $info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version; - $info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN'); - $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN')); - $length = strlen($rawdata); - $ParsedLyrics3['tag_offset_start'] = $info['avdataend']; - $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; - - } else { - - $info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead'; - return false; - - } - - } - - switch ($version) { - - case 1: - if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') { - $ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9)); - $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); - } else { - $info['error'][] = '"LYRICSEND" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'; - return false; - } - break; - - case 2: - if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') { - $ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ - $rawdata = $ParsedLyrics3['raw']['unparsed']; - while (strlen($rawdata) > 0) { - $fieldname = substr($rawdata, 0, 3); - $fieldsize = (int) substr($rawdata, 3, 5); - $ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize); - $rawdata = substr($rawdata, 3 + 5 + $fieldsize); - } - - if (isset($ParsedLyrics3['raw']['IND'])) { - $i = 0; - $flagnames = array('lyrics', 'timestamps', 'inhibitrandom'); - foreach ($flagnames as $flagname) { - if (strlen($ParsedLyrics3['raw']['IND']) > $i++) { - $ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1)); - } - } - } - - $fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author'); - foreach ($fieldnametranslation as $key => $value) { - if (isset($ParsedLyrics3['raw'][$key])) { - $ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]); - } - } - - if (isset($ParsedLyrics3['raw']['IMG'])) { - $imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']); - foreach ($imagestrings as $key => $imagestring) { - if (strpos($imagestring, '||') !== false) { - $imagearray = explode('||', $imagestring); - $ParsedLyrics3['images'][$key]['filename'] = (isset($imagearray[0]) ? $imagearray[0] : ''); - $ParsedLyrics3['images'][$key]['description'] = (isset($imagearray[1]) ? $imagearray[1] : ''); - $ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : ''); - } - } - } - if (isset($ParsedLyrics3['raw']['LYR'])) { - $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); - } - } else { - $info['error'][] = '"LYRICS200" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'; - return false; - } - break; - - default: - $info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)'; - return false; - break; - } - - - if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) { - $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data'; - unset($info['id3v1']); - foreach ($info['warning'] as $key => $value) { - if ($value == 'Some ID3v1 fields do not use NULL characters for padding') { - unset($info['warning'][$key]); - sort($info['warning']); - break; - } - } - } - - $info['lyrics3'] = $ParsedLyrics3; - - return true; - } - - public function Lyrics3Timestamp2Seconds($rawtimestamp) { - if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) { - return (int) (($regs[1] * 60) + $regs[2]); - } - return false; - } - - public function Lyrics3LyricsTimestampParse(&$Lyrics3data) { - $lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']); - foreach ($lyricsarray as $key => $lyricline) { - $regs = array(); - unset($thislinetimestamps); - while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) { - $thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]); - $lyricline = str_replace($regs[0], '', $lyricline); - } - $notimestamplyricsarray[$key] = $lyricline; - if (isset($thislinetimestamps) && is_array($thislinetimestamps)) { - sort($thislinetimestamps); - foreach ($thislinetimestamps as $timestampkey => $timestamp) { - if (isset($Lyrics3data['synchedlyrics'][$timestamp])) { - // timestamps only have a 1-second resolution, it's possible that multiple lines - // could have the same timestamp, if so, append - $Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline; - } else { - $Lyrics3data['synchedlyrics'][$timestamp] = $lyricline; - } - } - } - } - $Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray); - if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) { - ksort($Lyrics3data['synchedlyrics']); - } - return true; - } - - public function IntString2Bool($char) { - if ($char == '1') { - return true; - } elseif ($char == '0') { - return false; - } - return null; - } -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// module.tag.lyrics3.php // +// module for analyzing Lyrics3 tags // +// dependencies: module.tag.apetag.php (optional) // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_lyrics3 extends getid3_handler +{ + + public function Analyze() { + $info = &$this->getid3->info; + + // http://www.volweb.cz/str/tags.htm + + if (!getid3_lib::intValueSupported($info['filesize'])) { + $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + + fseek($this->getid3->fp, (0 - 128 - 9 - 6), SEEK_END); // end - ID3v1 - "LYRICSEND" - [Lyrics3size] + $lyrics3_id3v1 = fread($this->getid3->fp, 128 + 9 + 6); + $lyrics3lsz = substr($lyrics3_id3v1, 0, 6); // Lyrics3size + $lyrics3end = substr($lyrics3_id3v1, 6, 9); // LYRICSEND or LYRICS200 + $id3v1tag = substr($lyrics3_id3v1, 15, 128); // ID3v1 + + if ($lyrics3end == 'LYRICSEND') { + // Lyrics3v1, ID3v1, no APE + + $lyrics3size = 5100; + $lyrics3offset = $info['filesize'] - 128 - $lyrics3size; + $lyrics3version = 1; + + } elseif ($lyrics3end == 'LYRICS200') { + // Lyrics3v2, ID3v1, no APE + + // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); + $lyrics3offset = $info['filesize'] - 128 - $lyrics3size; + $lyrics3version = 2; + + } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICSEND')) { + // Lyrics3v1, no ID3v1, no APE + + $lyrics3size = 5100; + $lyrics3offset = $info['filesize'] - $lyrics3size; + $lyrics3version = 1; + $lyrics3offset = $info['filesize'] - $lyrics3size; + + } elseif (substr(strrev($lyrics3_id3v1), 0, 9) == strrev('LYRICS200')) { + + // Lyrics3v2, no ID3v1, no APE + + $lyrics3size = strrev(substr(strrev($lyrics3_id3v1), 9, 6)) + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $lyrics3offset = $info['filesize'] - $lyrics3size; + $lyrics3version = 2; + + } else { + + if (isset($info['ape']['tag_offset_start']) && ($info['ape']['tag_offset_start'] > 15)) { + + fseek($this->getid3->fp, $info['ape']['tag_offset_start'] - 15, SEEK_SET); + $lyrics3lsz = fread($this->getid3->fp, 6); + $lyrics3end = fread($this->getid3->fp, 9); + + if ($lyrics3end == 'LYRICSEND') { + // Lyrics3v1, APE, maybe ID3v1 + + $lyrics3size = 5100; + $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size; + $info['avdataend'] = $lyrics3offset; + $lyrics3version = 1; + $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability'; + + } elseif ($lyrics3end == 'LYRICS200') { + // Lyrics3v2, APE, maybe ID3v1 + + $lyrics3size = $lyrics3lsz + 6 + strlen('LYRICS200'); // LSZ = lyrics + 'LYRICSBEGIN'; add 6-byte size field; add 'LYRICS200' + $lyrics3offset = $info['ape']['tag_offset_start'] - $lyrics3size; + $lyrics3version = 2; + $info['warning'][] = 'APE tag located after Lyrics3, will probably break Lyrics3 compatability'; + + } + + } + + } + + if (isset($lyrics3offset)) { + $info['avdataend'] = $lyrics3offset; + $this->getLyrics3Data($lyrics3offset, $lyrics3version, $lyrics3size); + + if (!isset($info['ape'])) { + $GETID3_ERRORARRAY = &$info['warning']; + if (getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, false)) { + $getid3_temp = new getID3(); + $getid3_temp->openfile($this->getid3->filename); + $getid3_apetag = new getid3_apetag($getid3_temp); + $getid3_apetag->overrideendoffset = $info['lyrics3']['tag_offset_start']; + $getid3_apetag->Analyze(); + if (!empty($getid3_temp->info['ape'])) { + $info['ape'] = $getid3_temp->info['ape']; + } + if (!empty($getid3_temp->info['replay_gain'])) { + $info['replay_gain'] = $getid3_temp->info['replay_gain']; + } + unset($getid3_temp, $getid3_apetag); + } + } + + } + + return true; + } + + public function getLyrics3Data($endoffset, $version, $length) { + // http://www.volweb.cz/str/tags.htm + + $info = &$this->getid3->info; + + if (!getid3_lib::intValueSupported($endoffset)) { + $info['warning'][] = 'Unable to check for Lyrics3 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + + fseek($this->getid3->fp, $endoffset, SEEK_SET); + if ($length <= 0) { + return false; + } + $rawdata = fread($this->getid3->fp, $length); + + $ParsedLyrics3['raw']['lyrics3version'] = $version; + $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; + $ParsedLyrics3['tag_offset_start'] = $endoffset; + $ParsedLyrics3['tag_offset_end'] = $endoffset + $length - 1; + + if (substr($rawdata, 0, 11) != 'LYRICSBEGIN') { + if (strpos($rawdata, 'LYRICSBEGIN') !== false) { + + $info['warning'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but actually found at '.($endoffset + strpos($rawdata, 'LYRICSBEGIN')).' - this is invalid for Lyrics3 v'.$version; + $info['avdataend'] = $endoffset + strpos($rawdata, 'LYRICSBEGIN'); + $rawdata = substr($rawdata, strpos($rawdata, 'LYRICSBEGIN')); + $length = strlen($rawdata); + $ParsedLyrics3['tag_offset_start'] = $info['avdataend']; + $ParsedLyrics3['raw']['lyrics3tagsize'] = $length; + + } else { + + $info['error'][] = '"LYRICSBEGIN" expected at '.$endoffset.' but found "'.substr($rawdata, 0, 11).'" instead'; + return false; + + } + + } + + switch ($version) { + + case 1: + if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICSEND') { + $ParsedLyrics3['raw']['LYR'] = trim(substr($rawdata, 11, strlen($rawdata) - 11 - 9)); + $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); + } else { + $info['error'][] = '"LYRICSEND" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'; + return false; + } + break; + + case 2: + if (substr($rawdata, strlen($rawdata) - 9, 9) == 'LYRICS200') { + $ParsedLyrics3['raw']['unparsed'] = substr($rawdata, 11, strlen($rawdata) - 11 - 9 - 6); // LYRICSBEGIN + LYRICS200 + LSZ + $rawdata = $ParsedLyrics3['raw']['unparsed']; + while (strlen($rawdata) > 0) { + $fieldname = substr($rawdata, 0, 3); + $fieldsize = (int) substr($rawdata, 3, 5); + $ParsedLyrics3['raw'][$fieldname] = substr($rawdata, 8, $fieldsize); + $rawdata = substr($rawdata, 3 + 5 + $fieldsize); + } + + if (isset($ParsedLyrics3['raw']['IND'])) { + $i = 0; + $flagnames = array('lyrics', 'timestamps', 'inhibitrandom'); + foreach ($flagnames as $flagname) { + if (strlen($ParsedLyrics3['raw']['IND']) > $i++) { + $ParsedLyrics3['flags'][$flagname] = $this->IntString2Bool(substr($ParsedLyrics3['raw']['IND'], $i, 1 - 1)); + } + } + } + + $fieldnametranslation = array('ETT'=>'title', 'EAR'=>'artist', 'EAL'=>'album', 'INF'=>'comment', 'AUT'=>'author'); + foreach ($fieldnametranslation as $key => $value) { + if (isset($ParsedLyrics3['raw'][$key])) { + $ParsedLyrics3['comments'][$value][] = trim($ParsedLyrics3['raw'][$key]); + } + } + + if (isset($ParsedLyrics3['raw']['IMG'])) { + $imagestrings = explode("\r\n", $ParsedLyrics3['raw']['IMG']); + foreach ($imagestrings as $key => $imagestring) { + if (strpos($imagestring, '||') !== false) { + $imagearray = explode('||', $imagestring); + $ParsedLyrics3['images'][$key]['filename'] = (isset($imagearray[0]) ? $imagearray[0] : ''); + $ParsedLyrics3['images'][$key]['description'] = (isset($imagearray[1]) ? $imagearray[1] : ''); + $ParsedLyrics3['images'][$key]['timestamp'] = $this->Lyrics3Timestamp2Seconds(isset($imagearray[2]) ? $imagearray[2] : ''); + } + } + } + if (isset($ParsedLyrics3['raw']['LYR'])) { + $this->Lyrics3LyricsTimestampParse($ParsedLyrics3); + } + } else { + $info['error'][] = '"LYRICS200" expected at '.(ftell($this->getid3->fp) - 11 + $length - 9).' but found "'.substr($rawdata, strlen($rawdata) - 9, 9).'" instead'; + return false; + } + break; + + default: + $info['error'][] = 'Cannot process Lyrics3 version '.$version.' (only v1 and v2)'; + return false; + break; + } + + + if (isset($info['id3v1']['tag_offset_start']) && ($info['id3v1']['tag_offset_start'] <= $ParsedLyrics3['tag_offset_end'])) { + $info['warning'][] = 'ID3v1 tag information ignored since it appears to be a false synch in Lyrics3 tag data'; + unset($info['id3v1']); + foreach ($info['warning'] as $key => $value) { + if ($value == 'Some ID3v1 fields do not use NULL characters for padding') { + unset($info['warning'][$key]); + sort($info['warning']); + break; + } + } + } + + $info['lyrics3'] = $ParsedLyrics3; + + return true; + } + + public function Lyrics3Timestamp2Seconds($rawtimestamp) { + if (preg_match('#^\\[([0-9]{2}):([0-9]{2})\\]$#', $rawtimestamp, $regs)) { + return (int) (($regs[1] * 60) + $regs[2]); + } + return false; + } + + public function Lyrics3LyricsTimestampParse(&$Lyrics3data) { + $lyricsarray = explode("\r\n", $Lyrics3data['raw']['LYR']); + foreach ($lyricsarray as $key => $lyricline) { + $regs = array(); + unset($thislinetimestamps); + while (preg_match('#^(\\[[0-9]{2}:[0-9]{2}\\])#', $lyricline, $regs)) { + $thislinetimestamps[] = $this->Lyrics3Timestamp2Seconds($regs[0]); + $lyricline = str_replace($regs[0], '', $lyricline); + } + $notimestamplyricsarray[$key] = $lyricline; + if (isset($thislinetimestamps) && is_array($thislinetimestamps)) { + sort($thislinetimestamps); + foreach ($thislinetimestamps as $timestampkey => $timestamp) { + if (isset($Lyrics3data['synchedlyrics'][$timestamp])) { + // timestamps only have a 1-second resolution, it's possible that multiple lines + // could have the same timestamp, if so, append + $Lyrics3data['synchedlyrics'][$timestamp] .= "\r\n".$lyricline; + } else { + $Lyrics3data['synchedlyrics'][$timestamp] = $lyricline; + } + } + } + } + $Lyrics3data['unsynchedlyrics'] = implode("\r\n", $notimestamplyricsarray); + if (isset($Lyrics3data['synchedlyrics']) && is_array($Lyrics3data['synchedlyrics'])) { + ksort($Lyrics3data['synchedlyrics']); + } + return true; + } + + public function IntString2Bool($char) { + if ($char == '1') { + return true; + } elseif ($char == '0') { + return false; + } + return null; + } +} diff --git a/app/libs/vendor/getid3/module.tag.xmp.php b/app/libs/vendor/getid3/module.tag.xmp.php index 9a5f9e5d..366c4ec9 100644 --- a/app/libs/vendor/getid3/module.tag.xmp.php +++ b/app/libs/vendor/getid3/module.tag.xmp.php @@ -1,767 +1,767 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// module.tag.xmp.php // -// module for analyzing XMP metadata (e.g. in JPEG files) // -// dependencies: NONE // -// // -///////////////////////////////////////////////////////////////// -// // -// Module originally written [2009-Mar-26] by // -// Nigel Barnes // -// Bundled into getID3 with permission // -// called by getID3 in module.graphic.jpg.php // -// /// -///////////////////////////////////////////////////////////////// - -/************************************************************************************************** - * SWISScenter Source Nigel Barnes - * - * Provides functions for reading information from the 'APP1' Extensible Metadata - * Platform (XMP) segment of JPEG format files. - * This XMP segment is XML based and contains the Resource Description Framework (RDF) - * data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information. - * - * This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter. - *************************************************************************************************/ -class Image_XMP -{ - /** - * @var string - * The name of the image file that contains the XMP fields to extract and modify. - * @see Image_XMP() - */ - public $_sFilename = null; - - /** - * @var array - * The XMP fields that were extracted from the image or updated by this class. - * @see getAllTags() - */ - public $_aXMP = array(); - - /** - * @var boolean - * True if an APP1 segment was found to contain XMP metadata. - * @see isValid() - */ - public $_bXMPParse = false; - - /** - * Returns the status of XMP parsing during instantiation - * - * You'll normally want to call this method before trying to get XMP fields. - * - * @return boolean - * Returns true if an APP1 segment was found to contain XMP metadata. - */ - public function isValid() - { - return $this->_bXMPParse; - } - - /** - * Get a copy of all XMP tags extracted from the image - * - * @return array - An array of XMP fields as it extracted by the XMPparse() function - */ - public function getAllTags() - { - return $this->_aXMP; - } - - /** - * Reads all the JPEG header segments from an JPEG image file into an array - * - * @param string $filename - the filename of the JPEG file to read - * @return array $headerdata - Array of JPEG header segments - * @return boolean FALSE - if headers could not be read - */ - public function _get_jpeg_header_data($filename) - { - // prevent refresh from aborting file operations and hosing file - ignore_user_abort(true); - - // Attempt to open the jpeg file - the at symbol supresses the error message about - // not being able to open files. The file_exists would have been used, but it - // does not work with files fetched over http or ftp. - if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) { - // great - } else { - return false; - } - - // Read the first two characters - $data = fread($filehnd, 2); - - // Check that the first two characters are 0xFF 0xD8 (SOI - Start of image) - if ($data != "\xFF\xD8") - { - // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; - echo '

    This probably is not a JPEG file

    '."\n"; - fclose($filehnd); - return false; - } - - // Read the third character - $data = fread($filehnd, 2); - - // Check that the third character is 0xFF (Start of first segment header) - if ($data{0} != "\xFF") - { - // NO FF found - close file and return - JPEG is probably corrupted - fclose($filehnd); - return false; - } - - // Flag that we havent yet hit the compressed image data - $hit_compressed_image_data = false; - - // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, - // 2) we have hit the compressed image data (no more headers are allowed after data) - // 3) or end of file is hit - - while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd))) - { - // Found a segment to look at. - // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them - if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7)) - { - // Segment isn't a Restart marker - // Read the next two bytes (size) - $sizestr = fread($filehnd, 2); - - // convert the size bytes to an integer - $decodedsize = unpack('nsize', $sizestr); - - // Save the start position of the data - $segdatastart = ftell($filehnd); - - // Read the segment data with length indicated by the previously read size - $segdata = fread($filehnd, $decodedsize['size'] - 2); - - // Store the segment information in the output array - $headerdata[] = array( - 'SegType' => ord($data{1}), - 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})], - 'SegDataStart' => $segdatastart, - 'SegData' => $segdata, - ); - } - - // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows - if ($data{1} == "\xDA") - { - // Flag that we have hit the compressed image data - exit loop as no more headers available. - $hit_compressed_image_data = true; - } - else - { - // Not an SOS - Read the next two bytes - should be the segment marker for the next segment - $data = fread($filehnd, 2); - - // Check that the first byte of the two is 0xFF as it should be for a marker - if ($data{0} != "\xFF") - { - // NO FF found - close file and return - JPEG is probably corrupted - fclose($filehnd); - return false; - } - } - } - - // Close File - fclose($filehnd); - // Alow the user to abort from now on - ignore_user_abort(false); - - // Return the header data retrieved - return $headerdata; - } - - - /** - * Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string. - * - * @param string $filename - the filename of the JPEG file to read - * @return string $xmp_data - the string of raw XML text - * @return boolean FALSE - if an APP 1 XMP segment could not be found, or if an error occured - */ - public function _get_XMP_text($filename) - { - //Get JPEG header data - $jpeg_header_data = $this->_get_jpeg_header_data($filename); - - //Cycle through the header segments - for ($i = 0; $i < count($jpeg_header_data); $i++) - { - // If we find an APP1 header, - if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0) - { - // And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) , - if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0) - { - // Found a XMP/RDF block - // Return the XMP text - $xmp_data = substr($jpeg_header_data[$i]['SegData'], 29); - - return trim($xmp_data); // trim() should not be neccesary, but some files found in the wild with null-terminated block (known samples from Apple Aperture) causes problems elsewhere (see http://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153) - } - } - } - return false; - } - - /** - * Parses a string containing XMP data (XML), and returns an array - * which contains all the XMP (XML) information. - * - * @param string $xml_text - a string containing the XMP data (XML) to be parsed - * @return array $xmp_array - an array containing all xmp details retrieved. - * @return boolean FALSE - couldn't parse the XMP data - */ - public function read_XMP_array_from_text($xmltext) - { - // Check if there actually is any text to parse - if (trim($xmltext) == '') - { - return false; - } - - // Create an instance of a xml parser to parse the XML text - $xml_parser = xml_parser_create('UTF-8'); - - // Change: Fixed problem that caused the whitespace (especially newlines) to be destroyed when converting xml text to an xml array, as of revision 1.10 - - // We would like to remove unneccessary white space, but this will also - // remove things like newlines ( ) in the XML values, so white space - // will have to be removed later - if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false) - { - // Error setting case folding - destroy the parser and return - xml_parser_free($xml_parser); - return false; - } - - // to use XML code correctly we have to turn case folding - // (uppercasing) off. XML is case sensitive and upper - // casing is in reality XML standards violation - if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false) - { - // Error setting case folding - destroy the parser and return - xml_parser_free($xml_parser); - return false; - } - - // Parse the XML text into a array structure - if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0) - { - // Error Parsing XML - destroy the parser and return - xml_parser_free($xml_parser); - return false; - } - - // Destroy the xml parser - xml_parser_free($xml_parser); - - // Clear the output array - $xmp_array = array(); - - // The XMP data has now been parsed into an array ... - - // Cycle through each of the array elements - $current_property = ''; // current property being processed - $container_index = -1; // -1 = no container open, otherwise index of container content - foreach ($values as $xml_elem) - { - // Syntax and Class names - switch ($xml_elem['tag']) - { - case 'x:xmpmeta': - // only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit - break; - - case 'rdf:RDF': - // required element immediately within x:xmpmeta; no data here - break; - - case 'rdf:Description': - switch ($xml_elem['type']) - { - case 'open': - case 'complete': - if (array_key_exists('attributes', $xml_elem)) - { - // rdf:Description may contain wanted attributes - foreach (array_keys($xml_elem['attributes']) as $key) - { - // Check whether we want this details from this attribute -// if (in_array($key, $GLOBALS['XMP_tag_captions'])) - if (true) - { - // Attribute wanted - $xmp_array[$key] = $xml_elem['attributes'][$key]; - } - } - } - case 'cdata': - case 'close': - break; - } - - case 'rdf:ID': - case 'rdf:nodeID': - // Attributes are ignored - break; - - case 'rdf:li': - // Property member - if ($xml_elem['type'] == 'complete') - { - if (array_key_exists('attributes', $xml_elem)) - { - // If Lang Alt (language alternatives) then ensure we take the default language - if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default')) - { - break; - } - } - if ($current_property != '') - { - $xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : ''); - $container_index += 1; - } - //else unidentified attribute!! - } - break; - - case 'rdf:Seq': - case 'rdf:Bag': - case 'rdf:Alt': - // Container found - switch ($xml_elem['type']) - { - case 'open': - $container_index = 0; - break; - case 'close': - $container_index = -1; - break; - case 'cdata': - break; - } - break; - - default: - // Check whether we want the details from this attribute -// if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions'])) - if (true) - { - switch ($xml_elem['type']) - { - case 'open': - // open current element - $current_property = $xml_elem['tag']; - break; - - case 'close': - // close current element - $current_property = ''; - break; - - case 'complete': - // store attribute value - $xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : '')); - break; - - case 'cdata': - // ignore - break; - } - } - break; - } - - } - return $xmp_array; - } - - - /** - * Constructor - * - * @param string - Name of the image file to access and extract XMP information from. - */ - public function Image_XMP($sFilename) - { - $this->_sFilename = $sFilename; - - if (is_file($this->_sFilename)) - { - // Get XMP data - $xmp_data = $this->_get_XMP_text($sFilename); - if ($xmp_data) - { - $this->_aXMP = $this->read_XMP_array_from_text($xmp_data); - $this->_bXMPParse = true; - } - } - } - -} - -/** -* Global Variable: XMP_tag_captions -* -* The Property names of all known XMP fields. -* Note: this is a full list with unrequired properties commented out. -*/ -/* -$GLOBALS['XMP_tag_captions'] = array( -// IPTC Core - 'Iptc4xmpCore:CiAdrCity', - 'Iptc4xmpCore:CiAdrCtry', - 'Iptc4xmpCore:CiAdrExtadr', - 'Iptc4xmpCore:CiAdrPcode', - 'Iptc4xmpCore:CiAdrRegion', - 'Iptc4xmpCore:CiEmailWork', - 'Iptc4xmpCore:CiTelWork', - 'Iptc4xmpCore:CiUrlWork', - 'Iptc4xmpCore:CountryCode', - 'Iptc4xmpCore:CreatorContactInfo', - 'Iptc4xmpCore:IntellectualGenre', - 'Iptc4xmpCore:Location', - 'Iptc4xmpCore:Scene', - 'Iptc4xmpCore:SubjectCode', -// Dublin Core Schema - 'dc:contributor', - 'dc:coverage', - 'dc:creator', - 'dc:date', - 'dc:description', - 'dc:format', - 'dc:identifier', - 'dc:language', - 'dc:publisher', - 'dc:relation', - 'dc:rights', - 'dc:source', - 'dc:subject', - 'dc:title', - 'dc:type', -// XMP Basic Schema - 'xmp:Advisory', - 'xmp:BaseURL', - 'xmp:CreateDate', - 'xmp:CreatorTool', - 'xmp:Identifier', - 'xmp:Label', - 'xmp:MetadataDate', - 'xmp:ModifyDate', - 'xmp:Nickname', - 'xmp:Rating', - 'xmp:Thumbnails', - 'xmpidq:Scheme', -// XMP Rights Management Schema - 'xmpRights:Certificate', - 'xmpRights:Marked', - 'xmpRights:Owner', - 'xmpRights:UsageTerms', - 'xmpRights:WebStatement', -// These are not in spec but Photoshop CS seems to use them - 'xap:Advisory', - 'xap:BaseURL', - 'xap:CreateDate', - 'xap:CreatorTool', - 'xap:Identifier', - 'xap:MetadataDate', - 'xap:ModifyDate', - 'xap:Nickname', - 'xap:Rating', - 'xap:Thumbnails', - 'xapidq:Scheme', - 'xapRights:Certificate', - 'xapRights:Copyright', - 'xapRights:Marked', - 'xapRights:Owner', - 'xapRights:UsageTerms', - 'xapRights:WebStatement', -// XMP Media Management Schema - 'xapMM:DerivedFrom', - 'xapMM:DocumentID', - 'xapMM:History', - 'xapMM:InstanceID', - 'xapMM:ManagedFrom', - 'xapMM:Manager', - 'xapMM:ManageTo', - 'xapMM:ManageUI', - 'xapMM:ManagerVariant', - 'xapMM:RenditionClass', - 'xapMM:RenditionParams', - 'xapMM:VersionID', - 'xapMM:Versions', - 'xapMM:LastURL', - 'xapMM:RenditionOf', - 'xapMM:SaveID', -// XMP Basic Job Ticket Schema - 'xapBJ:JobRef', -// XMP Paged-Text Schema - 'xmpTPg:MaxPageSize', - 'xmpTPg:NPages', - 'xmpTPg:Fonts', - 'xmpTPg:Colorants', - 'xmpTPg:PlateNames', -// Adobe PDF Schema - 'pdf:Keywords', - 'pdf:PDFVersion', - 'pdf:Producer', -// Photoshop Schema - 'photoshop:AuthorsPosition', - 'photoshop:CaptionWriter', - 'photoshop:Category', - 'photoshop:City', - 'photoshop:Country', - 'photoshop:Credit', - 'photoshop:DateCreated', - 'photoshop:Headline', - 'photoshop:History', -// Not in XMP spec - 'photoshop:Instructions', - 'photoshop:Source', - 'photoshop:State', - 'photoshop:SupplementalCategories', - 'photoshop:TransmissionReference', - 'photoshop:Urgency', -// EXIF Schemas - 'tiff:ImageWidth', - 'tiff:ImageLength', - 'tiff:BitsPerSample', - 'tiff:Compression', - 'tiff:PhotometricInterpretation', - 'tiff:Orientation', - 'tiff:SamplesPerPixel', - 'tiff:PlanarConfiguration', - 'tiff:YCbCrSubSampling', - 'tiff:YCbCrPositioning', - 'tiff:XResolution', - 'tiff:YResolution', - 'tiff:ResolutionUnit', - 'tiff:TransferFunction', - 'tiff:WhitePoint', - 'tiff:PrimaryChromaticities', - 'tiff:YCbCrCoefficients', - 'tiff:ReferenceBlackWhite', - 'tiff:DateTime', - 'tiff:ImageDescription', - 'tiff:Make', - 'tiff:Model', - 'tiff:Software', - 'tiff:Artist', - 'tiff:Copyright', - 'exif:ExifVersion', - 'exif:FlashpixVersion', - 'exif:ColorSpace', - 'exif:ComponentsConfiguration', - 'exif:CompressedBitsPerPixel', - 'exif:PixelXDimension', - 'exif:PixelYDimension', - 'exif:MakerNote', - 'exif:UserComment', - 'exif:RelatedSoundFile', - 'exif:DateTimeOriginal', - 'exif:DateTimeDigitized', - 'exif:ExposureTime', - 'exif:FNumber', - 'exif:ExposureProgram', - 'exif:SpectralSensitivity', - 'exif:ISOSpeedRatings', - 'exif:OECF', - 'exif:ShutterSpeedValue', - 'exif:ApertureValue', - 'exif:BrightnessValue', - 'exif:ExposureBiasValue', - 'exif:MaxApertureValue', - 'exif:SubjectDistance', - 'exif:MeteringMode', - 'exif:LightSource', - 'exif:Flash', - 'exif:FocalLength', - 'exif:SubjectArea', - 'exif:FlashEnergy', - 'exif:SpatialFrequencyResponse', - 'exif:FocalPlaneXResolution', - 'exif:FocalPlaneYResolution', - 'exif:FocalPlaneResolutionUnit', - 'exif:SubjectLocation', - 'exif:SensingMethod', - 'exif:FileSource', - 'exif:SceneType', - 'exif:CFAPattern', - 'exif:CustomRendered', - 'exif:ExposureMode', - 'exif:WhiteBalance', - 'exif:DigitalZoomRatio', - 'exif:FocalLengthIn35mmFilm', - 'exif:SceneCaptureType', - 'exif:GainControl', - 'exif:Contrast', - 'exif:Saturation', - 'exif:Sharpness', - 'exif:DeviceSettingDescription', - 'exif:SubjectDistanceRange', - 'exif:ImageUniqueID', - 'exif:GPSVersionID', - 'exif:GPSLatitude', - 'exif:GPSLongitude', - 'exif:GPSAltitudeRef', - 'exif:GPSAltitude', - 'exif:GPSTimeStamp', - 'exif:GPSSatellites', - 'exif:GPSStatus', - 'exif:GPSMeasureMode', - 'exif:GPSDOP', - 'exif:GPSSpeedRef', - 'exif:GPSSpeed', - 'exif:GPSTrackRef', - 'exif:GPSTrack', - 'exif:GPSImgDirectionRef', - 'exif:GPSImgDirection', - 'exif:GPSMapDatum', - 'exif:GPSDestLatitude', - 'exif:GPSDestLongitude', - 'exif:GPSDestBearingRef', - 'exif:GPSDestBearing', - 'exif:GPSDestDistanceRef', - 'exif:GPSDestDistance', - 'exif:GPSProcessingMethod', - 'exif:GPSAreaInformation', - 'exif:GPSDifferential', - 'stDim:w', - 'stDim:h', - 'stDim:unit', - 'xapGImg:height', - 'xapGImg:width', - 'xapGImg:format', - 'xapGImg:image', - 'stEvt:action', - 'stEvt:instanceID', - 'stEvt:parameters', - 'stEvt:softwareAgent', - 'stEvt:when', - 'stRef:instanceID', - 'stRef:documentID', - 'stRef:versionID', - 'stRef:renditionClass', - 'stRef:renditionParams', - 'stRef:manager', - 'stRef:managerVariant', - 'stRef:manageTo', - 'stRef:manageUI', - 'stVer:comments', - 'stVer:event', - 'stVer:modifyDate', - 'stVer:modifier', - 'stVer:version', - 'stJob:name', - 'stJob:id', - 'stJob:url', -// Exif Flash - 'exif:Fired', - 'exif:Return', - 'exif:Mode', - 'exif:Function', - 'exif:RedEyeMode', -// Exif OECF/SFR - 'exif:Columns', - 'exif:Rows', - 'exif:Names', - 'exif:Values', -// Exif CFAPattern - 'exif:Columns', - 'exif:Rows', - 'exif:Values', -// Exif DeviceSettings - 'exif:Columns', - 'exif:Rows', - 'exif:Settings', -); -*/ - -/** -* Global Variable: JPEG_Segment_Names -* -* The names of the JPEG segment markers, indexed by their marker number -*/ -$GLOBALS['JPEG_Segment_Names'] = array( - 0x01 => 'TEM', - 0x02 => 'RES', - 0xC0 => 'SOF0', - 0xC1 => 'SOF1', - 0xC2 => 'SOF2', - 0xC3 => 'SOF4', - 0xC4 => 'DHT', - 0xC5 => 'SOF5', - 0xC6 => 'SOF6', - 0xC7 => 'SOF7', - 0xC8 => 'JPG', - 0xC9 => 'SOF9', - 0xCA => 'SOF10', - 0xCB => 'SOF11', - 0xCC => 'DAC', - 0xCD => 'SOF13', - 0xCE => 'SOF14', - 0xCF => 'SOF15', - 0xD0 => 'RST0', - 0xD1 => 'RST1', - 0xD2 => 'RST2', - 0xD3 => 'RST3', - 0xD4 => 'RST4', - 0xD5 => 'RST5', - 0xD6 => 'RST6', - 0xD7 => 'RST7', - 0xD8 => 'SOI', - 0xD9 => 'EOI', - 0xDA => 'SOS', - 0xDB => 'DQT', - 0xDC => 'DNL', - 0xDD => 'DRI', - 0xDE => 'DHP', - 0xDF => 'EXP', - 0xE0 => 'APP0', - 0xE1 => 'APP1', - 0xE2 => 'APP2', - 0xE3 => 'APP3', - 0xE4 => 'APP4', - 0xE5 => 'APP5', - 0xE6 => 'APP6', - 0xE7 => 'APP7', - 0xE8 => 'APP8', - 0xE9 => 'APP9', - 0xEA => 'APP10', - 0xEB => 'APP11', - 0xEC => 'APP12', - 0xED => 'APP13', - 0xEE => 'APP14', - 0xEF => 'APP15', - 0xF0 => 'JPG0', - 0xF1 => 'JPG1', - 0xF2 => 'JPG2', - 0xF3 => 'JPG3', - 0xF4 => 'JPG4', - 0xF5 => 'JPG5', - 0xF6 => 'JPG6', - 0xF7 => 'JPG7', - 0xF8 => 'JPG8', - 0xF9 => 'JPG9', - 0xFA => 'JPG10', - 0xFB => 'JPG11', - 0xFC => 'JPG12', - 0xFD => 'JPG13', - 0xFE => 'COM', -); + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// module.tag.xmp.php // +// module for analyzing XMP metadata (e.g. in JPEG files) // +// dependencies: NONE // +// // +///////////////////////////////////////////////////////////////// +// // +// Module originally written [2009-Mar-26] by // +// Nigel Barnes // +// Bundled into getID3 with permission // +// called by getID3 in module.graphic.jpg.php // +// /// +///////////////////////////////////////////////////////////////// + +/************************************************************************************************** + * SWISScenter Source Nigel Barnes + * + * Provides functions for reading information from the 'APP1' Extensible Metadata + * Platform (XMP) segment of JPEG format files. + * This XMP segment is XML based and contains the Resource Description Framework (RDF) + * data, which itself can contain the Dublin Core Metadata Initiative (DCMI) information. + * + * This code uses segments from the JPEG Metadata Toolkit project by Evan Hunter. + *************************************************************************************************/ +class Image_XMP +{ + /** + * @var string + * The name of the image file that contains the XMP fields to extract and modify. + * @see Image_XMP() + */ + public $_sFilename = null; + + /** + * @var array + * The XMP fields that were extracted from the image or updated by this class. + * @see getAllTags() + */ + public $_aXMP = array(); + + /** + * @var boolean + * True if an APP1 segment was found to contain XMP metadata. + * @see isValid() + */ + public $_bXMPParse = false; + + /** + * Returns the status of XMP parsing during instantiation + * + * You'll normally want to call this method before trying to get XMP fields. + * + * @return boolean + * Returns true if an APP1 segment was found to contain XMP metadata. + */ + public function isValid() + { + return $this->_bXMPParse; + } + + /** + * Get a copy of all XMP tags extracted from the image + * + * @return array - An array of XMP fields as it extracted by the XMPparse() function + */ + public function getAllTags() + { + return $this->_aXMP; + } + + /** + * Reads all the JPEG header segments from an JPEG image file into an array + * + * @param string $filename - the filename of the JPEG file to read + * @return array $headerdata - Array of JPEG header segments + * @return boolean FALSE - if headers could not be read + */ + public function _get_jpeg_header_data($filename) + { + // prevent refresh from aborting file operations and hosing file + ignore_user_abort(true); + + // Attempt to open the jpeg file - the at symbol supresses the error message about + // not being able to open files. The file_exists would have been used, but it + // does not work with files fetched over http or ftp. + if (is_readable($filename) && is_file($filename) && ($filehnd = fopen($filename, 'rb'))) { + // great + } else { + return false; + } + + // Read the first two characters + $data = fread($filehnd, 2); + + // Check that the first two characters are 0xFF 0xD8 (SOI - Start of image) + if ($data != "\xFF\xD8") + { + // No SOI (FF D8) at start of file - This probably isn't a JPEG file - close file and return; + echo '

    This probably is not a JPEG file

    '."\n"; + fclose($filehnd); + return false; + } + + // Read the third character + $data = fread($filehnd, 2); + + // Check that the third character is 0xFF (Start of first segment header) + if ($data{0} != "\xFF") + { + // NO FF found - close file and return - JPEG is probably corrupted + fclose($filehnd); + return false; + } + + // Flag that we havent yet hit the compressed image data + $hit_compressed_image_data = false; + + // Cycle through the file until, one of: 1) an EOI (End of image) marker is hit, + // 2) we have hit the compressed image data (no more headers are allowed after data) + // 3) or end of file is hit + + while (($data{1} != "\xD9") && (!$hit_compressed_image_data) && (!feof($filehnd))) + { + // Found a segment to look at. + // Check that the segment marker is not a Restart marker - restart markers don't have size or data after them + if ((ord($data{1}) < 0xD0) || (ord($data{1}) > 0xD7)) + { + // Segment isn't a Restart marker + // Read the next two bytes (size) + $sizestr = fread($filehnd, 2); + + // convert the size bytes to an integer + $decodedsize = unpack('nsize', $sizestr); + + // Save the start position of the data + $segdatastart = ftell($filehnd); + + // Read the segment data with length indicated by the previously read size + $segdata = fread($filehnd, $decodedsize['size'] - 2); + + // Store the segment information in the output array + $headerdata[] = array( + 'SegType' => ord($data{1}), + 'SegName' => $GLOBALS['JPEG_Segment_Names'][ord($data{1})], + 'SegDataStart' => $segdatastart, + 'SegData' => $segdata, + ); + } + + // If this is a SOS (Start Of Scan) segment, then there is no more header data - the compressed image data follows + if ($data{1} == "\xDA") + { + // Flag that we have hit the compressed image data - exit loop as no more headers available. + $hit_compressed_image_data = true; + } + else + { + // Not an SOS - Read the next two bytes - should be the segment marker for the next segment + $data = fread($filehnd, 2); + + // Check that the first byte of the two is 0xFF as it should be for a marker + if ($data{0} != "\xFF") + { + // NO FF found - close file and return - JPEG is probably corrupted + fclose($filehnd); + return false; + } + } + } + + // Close File + fclose($filehnd); + // Alow the user to abort from now on + ignore_user_abort(false); + + // Return the header data retrieved + return $headerdata; + } + + + /** + * Retrieves XMP information from an APP1 JPEG segment and returns the raw XML text as a string. + * + * @param string $filename - the filename of the JPEG file to read + * @return string $xmp_data - the string of raw XML text + * @return boolean FALSE - if an APP 1 XMP segment could not be found, or if an error occured + */ + public function _get_XMP_text($filename) + { + //Get JPEG header data + $jpeg_header_data = $this->_get_jpeg_header_data($filename); + + //Cycle through the header segments + for ($i = 0; $i < count($jpeg_header_data); $i++) + { + // If we find an APP1 header, + if (strcmp($jpeg_header_data[$i]['SegName'], 'APP1') == 0) + { + // And if it has the Adobe XMP/RDF label (http://ns.adobe.com/xap/1.0/\x00) , + if (strncmp($jpeg_header_data[$i]['SegData'], 'http://ns.adobe.com/xap/1.0/'."\x00", 29) == 0) + { + // Found a XMP/RDF block + // Return the XMP text + $xmp_data = substr($jpeg_header_data[$i]['SegData'], 29); + + return trim($xmp_data); // trim() should not be neccesary, but some files found in the wild with null-terminated block (known samples from Apple Aperture) causes problems elsewhere (see http://www.getid3.org/phpBB3/viewtopic.php?f=4&t=1153) + } + } + } + return false; + } + + /** + * Parses a string containing XMP data (XML), and returns an array + * which contains all the XMP (XML) information. + * + * @param string $xml_text - a string containing the XMP data (XML) to be parsed + * @return array $xmp_array - an array containing all xmp details retrieved. + * @return boolean FALSE - couldn't parse the XMP data + */ + public function read_XMP_array_from_text($xmltext) + { + // Check if there actually is any text to parse + if (trim($xmltext) == '') + { + return false; + } + + // Create an instance of a xml parser to parse the XML text + $xml_parser = xml_parser_create('UTF-8'); + + // Change: Fixed problem that caused the whitespace (especially newlines) to be destroyed when converting xml text to an xml array, as of revision 1.10 + + // We would like to remove unneccessary white space, but this will also + // remove things like newlines ( ) in the XML values, so white space + // will have to be removed later + if (xml_parser_set_option($xml_parser, XML_OPTION_SKIP_WHITE, 0) == false) + { + // Error setting case folding - destroy the parser and return + xml_parser_free($xml_parser); + return false; + } + + // to use XML code correctly we have to turn case folding + // (uppercasing) off. XML is case sensitive and upper + // casing is in reality XML standards violation + if (xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, 0) == false) + { + // Error setting case folding - destroy the parser and return + xml_parser_free($xml_parser); + return false; + } + + // Parse the XML text into a array structure + if (xml_parse_into_struct($xml_parser, $xmltext, $values, $tags) == 0) + { + // Error Parsing XML - destroy the parser and return + xml_parser_free($xml_parser); + return false; + } + + // Destroy the xml parser + xml_parser_free($xml_parser); + + // Clear the output array + $xmp_array = array(); + + // The XMP data has now been parsed into an array ... + + // Cycle through each of the array elements + $current_property = ''; // current property being processed + $container_index = -1; // -1 = no container open, otherwise index of container content + foreach ($values as $xml_elem) + { + // Syntax and Class names + switch ($xml_elem['tag']) + { + case 'x:xmpmeta': + // only defined attribute is x:xmptk written by Adobe XMP Toolkit; value is the version of the toolkit + break; + + case 'rdf:RDF': + // required element immediately within x:xmpmeta; no data here + break; + + case 'rdf:Description': + switch ($xml_elem['type']) + { + case 'open': + case 'complete': + if (array_key_exists('attributes', $xml_elem)) + { + // rdf:Description may contain wanted attributes + foreach (array_keys($xml_elem['attributes']) as $key) + { + // Check whether we want this details from this attribute +// if (in_array($key, $GLOBALS['XMP_tag_captions'])) + if (true) + { + // Attribute wanted + $xmp_array[$key] = $xml_elem['attributes'][$key]; + } + } + } + case 'cdata': + case 'close': + break; + } + + case 'rdf:ID': + case 'rdf:nodeID': + // Attributes are ignored + break; + + case 'rdf:li': + // Property member + if ($xml_elem['type'] == 'complete') + { + if (array_key_exists('attributes', $xml_elem)) + { + // If Lang Alt (language alternatives) then ensure we take the default language + if (isset($xml_elem['attributes']['xml:lang']) && ($xml_elem['attributes']['xml:lang'] != 'x-default')) + { + break; + } + } + if ($current_property != '') + { + $xmp_array[$current_property][$container_index] = (isset($xml_elem['value']) ? $xml_elem['value'] : ''); + $container_index += 1; + } + //else unidentified attribute!! + } + break; + + case 'rdf:Seq': + case 'rdf:Bag': + case 'rdf:Alt': + // Container found + switch ($xml_elem['type']) + { + case 'open': + $container_index = 0; + break; + case 'close': + $container_index = -1; + break; + case 'cdata': + break; + } + break; + + default: + // Check whether we want the details from this attribute +// if (in_array($xml_elem['tag'], $GLOBALS['XMP_tag_captions'])) + if (true) + { + switch ($xml_elem['type']) + { + case 'open': + // open current element + $current_property = $xml_elem['tag']; + break; + + case 'close': + // close current element + $current_property = ''; + break; + + case 'complete': + // store attribute value + $xmp_array[$xml_elem['tag']] = (isset($xml_elem['attributes']) ? $xml_elem['attributes'] : (isset($xml_elem['value']) ? $xml_elem['value'] : '')); + break; + + case 'cdata': + // ignore + break; + } + } + break; + } + + } + return $xmp_array; + } + + + /** + * Constructor + * + * @param string - Name of the image file to access and extract XMP information from. + */ + public function Image_XMP($sFilename) + { + $this->_sFilename = $sFilename; + + if (is_file($this->_sFilename)) + { + // Get XMP data + $xmp_data = $this->_get_XMP_text($sFilename); + if ($xmp_data) + { + $this->_aXMP = $this->read_XMP_array_from_text($xmp_data); + $this->_bXMPParse = true; + } + } + } + +} + +/** +* Global Variable: XMP_tag_captions +* +* The Property names of all known XMP fields. +* Note: this is a full list with unrequired properties commented out. +*/ +/* +$GLOBALS['XMP_tag_captions'] = array( +// IPTC Core + 'Iptc4xmpCore:CiAdrCity', + 'Iptc4xmpCore:CiAdrCtry', + 'Iptc4xmpCore:CiAdrExtadr', + 'Iptc4xmpCore:CiAdrPcode', + 'Iptc4xmpCore:CiAdrRegion', + 'Iptc4xmpCore:CiEmailWork', + 'Iptc4xmpCore:CiTelWork', + 'Iptc4xmpCore:CiUrlWork', + 'Iptc4xmpCore:CountryCode', + 'Iptc4xmpCore:CreatorContactInfo', + 'Iptc4xmpCore:IntellectualGenre', + 'Iptc4xmpCore:Location', + 'Iptc4xmpCore:Scene', + 'Iptc4xmpCore:SubjectCode', +// Dublin Core Schema + 'dc:contributor', + 'dc:coverage', + 'dc:creator', + 'dc:date', + 'dc:description', + 'dc:format', + 'dc:identifier', + 'dc:language', + 'dc:publisher', + 'dc:relation', + 'dc:rights', + 'dc:source', + 'dc:subject', + 'dc:title', + 'dc:type', +// XMP Basic Schema + 'xmp:Advisory', + 'xmp:BaseURL', + 'xmp:CreateDate', + 'xmp:CreatorTool', + 'xmp:Identifier', + 'xmp:Label', + 'xmp:MetadataDate', + 'xmp:ModifyDate', + 'xmp:Nickname', + 'xmp:Rating', + 'xmp:Thumbnails', + 'xmpidq:Scheme', +// XMP Rights Management Schema + 'xmpRights:Certificate', + 'xmpRights:Marked', + 'xmpRights:Owner', + 'xmpRights:UsageTerms', + 'xmpRights:WebStatement', +// These are not in spec but Photoshop CS seems to use them + 'xap:Advisory', + 'xap:BaseURL', + 'xap:CreateDate', + 'xap:CreatorTool', + 'xap:Identifier', + 'xap:MetadataDate', + 'xap:ModifyDate', + 'xap:Nickname', + 'xap:Rating', + 'xap:Thumbnails', + 'xapidq:Scheme', + 'xapRights:Certificate', + 'xapRights:Copyright', + 'xapRights:Marked', + 'xapRights:Owner', + 'xapRights:UsageTerms', + 'xapRights:WebStatement', +// XMP Media Management Schema + 'xapMM:DerivedFrom', + 'xapMM:DocumentID', + 'xapMM:History', + 'xapMM:InstanceID', + 'xapMM:ManagedFrom', + 'xapMM:Manager', + 'xapMM:ManageTo', + 'xapMM:ManageUI', + 'xapMM:ManagerVariant', + 'xapMM:RenditionClass', + 'xapMM:RenditionParams', + 'xapMM:VersionID', + 'xapMM:Versions', + 'xapMM:LastURL', + 'xapMM:RenditionOf', + 'xapMM:SaveID', +// XMP Basic Job Ticket Schema + 'xapBJ:JobRef', +// XMP Paged-Text Schema + 'xmpTPg:MaxPageSize', + 'xmpTPg:NPages', + 'xmpTPg:Fonts', + 'xmpTPg:Colorants', + 'xmpTPg:PlateNames', +// Adobe PDF Schema + 'pdf:Keywords', + 'pdf:PDFVersion', + 'pdf:Producer', +// Photoshop Schema + 'photoshop:AuthorsPosition', + 'photoshop:CaptionWriter', + 'photoshop:Category', + 'photoshop:City', + 'photoshop:Country', + 'photoshop:Credit', + 'photoshop:DateCreated', + 'photoshop:Headline', + 'photoshop:History', +// Not in XMP spec + 'photoshop:Instructions', + 'photoshop:Source', + 'photoshop:State', + 'photoshop:SupplementalCategories', + 'photoshop:TransmissionReference', + 'photoshop:Urgency', +// EXIF Schemas + 'tiff:ImageWidth', + 'tiff:ImageLength', + 'tiff:BitsPerSample', + 'tiff:Compression', + 'tiff:PhotometricInterpretation', + 'tiff:Orientation', + 'tiff:SamplesPerPixel', + 'tiff:PlanarConfiguration', + 'tiff:YCbCrSubSampling', + 'tiff:YCbCrPositioning', + 'tiff:XResolution', + 'tiff:YResolution', + 'tiff:ResolutionUnit', + 'tiff:TransferFunction', + 'tiff:WhitePoint', + 'tiff:PrimaryChromaticities', + 'tiff:YCbCrCoefficients', + 'tiff:ReferenceBlackWhite', + 'tiff:DateTime', + 'tiff:ImageDescription', + 'tiff:Make', + 'tiff:Model', + 'tiff:Software', + 'tiff:Artist', + 'tiff:Copyright', + 'exif:ExifVersion', + 'exif:FlashpixVersion', + 'exif:ColorSpace', + 'exif:ComponentsConfiguration', + 'exif:CompressedBitsPerPixel', + 'exif:PixelXDimension', + 'exif:PixelYDimension', + 'exif:MakerNote', + 'exif:UserComment', + 'exif:RelatedSoundFile', + 'exif:DateTimeOriginal', + 'exif:DateTimeDigitized', + 'exif:ExposureTime', + 'exif:FNumber', + 'exif:ExposureProgram', + 'exif:SpectralSensitivity', + 'exif:ISOSpeedRatings', + 'exif:OECF', + 'exif:ShutterSpeedValue', + 'exif:ApertureValue', + 'exif:BrightnessValue', + 'exif:ExposureBiasValue', + 'exif:MaxApertureValue', + 'exif:SubjectDistance', + 'exif:MeteringMode', + 'exif:LightSource', + 'exif:Flash', + 'exif:FocalLength', + 'exif:SubjectArea', + 'exif:FlashEnergy', + 'exif:SpatialFrequencyResponse', + 'exif:FocalPlaneXResolution', + 'exif:FocalPlaneYResolution', + 'exif:FocalPlaneResolutionUnit', + 'exif:SubjectLocation', + 'exif:SensingMethod', + 'exif:FileSource', + 'exif:SceneType', + 'exif:CFAPattern', + 'exif:CustomRendered', + 'exif:ExposureMode', + 'exif:WhiteBalance', + 'exif:DigitalZoomRatio', + 'exif:FocalLengthIn35mmFilm', + 'exif:SceneCaptureType', + 'exif:GainControl', + 'exif:Contrast', + 'exif:Saturation', + 'exif:Sharpness', + 'exif:DeviceSettingDescription', + 'exif:SubjectDistanceRange', + 'exif:ImageUniqueID', + 'exif:GPSVersionID', + 'exif:GPSLatitude', + 'exif:GPSLongitude', + 'exif:GPSAltitudeRef', + 'exif:GPSAltitude', + 'exif:GPSTimeStamp', + 'exif:GPSSatellites', + 'exif:GPSStatus', + 'exif:GPSMeasureMode', + 'exif:GPSDOP', + 'exif:GPSSpeedRef', + 'exif:GPSSpeed', + 'exif:GPSTrackRef', + 'exif:GPSTrack', + 'exif:GPSImgDirectionRef', + 'exif:GPSImgDirection', + 'exif:GPSMapDatum', + 'exif:GPSDestLatitude', + 'exif:GPSDestLongitude', + 'exif:GPSDestBearingRef', + 'exif:GPSDestBearing', + 'exif:GPSDestDistanceRef', + 'exif:GPSDestDistance', + 'exif:GPSProcessingMethod', + 'exif:GPSAreaInformation', + 'exif:GPSDifferential', + 'stDim:w', + 'stDim:h', + 'stDim:unit', + 'xapGImg:height', + 'xapGImg:width', + 'xapGImg:format', + 'xapGImg:image', + 'stEvt:action', + 'stEvt:instanceID', + 'stEvt:parameters', + 'stEvt:softwareAgent', + 'stEvt:when', + 'stRef:instanceID', + 'stRef:documentID', + 'stRef:versionID', + 'stRef:renditionClass', + 'stRef:renditionParams', + 'stRef:manager', + 'stRef:managerVariant', + 'stRef:manageTo', + 'stRef:manageUI', + 'stVer:comments', + 'stVer:event', + 'stVer:modifyDate', + 'stVer:modifier', + 'stVer:version', + 'stJob:name', + 'stJob:id', + 'stJob:url', +// Exif Flash + 'exif:Fired', + 'exif:Return', + 'exif:Mode', + 'exif:Function', + 'exif:RedEyeMode', +// Exif OECF/SFR + 'exif:Columns', + 'exif:Rows', + 'exif:Names', + 'exif:Values', +// Exif CFAPattern + 'exif:Columns', + 'exif:Rows', + 'exif:Values', +// Exif DeviceSettings + 'exif:Columns', + 'exif:Rows', + 'exif:Settings', +); +*/ + +/** +* Global Variable: JPEG_Segment_Names +* +* The names of the JPEG segment markers, indexed by their marker number +*/ +$GLOBALS['JPEG_Segment_Names'] = array( + 0x01 => 'TEM', + 0x02 => 'RES', + 0xC0 => 'SOF0', + 0xC1 => 'SOF1', + 0xC2 => 'SOF2', + 0xC3 => 'SOF4', + 0xC4 => 'DHT', + 0xC5 => 'SOF5', + 0xC6 => 'SOF6', + 0xC7 => 'SOF7', + 0xC8 => 'JPG', + 0xC9 => 'SOF9', + 0xCA => 'SOF10', + 0xCB => 'SOF11', + 0xCC => 'DAC', + 0xCD => 'SOF13', + 0xCE => 'SOF14', + 0xCF => 'SOF15', + 0xD0 => 'RST0', + 0xD1 => 'RST1', + 0xD2 => 'RST2', + 0xD3 => 'RST3', + 0xD4 => 'RST4', + 0xD5 => 'RST5', + 0xD6 => 'RST6', + 0xD7 => 'RST7', + 0xD8 => 'SOI', + 0xD9 => 'EOI', + 0xDA => 'SOS', + 0xDB => 'DQT', + 0xDC => 'DNL', + 0xDD => 'DRI', + 0xDE => 'DHP', + 0xDF => 'EXP', + 0xE0 => 'APP0', + 0xE1 => 'APP1', + 0xE2 => 'APP2', + 0xE3 => 'APP3', + 0xE4 => 'APP4', + 0xE5 => 'APP5', + 0xE6 => 'APP6', + 0xE7 => 'APP7', + 0xE8 => 'APP8', + 0xE9 => 'APP9', + 0xEA => 'APP10', + 0xEB => 'APP11', + 0xEC => 'APP12', + 0xED => 'APP13', + 0xEE => 'APP14', + 0xEF => 'APP15', + 0xF0 => 'JPG0', + 0xF1 => 'JPG1', + 0xF2 => 'JPG2', + 0xF3 => 'JPG3', + 0xF4 => 'JPG4', + 0xF5 => 'JPG5', + 0xF6 => 'JPG6', + 0xF7 => 'JPG7', + 0xF8 => 'JPG8', + 0xF9 => 'JPG9', + 0xFA => 'JPG10', + 0xFB => 'JPG11', + 0xFC => 'JPG12', + 0xFD => 'JPG13', + 0xFE => 'COM', +); diff --git a/app/libs/vendor/getid3/write.apetag.php b/app/libs/vendor/getid3/write.apetag.php index 540201ba..68bd771d 100644 --- a/app/libs/vendor/getid3/write.apetag.php +++ b/app/libs/vendor/getid3/write.apetag.php @@ -1,223 +1,223 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.apetag.php // -// module for writing APE tags // -// dependencies: module.tag.apetag.php // -// /// -///////////////////////////////////////////////////////////////// - - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); - -class getid3_write_apetag -{ - - public $filename; - public $tag_data; - public $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_apetag() { - return true; - } - - public function WriteAPEtag() { - // NOTE: All data passed to this function must be UTF-8 format - - $getID3 = new getID3; - $ThisFileInfo = $getID3->analyze($this->filename); - - if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { - if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) { - // Current APE tag between Lyrics3 and ID3v1/EOF - // This break Lyrics3 functionality - if (!$this->DeleteAPEtag()) { - return false; - } - $ThisFileInfo = $getID3->analyze($this->filename); - } - } - - if ($this->always_preserve_replaygain) { - $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'); - foreach ($ReplayGainTagsToPreserve as $rg_key) { - if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) { - $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]; - } - } - } - - if ($APEtag = $this->GenerateAPEtag()) { - if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { - $oldignoreuserabort = ignore_user_abort(true); - flock($fp, LOCK_EX); - - $PostAPEdataOffset = $ThisFileInfo['avdataend']; - if (isset($ThisFileInfo['ape']['tag_offset_end'])) { - $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']); - } - if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) { - $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']); - } - fseek($fp, $PostAPEdataOffset, SEEK_SET); - $PostAPEdata = ''; - if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) { - $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset); - } - - fseek($fp, $PostAPEdataOffset, SEEK_SET); - if (isset($ThisFileInfo['ape']['tag_offset_start'])) { - fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); - } - ftruncate($fp, ftell($fp)); - fwrite($fp, $APEtag, strlen($APEtag)); - if (!empty($PostAPEdata)) { - fwrite($fp, $PostAPEdata, strlen($PostAPEdata)); - } - flock($fp, LOCK_UN); - fclose($fp); - ignore_user_abort($oldignoreuserabort); - return true; - } - } - return false; - } - - public function DeleteAPEtag() { - $getID3 = new getID3; - $ThisFileInfo = $getID3->analyze($this->filename); - if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { - if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { - - flock($fp, LOCK_EX); - $oldignoreuserabort = ignore_user_abort(true); - - fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET); - $DataAfterAPE = ''; - if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { - $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); - } - - ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); - fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); - - if (!empty($DataAfterAPE)) { - fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); - } - - flock($fp, LOCK_UN); - fclose($fp); - ignore_user_abort($oldignoreuserabort); - - return true; - } - return false; - } - return true; - } - - - public function GenerateAPEtag() { - // NOTE: All data passed to this function must be UTF-8 format - - $items = array(); - if (!is_array($this->tag_data)) { - return false; - } - foreach ($this->tag_data as $key => $arrayofvalues) { - if (!is_array($arrayofvalues)) { - return false; - } - - $valuestring = ''; - foreach ($arrayofvalues as $value) { - $valuestring .= str_replace("\x00", '', $value)."\x00"; - } - $valuestring = rtrim($valuestring, "\x00"); - - // Length of the assigned value in bytes - $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4); - - //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false); - $tagitem .= "\x00\x00\x00\x00"; - - $tagitem .= $this->CleanAPEtagItemKey($key)."\x00"; - $tagitem .= $valuestring; - - $items[] = $tagitem; - - } - - return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false); - } - - public function GenerateAPEtagHeaderFooter(&$items, $isheader=false) { - $tagdatalength = 0; - foreach ($items as $itemdata) { - $tagdatalength += strlen($itemdata); - } - - $APEheader = 'APETAGEX'; - $APEheader .= getid3_lib::LittleEndian2String(2000, 4); - $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4); - $APEheader .= getid3_lib::LittleEndian2String(count($items), 4); - $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); - $APEheader .= str_repeat("\x00", 8); - - return $APEheader; - } - - public function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) { - $APEtagFlags = array_fill(0, 4, 0); - if ($header) { - $APEtagFlags[0] |= 0x80; // Tag contains a header - } - if (!$footer) { - $APEtagFlags[0] |= 0x40; // Tag contains no footer - } - if ($isheader) { - $APEtagFlags[0] |= 0x20; // This is the header, not the footer - } - - // 0: Item contains text information coded in UTF-8 - // 1: Item contains binary information °) - // 2: Item is a locator of external stored information °°) - // 3: reserved - $APEtagFlags[3] |= ($encodingid << 1); - - if ($readonly) { - $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only - } - - return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]); - } - - public function CleanAPEtagItemKey($itemkey) { - $itemkey = preg_replace("#[^\x20-\x7E]#i", '', $itemkey); - - // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html - switch (strtoupper($itemkey)) { - case 'EAN/UPC': - case 'ISBN': - case 'LC': - case 'ISRC': - $itemkey = strtoupper($itemkey); - break; - - default: - $itemkey = ucwords($itemkey); - break; - } - return $itemkey; - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.apetag.php // +// module for writing APE tags // +// dependencies: module.tag.apetag.php // +// /// +///////////////////////////////////////////////////////////////// + + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.apetag.php', __FILE__, true); + +class getid3_write_apetag +{ + + public $filename; + public $tag_data; + public $always_preserve_replaygain = true; // ReplayGain / MP3gain tags will be copied from old tag even if not passed in data + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_apetag() { + return true; + } + + public function WriteAPEtag() { + // NOTE: All data passed to this function must be UTF-8 format + + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + + if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { + if ($ThisFileInfo['ape']['tag_offset_start'] >= $ThisFileInfo['lyrics3']['tag_offset_end']) { + // Current APE tag between Lyrics3 and ID3v1/EOF + // This break Lyrics3 functionality + if (!$this->DeleteAPEtag()) { + return false; + } + $ThisFileInfo = $getID3->analyze($this->filename); + } + } + + if ($this->always_preserve_replaygain) { + $ReplayGainTagsToPreserve = array('mp3gain_minmax', 'mp3gain_album_minmax', 'mp3gain_undo', 'replaygain_track_peak', 'replaygain_track_gain', 'replaygain_album_peak', 'replaygain_album_gain'); + foreach ($ReplayGainTagsToPreserve as $rg_key) { + if (isset($ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]) && !isset($this->tag_data[strtoupper($rg_key)][0])) { + $this->tag_data[strtoupper($rg_key)][0] = $ThisFileInfo['ape']['items'][strtolower($rg_key)]['data'][0]; + } + } + } + + if ($APEtag = $this->GenerateAPEtag()) { + if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { + $oldignoreuserabort = ignore_user_abort(true); + flock($fp, LOCK_EX); + + $PostAPEdataOffset = $ThisFileInfo['avdataend']; + if (isset($ThisFileInfo['ape']['tag_offset_end'])) { + $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['ape']['tag_offset_end']); + } + if (isset($ThisFileInfo['lyrics3']['tag_offset_start'])) { + $PostAPEdataOffset = max($PostAPEdataOffset, $ThisFileInfo['lyrics3']['tag_offset_start']); + } + fseek($fp, $PostAPEdataOffset, SEEK_SET); + $PostAPEdata = ''; + if ($ThisFileInfo['filesize'] > $PostAPEdataOffset) { + $PostAPEdata = fread($fp, $ThisFileInfo['filesize'] - $PostAPEdataOffset); + } + + fseek($fp, $PostAPEdataOffset, SEEK_SET); + if (isset($ThisFileInfo['ape']['tag_offset_start'])) { + fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); + } + ftruncate($fp, ftell($fp)); + fwrite($fp, $APEtag, strlen($APEtag)); + if (!empty($PostAPEdata)) { + fwrite($fp, $PostAPEdata, strlen($PostAPEdata)); + } + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + return true; + } + } + return false; + } + + public function DeleteAPEtag() { + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['ape']['tag_offset_start']) && isset($ThisFileInfo['ape']['tag_offset_end'])) { + if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { + + flock($fp, LOCK_EX); + $oldignoreuserabort = ignore_user_abort(true); + + fseek($fp, $ThisFileInfo['ape']['tag_offset_end'], SEEK_SET); + $DataAfterAPE = ''; + if ($ThisFileInfo['filesize'] > $ThisFileInfo['ape']['tag_offset_end']) { + $DataAfterAPE = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['ape']['tag_offset_end']); + } + + ftruncate($fp, $ThisFileInfo['ape']['tag_offset_start']); + fseek($fp, $ThisFileInfo['ape']['tag_offset_start'], SEEK_SET); + + if (!empty($DataAfterAPE)) { + fwrite($fp, $DataAfterAPE, strlen($DataAfterAPE)); + } + + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + + return true; + } + return false; + } + return true; + } + + + public function GenerateAPEtag() { + // NOTE: All data passed to this function must be UTF-8 format + + $items = array(); + if (!is_array($this->tag_data)) { + return false; + } + foreach ($this->tag_data as $key => $arrayofvalues) { + if (!is_array($arrayofvalues)) { + return false; + } + + $valuestring = ''; + foreach ($arrayofvalues as $value) { + $valuestring .= str_replace("\x00", '', $value)."\x00"; + } + $valuestring = rtrim($valuestring, "\x00"); + + // Length of the assigned value in bytes + $tagitem = getid3_lib::LittleEndian2String(strlen($valuestring), 4); + + //$tagitem .= $this->GenerateAPEtagFlags(true, true, false, 0, false); + $tagitem .= "\x00\x00\x00\x00"; + + $tagitem .= $this->CleanAPEtagItemKey($key)."\x00"; + $tagitem .= $valuestring; + + $items[] = $tagitem; + + } + + return $this->GenerateAPEtagHeaderFooter($items, true).implode('', $items).$this->GenerateAPEtagHeaderFooter($items, false); + } + + public function GenerateAPEtagHeaderFooter(&$items, $isheader=false) { + $tagdatalength = 0; + foreach ($items as $itemdata) { + $tagdatalength += strlen($itemdata); + } + + $APEheader = 'APETAGEX'; + $APEheader .= getid3_lib::LittleEndian2String(2000, 4); + $APEheader .= getid3_lib::LittleEndian2String(32 + $tagdatalength, 4); + $APEheader .= getid3_lib::LittleEndian2String(count($items), 4); + $APEheader .= $this->GenerateAPEtagFlags(true, true, $isheader, 0, false); + $APEheader .= str_repeat("\x00", 8); + + return $APEheader; + } + + public function GenerateAPEtagFlags($header=true, $footer=true, $isheader=false, $encodingid=0, $readonly=false) { + $APEtagFlags = array_fill(0, 4, 0); + if ($header) { + $APEtagFlags[0] |= 0x80; // Tag contains a header + } + if (!$footer) { + $APEtagFlags[0] |= 0x40; // Tag contains no footer + } + if ($isheader) { + $APEtagFlags[0] |= 0x20; // This is the header, not the footer + } + + // 0: Item contains text information coded in UTF-8 + // 1: Item contains binary information °) + // 2: Item is a locator of external stored information °°) + // 3: reserved + $APEtagFlags[3] |= ($encodingid << 1); + + if ($readonly) { + $APEtagFlags[3] |= 0x01; // Tag or Item is Read Only + } + + return chr($APEtagFlags[3]).chr($APEtagFlags[2]).chr($APEtagFlags[1]).chr($APEtagFlags[0]); + } + + public function CleanAPEtagItemKey($itemkey) { + $itemkey = preg_replace("#[^\x20-\x7E]#i", '', $itemkey); + + // http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html + switch (strtoupper($itemkey)) { + case 'EAN/UPC': + case 'ISBN': + case 'LC': + case 'ISRC': + $itemkey = strtoupper($itemkey); + break; + + default: + $itemkey = ucwords($itemkey); + break; + } + return $itemkey; + + } + +} diff --git a/app/libs/vendor/getid3/write.id3v1.php b/app/libs/vendor/getid3/write.id3v1.php index 6309b98a..86d50920 100644 --- a/app/libs/vendor/getid3/write.id3v1.php +++ b/app/libs/vendor/getid3/write.id3v1.php @@ -1,136 +1,136 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.id3v1.php // -// module for writing ID3v1 tags // -// dependencies: module.tag.id3v1.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); - -class getid3_write_id3v1 -{ - public $filename; - public $filesize; - public $tag_data; - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_id3v1() { - return true; - } - - public function WriteID3v1() { - // File MUST be writeable - CHMOD(646) at least - if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) { - $this->setRealFileSize(); - if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { - $this->errors[] = 'Unable to WriteID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - if ($fp_source = fopen($this->filename, 'r+b')) { - fseek($fp_source, -128, SEEK_END); - if (fread($fp_source, 3) == 'TAG') { - fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag - } else { - fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag - } - $this->tag_data['track'] = (isset($this->tag_data['track']) ? $this->tag_data['track'] : (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : (isset($this->tag_data['tracknumber']) ? $this->tag_data['tracknumber'] : ''))); - - $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag( - (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''), - (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''), - (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''), - (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''), - (isset($this->tag_data['genreid']) ? $this->tag_data['genreid'] : ''), - (isset($this->tag_data['comment']) ? $this->tag_data['comment'] : ''), - (isset($this->tag_data['track'] ) ? $this->tag_data['track'] : '')); - fwrite($fp_source, $new_id3v1_tag_data, 128); - fclose($fp_source); - return true; - - } else { - $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; - return false; - } - } - $this->errors[] = 'File is not writeable: '.$this->filename; - return false; - } - - public function FixID3v1Padding() { - // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces - // This function rewrites the ID3v1 tag with correct padding - - // Initialize getID3 engine - $getID3 = new getID3; - $getID3->option_tag_id3v2 = false; - $getID3->option_tag_apetag = false; - $getID3->option_tags_html = false; - $getID3->option_extra_info = false; - $getID3->option_tag_id3v1 = true; - $ThisFileInfo = $getID3->analyze($this->filename); - if (isset($ThisFileInfo['tags']['id3v1'])) { - foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) { - $id3v1data[$key] = implode(',', $value); - } - $this->tag_data = $id3v1data; - return $this->WriteID3v1(); - } - return false; - } - - public function RemoveID3v1() { - // File MUST be writeable - CHMOD(646) at least - if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) { - $this->setRealFileSize(); - if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { - $this->errors[] = 'Unable to RemoveID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - return false; - } - if ($fp_source = fopen($this->filename, 'r+b')) { - - fseek($fp_source, -128, SEEK_END); - if (fread($fp_source, 3) == 'TAG') { - ftruncate($fp_source, $this->filesize - 128); - } else { - // no ID3v1 tag to begin with - do nothing - } - fclose($fp_source); - return true; - - } else { - $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; - } - } else { - $this->errors[] = $this->filename.' is not writeable'; - } - return false; - } - - public function setRealFileSize() { - if (PHP_INT_MAX > 2147483647) { - $this->filesize = filesize($this->filename); - return true; - } - // 32-bit PHP will not return correct values for filesize() if file is >=2GB - // but getID3->analyze() has workarounds to get actual filesize - $getID3 = new getID3; - $getID3->option_tag_id3v1 = false; - $getID3->option_tag_id3v2 = false; - $getID3->option_tag_apetag = false; - $getID3->option_tags_html = false; - $getID3->option_extra_info = false; - $ThisFileInfo = $getID3->analyze($this->filename); - $this->filesize = $ThisFileInfo['filesize']; - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.id3v1.php // +// module for writing ID3v1 tags // +// dependencies: module.tag.id3v1.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v1.php', __FILE__, true); + +class getid3_write_id3v1 +{ + public $filename; + public $filesize; + public $tag_data; + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_id3v1() { + return true; + } + + public function WriteID3v1() { + // File MUST be writeable - CHMOD(646) at least + if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) { + $this->setRealFileSize(); + if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { + $this->errors[] = 'Unable to WriteID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + if ($fp_source = fopen($this->filename, 'r+b')) { + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + fseek($fp_source, -128, SEEK_END); // overwrite existing ID3v1 tag + } else { + fseek($fp_source, 0, SEEK_END); // append new ID3v1 tag + } + $this->tag_data['track'] = (isset($this->tag_data['track']) ? $this->tag_data['track'] : (isset($this->tag_data['track_number']) ? $this->tag_data['track_number'] : (isset($this->tag_data['tracknumber']) ? $this->tag_data['tracknumber'] : ''))); + + $new_id3v1_tag_data = getid3_id3v1::GenerateID3v1Tag( + (isset($this->tag_data['title'] ) ? $this->tag_data['title'] : ''), + (isset($this->tag_data['artist'] ) ? $this->tag_data['artist'] : ''), + (isset($this->tag_data['album'] ) ? $this->tag_data['album'] : ''), + (isset($this->tag_data['year'] ) ? $this->tag_data['year'] : ''), + (isset($this->tag_data['genreid']) ? $this->tag_data['genreid'] : ''), + (isset($this->tag_data['comment']) ? $this->tag_data['comment'] : ''), + (isset($this->tag_data['track'] ) ? $this->tag_data['track'] : '')); + fwrite($fp_source, $new_id3v1_tag_data, 128); + fclose($fp_source); + return true; + + } else { + $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; + return false; + } + } + $this->errors[] = 'File is not writeable: '.$this->filename; + return false; + } + + public function FixID3v1Padding() { + // ID3v1 data is supposed to be padded with NULL characters, but some taggers incorrectly use spaces + // This function rewrites the ID3v1 tag with correct padding + + // Initialize getID3 engine + $getID3 = new getID3; + $getID3->option_tag_id3v2 = false; + $getID3->option_tag_apetag = false; + $getID3->option_tags_html = false; + $getID3->option_extra_info = false; + $getID3->option_tag_id3v1 = true; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['tags']['id3v1'])) { + foreach ($ThisFileInfo['tags']['id3v1'] as $key => $value) { + $id3v1data[$key] = implode(',', $value); + } + $this->tag_data = $id3v1data; + return $this->WriteID3v1(); + } + return false; + } + + public function RemoveID3v1() { + // File MUST be writeable - CHMOD(646) at least + if (!empty($this->filename) && is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename)) { + $this->setRealFileSize(); + if (($this->filesize <= 0) || !getid3_lib::intValueSupported($this->filesize)) { + $this->errors[] = 'Unable to RemoveID3v1('.$this->filename.') because filesize ('.$this->filesize.') is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + return false; + } + if ($fp_source = fopen($this->filename, 'r+b')) { + + fseek($fp_source, -128, SEEK_END); + if (fread($fp_source, 3) == 'TAG') { + ftruncate($fp_source, $this->filesize - 128); + } else { + // no ID3v1 tag to begin with - do nothing + } + fclose($fp_source); + return true; + + } else { + $this->errors[] = 'Could not fopen('.$this->filename.', "r+b")'; + } + } else { + $this->errors[] = $this->filename.' is not writeable'; + } + return false; + } + + public function setRealFileSize() { + if (PHP_INT_MAX > 2147483647) { + $this->filesize = filesize($this->filename); + return true; + } + // 32-bit PHP will not return correct values for filesize() if file is >=2GB + // but getID3->analyze() has workarounds to get actual filesize + $getID3 = new getID3; + $getID3->option_tag_id3v1 = false; + $getID3->option_tag_id3v2 = false; + $getID3->option_tag_apetag = false; + $getID3->option_tags_html = false; + $getID3->option_extra_info = false; + $ThisFileInfo = $getID3->analyze($this->filename); + $this->filesize = $ThisFileInfo['filesize']; + return true; + } + +} diff --git a/app/libs/vendor/getid3/write.id3v2.php b/app/libs/vendor/getid3/write.id3v2.php index bd18be52..3d2bfecc 100644 --- a/app/libs/vendor/getid3/write.id3v2.php +++ b/app/libs/vendor/getid3/write.id3v2.php @@ -1,2049 +1,2049 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -/// // -// write.id3v2.php // -// module for writing ID3v2 tags // -// dependencies: module.tag.id3v2.php // -// /// -///////////////////////////////////////////////////////////////// - -getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); - -class getid3_write_id3v2 -{ - public $filename; - public $tag_data; - public $fread_buffer_size = 32768; // read buffer size in bytes - public $paddedlength = 4096; // minimum length of ID3v2 tag in bytes - public $majorversion = 3; // ID3v2 major version (2, 3 (recommended), 4) - public $minorversion = 0; // ID3v2 minor version - always 0 - public $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags - public $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed - public $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it. - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_id3v2() { - return true; - } - - public function WriteID3v2() { - // File MUST be writeable - CHMOD(646) at least. It's best if the - // directory is also writeable, because that method is both faster and less susceptible to errors. - - if (!empty($this->filename) && (is_writeable($this->filename) || (!file_exists($this->filename) && is_writeable(dirname($this->filename))))) { - // Initialize getID3 engine - $getID3 = new getID3; - $OldThisFileInfo = $getID3->analyze($this->filename); - if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { - $this->errors[] = 'Unable to write ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - fclose($fp_source); - return false; - } - if ($this->merge_existing_data) { - // merge with existing data - if (!empty($OldThisFileInfo['id3v2'])) { - $this->tag_data = $this->array_join_merge($OldThisFileInfo['id3v2'], $this->tag_data); - } - } - $this->paddedlength = (isset($OldThisFileInfo['id3v2']['headerlength']) ? max($OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength) : $this->paddedlength); - - if ($NewID3v2Tag = $this->GenerateID3v2Tag()) { - - if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) { - - // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) - if (file_exists($this->filename)) { - - if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; - } - - } else { - - if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'wb'))) { - rewind($fp); - fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); - fclose($fp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; - } - - } - - } else { - - if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { - if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { - if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { - - fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); - - rewind($fp_source); - if (!empty($OldThisFileInfo['avdataoffset'])) { - fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); - } - - while ($buffer = fread($fp_source, $this->fread_buffer_size)) { - fwrite($fp_temp, $buffer, strlen($buffer)); - } - - fclose($fp_temp); - fclose($fp_source); - copy($tempfilename, $this->filename); - unlink($tempfilename); - return true; - - } else { - $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; - } - fclose($fp_source); - - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; - } - } - return false; - - } - - } else { - - $this->errors[] = '$this->GenerateID3v2Tag() failed'; - - } - - if (!empty($this->errors)) { - return false; - } - return true; - } else { - $this->errors[] = 'WriteID3v2() failed: !is_writeable('.$this->filename.')'; - } - return false; - } - - public function RemoveID3v2() { - // File MUST be writeable - CHMOD(646) at least. It's best if the - // directory is also writeable, because that method is both faster and less susceptible to errors. - if (is_writeable(dirname($this->filename))) { - - // preferred method - only one copying operation, minimal chance of corrupting - // original file if script is interrupted, but required directory to be writeable - if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { - - // Initialize getID3 engine - $getID3 = new getID3; - $OldThisFileInfo = $getID3->analyze($this->filename); - if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { - $this->errors[] = 'Unable to remove ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - fclose($fp_source); - return false; - } - rewind($fp_source); - if ($OldThisFileInfo['avdataoffset'] !== false) { - fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); - } - if (is_writable($this->filename) && is_file($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { - while ($buffer = fread($fp_source, $this->fread_buffer_size)) { - fwrite($fp_temp, $buffer, strlen($buffer)); - } - fclose($fp_temp); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'getid3tmp", "w+b")'; - } - fclose($fp_source); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; - } - if (file_exists($this->filename)) { - unlink($this->filename); - } - rename($this->filename.'getid3tmp', $this->filename); - - } elseif (is_writable($this->filename)) { - - // less desirable alternate method - double-copies the file, overwrites original file - // and could corrupt source file if the script is interrupted or an error occurs. - if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { - - // Initialize getID3 engine - $getID3 = new getID3; - $OldThisFileInfo = $getID3->analyze($this->filename); - if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { - $this->errors[] = 'Unable to remove ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; - fclose($fp_source); - return false; - } - rewind($fp_source); - if ($OldThisFileInfo['avdataoffset'] !== false) { - fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); - } - if ($fp_temp = tmpfile()) { - while ($buffer = fread($fp_source, $this->fread_buffer_size)) { - fwrite($fp_temp, $buffer, strlen($buffer)); - } - fclose($fp_source); - if (is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { - rewind($fp_temp); - while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { - fwrite($fp_source, $buffer, strlen($buffer)); - } - fseek($fp_temp, -128, SEEK_END); - fclose($fp_source); - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; - } - fclose($fp_temp); - } else { - $this->errors[] = 'Could not create tmpfile()'; - } - } else { - $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; - } - - } else { - - $this->errors[] = 'Directory and file both not writeable'; - - } - - if (!empty($this->errors)) { - return false; - } - return true; - } - - - public function GenerateID3v2TagFlags($flags) { - switch ($this->majorversion) { - case 4: - // %abcd0000 - $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation - $flag .= (!empty($flags['extendedheader'] ) ? '1' : '0'); // b - Extended header - $flag .= (!empty($flags['experimental'] ) ? '1' : '0'); // c - Experimental indicator - $flag .= (!empty($flags['footer'] ) ? '1' : '0'); // d - Footer present - $flag .= '0000'; - break; - - case 3: - // %abc00000 - $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation - $flag .= (!empty($flags['extendedheader'] ) ? '1' : '0'); // b - Extended header - $flag .= (!empty($flags['experimental'] ) ? '1' : '0'); // c - Experimental indicator - $flag .= '00000'; - break; - - case 2: - // %ab000000 - $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation - $flag .= (!empty($flags['compression'] ) ? '1' : '0'); // b - Compression - $flag .= '000000'; - break; - - default: - return false; - break; - } - return chr(bindec($flag)); - } - - - public function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) { - switch ($this->majorversion) { - case 4: - // %0abc0000 %0h00kmnp - $flag1 = '0'; - $flag1 .= $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) - $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) - $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) - $flag1 .= '0000'; - - $flag2 = '0'; - $flag2 .= $GroupingIdentity ? '1' : '0'; // h - Grouping identity (true == contains group information) - $flag2 .= '00'; - $flag2 .= $Compression ? '1' : '0'; // k - Compression (true == compressed) - $flag2 .= $Encryption ? '1' : '0'; // m - Encryption (true == encrypted) - $flag2 .= $Unsynchronisation ? '1' : '0'; // n - Unsynchronisation (true == unsynchronised) - $flag2 .= $DataLengthIndicator ? '1' : '0'; // p - Data length indicator (true == data length indicator added) - break; - - case 3: - // %abc00000 %ijk00000 - $flag1 = $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) - $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) - $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) - $flag1 .= '00000'; - - $flag2 = $Compression ? '1' : '0'; // i - Compression (true == compressed) - $flag2 .= $Encryption ? '1' : '0'; // j - Encryption (true == encrypted) - $flag2 .= $GroupingIdentity ? '1' : '0'; // k - Grouping identity (true == contains group information) - $flag2 .= '00000'; - break; - - default: - return false; - break; - - } - return chr(bindec($flag1)).chr(bindec($flag2)); - } - - public function GenerateID3v2FrameData($frame_name, $source_data_array) { - if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { - return false; - } - $framedata = ''; - - if (($this->majorversion < 3) || ($this->majorversion > 4)) { - - $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()'; - - } else { // $this->majorversion 3 or 4 - - switch ($frame_name) { - case 'UFID': - // 4.1 UFID Unique file identifier - // Owner identifier $00 - // Identifier - if (strlen($source_data_array['data']) > 64) { - $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)'; - } else { - $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; - $framedata .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer - } - break; - - case 'TXXX': - // 4.2.2 TXXX User defined text information frame - // Text encoding $xx - // Description $00 (00) - // Value - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'WXXX': - // 4.3.2 WXXX User defined URL link frame - // Text encoding $xx - // Description $00 (00) - // URL - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (!isset($source_data_array['data']) || !$this->IsValidURL($source_data_array['data'], false, false)) { - //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - // probably should be an error, need to rewrite IsValidURL() to handle other encodings - $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'IPLS': - // 4.4 IPLS Involved people list (ID3v2.3 only) - // Text encoding $xx - // People list strings - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'MCDI': - // 4.4 MCDI Music CD identifier - // CD TOC - $framedata .= $source_data_array['data']; - break; - - case 'ETCO': - // 4.5 ETCO Event timing codes - // Time stamp format $xx - // Where time stamp format is: - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - // Followed by a list of key events in the following format: - // Type of event $xx - // Time stamp $xx (xx ...) - // The 'Time stamp' is set to zero if directly at the beginning of the sound - // or after the previous event. All events MUST be sorted in chronological order. - if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { - $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; - } else { - $framedata .= chr($source_data_array['timestampformat']); - foreach ($source_data_array as $key => $val) { - if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { - $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; - } elseif (($key != 'timestampformat') && ($key != 'flags')) { - if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) { - // The 'Time stamp' is set to zero if directly at the beginning of the sound - // or after the previous event. All events MUST be sorted in chronological order. - $this->errors[] = 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')'; - } else { - $framedata .= chr($val['typeid']); - $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); - } - } - } - } - break; - - case 'MLLT': - // 4.6 MLLT MPEG location lookup table - // MPEG frames between reference $xx xx - // Bytes between reference $xx xx xx - // Milliseconds between reference $xx xx xx - // Bits for bytes deviation $xx - // Bits for milliseconds dev. $xx - // Then for every reference the following data is included; - // Deviation in bytes %xxx.... - // Deviation in milliseconds %xxx.... - if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false); - } else { - $this->errors[] = 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')'; - } - if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false); - } else { - $this->errors[] = 'Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')'; - } - if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false); - } else { - $this->errors[] = 'Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')'; - } - if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) { - if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) { - $framedata .= chr($source_data_array['bitsforbytesdeviation']); - } else { - $this->errors[] = 'Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; - } - } else { - $this->errors[] = 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')'; - } - if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) { - if (($source_data_array['bitsformsdeviation'] % 4) == 0) { - $framedata .= chr($source_data_array['bitsformsdeviation']); - } else { - $this->errors[] = 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; - } - } else { - $this->errors[] = 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')'; - } - foreach ($source_data_array as $key => $val) { - if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) { - $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT); - $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT); - } - } - for ($i = 0; $i < strlen($unwrittenbitstream); $i += 8) { - $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4; - $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4)); - $framedata .= chr($highnibble & $lownibble); - } - break; - - case 'SYTC': - // 4.7 SYTC Synchronised tempo codes - // Time stamp format $xx - // Tempo data - // Where time stamp format is: - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { - $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; - } else { - $framedata .= chr($source_data_array['timestampformat']); - foreach ($source_data_array as $key => $val) { - if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { - $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; - } elseif (($key != 'timestampformat') && ($key != 'flags')) { - if (($val['tempo'] < 0) || ($val['tempo'] > 510)) { - $this->errors[] = 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')'; - } else { - if ($val['tempo'] > 255) { - $framedata .= chr(255); - $val['tempo'] -= 255; - } - $framedata .= chr($val['tempo']); - $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); - } - } - } - } - break; - - case 'USLT': - // 4.8 USLT Unsynchronised lyric/text transcription - // Text encoding $xx - // Language $xx xx xx - // Content descriptor $00 (00) - // Lyrics/text - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { - $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= strtolower($source_data_array['language']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'SYLT': - // 4.9 SYLT Synchronised lyric/text - // Text encoding $xx - // Language $xx xx xx - // Time stamp format $xx - // $01 (32-bit value) MPEG frames from beginning of file - // $02 (32-bit value) milliseconds from beginning of file - // Content type $xx - // Content descriptor $00 (00) - // Terminated text to be synced (typically a syllable) - // Sync identifier (terminator to above string) $00 (00) - // Time stamp $xx (xx ...) - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { - $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; - } elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { - $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; - } elseif (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) { - $this->errors[] = 'Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')'; - } elseif (!is_array($source_data_array['data'])) { - $this->errors[] = 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= strtolower($source_data_array['language']); - $framedata .= chr($source_data_array['timestampformat']); - $framedata .= chr($source_data_array['contenttypeid']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - ksort($source_data_array['data']); - foreach ($source_data_array['data'] as $key => $val) { - $framedata .= $val['data'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); - } - } - break; - - case 'COMM': - // 4.10 COMM Comments - // Text encoding $xx - // Language $xx xx xx - // Short content descrip. $00 (00) - // The actual text - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { - $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= strtolower($source_data_array['language']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'RVA2': - // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) - // Identification $00 - // The 'identification' string is used to identify the situation and/or - // device where this adjustment should apply. The following is then - // repeated for every channel: - // Type of channel $xx - // Volume adjustment $xx xx - // Bits representing peak $xx - // Peak volume $xx (xx ...) - $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; - foreach ($source_data_array as $key => $val) { - if ($key != 'description') { - $framedata .= chr($val['channeltypeid']); - $framedata .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit - if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) { - $framedata .= chr($val['bitspeakvolume']); - if ($val['bitspeakvolume'] > 0) { - $framedata .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false); - } - } else { - $this->errors[] = 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)'; - } - } - } - break; - - case 'RVAD': - // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) - // Increment/decrement %00fedcba - // Bits used for volume descr. $xx - // Relative volume change, right $xx xx (xx ...) // a - // Relative volume change, left $xx xx (xx ...) // b - // Peak volume right $xx xx (xx ...) - // Peak volume left $xx xx (xx ...) - // Relative volume change, right back $xx xx (xx ...) // c - // Relative volume change, left back $xx xx (xx ...) // d - // Peak volume right back $xx xx (xx ...) - // Peak volume left back $xx xx (xx ...) - // Relative volume change, center $xx xx (xx ...) // e - // Peak volume center $xx xx (xx ...) - // Relative volume change, bass $xx xx (xx ...) // f - // Peak volume bass $xx xx (xx ...) - if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { - $this->errors[] = 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; - } else { - $incdecflag .= '00'; - $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right - $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left - $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back - $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back - $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center - $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass - $framedata .= chr(bindec($incdecflag)); - $framedata .= chr($source_data_array['bitsvolume']); - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false); - if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] || - $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] || - $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || - $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); - } - if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || - $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume']/8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume']/8), false); - } - if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { - $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume']/8), false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume']/8), false); - } - } - break; - - case 'EQU2': - // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) - // Interpolation method $xx - // $00 Band - // $01 Linear - // Identification $00 - // The following is then repeated for every adjustment point - // Frequency $xx xx - // Volume adjustment $xx xx - if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) { - $this->errors[] = 'Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)'; - } else { - $framedata .= chr($source_data_array['interpolationmethod']); - $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; - foreach ($source_data_array['data'] as $key => $val) { - $framedata .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false); - $framedata .= getid3_lib::BigEndian2String($val, 2, false, true); // signed 16-bit - } - } - break; - - case 'EQUA': - // 4.12 EQUA Equalisation (ID3v2.3 only) - // Adjustment bits $xx - // This is followed by 2 bytes + ('adjustment bits' rounded up to the - // nearest byte) for every equalisation band in the following format, - // giving a frequency range of 0 - 32767Hz: - // Increment/decrement %x (MSB of the Frequency) - // Frequency (lower 15 bits) - // Adjustment $xx (xx ...) - if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { - $this->errors[] = 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; - } else { - $framedata .= chr($source_data_array['adjustmentbits']); - foreach ($source_data_array as $key => $val) { - if ($key != 'bitsvolume') { - if (($key > 32767) || ($key < 0)) { - $this->errors[] = 'Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)'; - } else { - if ($val >= 0) { - // put MSB of frequency to 1 if increment, 0 if decrement - $key |= 0x8000; - } - $framedata .= getid3_lib::BigEndian2String($key, 2, false); - $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false); - } - } - } - } - break; - - case 'RVRB': - // 4.13 RVRB Reverb - // Reverb left (ms) $xx xx - // Reverb right (ms) $xx xx - // Reverb bounces, left $xx - // Reverb bounces, right $xx - // Reverb feedback, left to left $xx - // Reverb feedback, left to right $xx - // Reverb feedback, right to right $xx - // Reverb feedback, right to left $xx - // Premix left to right $xx - // Premix right to left $xx - if (!$this->IsWithinBitRange($source_data_array['left'], 16, false)) { - $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['left'].') (range = 0 to 65535)'; - } elseif (!$this->IsWithinBitRange($source_data_array['right'], 16, false)) { - $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['right'].') (range = 0 to 65535)'; - } elseif (!$this->IsWithinBitRange($source_data_array['bouncesL'], 8, false)) { - $this->errors[] = 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$source_data_array['bouncesL'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['bouncesR'], 8, false)) { - $this->errors[] = 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$source_data_array['bouncesR'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLL'], 8, false)) { - $this->errors[] = 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$source_data_array['feedbackLL'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLR'], 8, false)) { - $this->errors[] = 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$source_data_array['feedbackLR'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRR'], 8, false)) { - $this->errors[] = 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$source_data_array['feedbackRR'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRL'], 8, false)) { - $this->errors[] = 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$source_data_array['feedbackRL'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['premixLR'], 8, false)) { - $this->errors[] = 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$source_data_array['premixLR'].') (range = 0 to 255)'; - } elseif (!$this->IsWithinBitRange($source_data_array['premixRL'], 8, false)) { - $this->errors[] = 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$source_data_array['premixRL'].') (range = 0 to 255)'; - } else { - $framedata .= getid3_lib::BigEndian2String($source_data_array['left'], 2, false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['right'], 2, false); - $framedata .= chr($source_data_array['bouncesL']); - $framedata .= chr($source_data_array['bouncesR']); - $framedata .= chr($source_data_array['feedbackLL']); - $framedata .= chr($source_data_array['feedbackLR']); - $framedata .= chr($source_data_array['feedbackRR']); - $framedata .= chr($source_data_array['feedbackRL']); - $framedata .= chr($source_data_array['premixLR']); - $framedata .= chr($source_data_array['premixRL']); - } - break; - - case 'APIC': - // 4.14 APIC Attached picture - // Text encoding $xx - // MIME type $00 - // Picture type $xx - // Description $00 (00) - // Picture data - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) { - $this->errors[] = 'Invalid Picture Type byte in '.$frame_name.' ('.$source_data_array['picturetypeid'].') for ID3v2.'.$this->majorversion; - } elseif (($this->majorversion >= 3) && (!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) { - $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].') for ID3v2.'.$this->majorversion; - } elseif (($source_data_array['mime'] == '-->') && (!$this->IsValidURL($source_data_array['data'], false, false))) { - //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - // probably should be an error, need to rewrite IsValidURL() to handle other encodings - $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; - $framedata .= chr($source_data_array['picturetypeid']); - $framedata .= (!empty($source_data_array['description']) ? $source_data_array['description'] : '').getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'GEOB': - // 4.15 GEOB General encapsulated object - // Text encoding $xx - // MIME type $00 - // Filename $00 (00) - // Content description $00 (00) - // Encapsulated object - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { - $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; - } elseif (!$source_data_array['description']) { - $this->errors[] = 'Missing Description in '.$frame_name; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; - $framedata .= $source_data_array['filename'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - break; - - case 'PCNT': - // 4.16 PCNT Play counter - // When the counter reaches all one's, one byte is inserted in - // front of the counter thus making the counter eight bits bigger - // Counter $xx xx xx xx (xx ...) - $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); - break; - - case 'POPM': - // 4.17 POPM Popularimeter - // When the counter reaches all one's, one byte is inserted in - // front of the counter thus making the counter eight bits bigger - // Email to user $00 - // Rating $xx - // Counter $xx xx xx xx (xx ...) - if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) { - $this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)'; - } elseif (!IsValidEmail($source_data_array['email'])) { - $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')'; - } else { - $framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00"; - $framedata .= chr($source_data_array['rating']); - $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); - } - break; - - case 'RBUF': - // 4.18 RBUF Recommended buffer size - // Buffer size $xx xx xx - // Embedded info flag %0000000x - // Offset to next tag $xx xx xx xx - if (!$this->IsWithinBitRange($source_data_array['buffersize'], 24, false)) { - $this->errors[] = 'Invalid Buffer Size in '.$frame_name; - } elseif (!$this->IsWithinBitRange($source_data_array['nexttagoffset'], 32, false)) { - $this->errors[] = 'Invalid Offset To Next Tag in '.$frame_name; - } else { - $framedata .= getid3_lib::BigEndian2String($source_data_array['buffersize'], 3, false); - $flag .= '0000000'; - $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0'; - $framedata .= chr(bindec($flag)); - $framedata .= getid3_lib::BigEndian2String($source_data_array['nexttagoffset'], 4, false); - } - break; - - case 'AENC': - // 4.19 AENC Audio encryption - // Owner identifier $00 - // Preview start $xx xx - // Preview length $xx xx - // Encryption info - if (!$this->IsWithinBitRange($source_data_array['previewstart'], 16, false)) { - $this->errors[] = 'Invalid Preview Start in '.$frame_name.' ('.$source_data_array['previewstart'].')'; - } elseif (!$this->IsWithinBitRange($source_data_array['previewlength'], 16, false)) { - $this->errors[] = 'Invalid Preview Length in '.$frame_name.' ('.$source_data_array['previewlength'].')'; - } else { - $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; - $framedata .= getid3_lib::BigEndian2String($source_data_array['previewstart'], 2, false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['previewlength'], 2, false); - $framedata .= $source_data_array['encryptioninfo']; - } - break; - - case 'LINK': - // 4.20 LINK Linked information - // Frame identifier $xx xx xx xx - // URL $00 - // ID and additional data - if (!getid3_id3v2::IsValidID3v2FrameName($source_data_array['frameid'], $this->majorversion)) { - $this->errors[] = 'Invalid Frame Identifier in '.$frame_name.' ('.$source_data_array['frameid'].')'; - } elseif (!$this->IsValidURL($source_data_array['data'], true, false)) { - //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - // probably should be an error, need to rewrite IsValidURL() to handle other encodings - $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - } elseif ((($source_data_array['frameid'] == 'AENC') || ($source_data_array['frameid'] == 'APIC') || ($source_data_array['frameid'] == 'GEOB') || ($source_data_array['frameid'] == 'TXXX')) && ($source_data_array['additionaldata'] == '')) { - $this->errors[] = 'Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; - } elseif (($source_data_array['frameid'] == 'USER') && (getid3_id3v2::LanguageLookup($source_data_array['additionaldata'], true) == '')) { - $this->errors[] = 'Language must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; - } elseif (($source_data_array['frameid'] == 'PRIV') && ($source_data_array['additionaldata'] == '')) { - $this->errors[] = 'Owner Identifier must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; - } elseif ((($source_data_array['frameid'] == 'COMM') || ($source_data_array['frameid'] == 'SYLT') || ($source_data_array['frameid'] == 'USLT')) && ((getid3_id3v2::LanguageLookup(substr($source_data_array['additionaldata'], 0, 3), true) == '') || (substr($source_data_array['additionaldata'], 3) == ''))) { - $this->errors[] = 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; - } else { - $framedata .= $source_data_array['frameid']; - $framedata .= str_replace("\x00", '', $source_data_array['data'])."\x00"; - switch ($source_data_array['frameid']) { - case 'COMM': - case 'SYLT': - case 'USLT': - case 'PRIV': - case 'USER': - case 'AENC': - case 'APIC': - case 'GEOB': - case 'TXXX': - $framedata .= $source_data_array['additionaldata']; - break; - case 'ASPI': - case 'ETCO': - case 'EQU2': - case 'MCID': - case 'MLLT': - case 'OWNE': - case 'RVA2': - case 'RVRB': - case 'SYTC': - case 'IPLS': - case 'RVAD': - case 'EQUA': - // no additional data required - break; - case 'RBUF': - if ($this->majorversion == 3) { - // no additional data required - } else { - $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; - } - - default: - if ((substr($source_data_array['frameid'], 0, 1) == 'T') || (substr($source_data_array['frameid'], 0, 1) == 'W')) { - // no additional data required - } else { - $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; - } - break; - } - } - break; - - case 'POSS': - // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) - // Time stamp format $xx - // Position $xx (xx ...) - if (($source_data_array['timestampformat'] < 1) || ($source_data_array['timestampformat'] > 2)) { - $this->errors[] = 'Invalid Time Stamp Format in '.$frame_name.' ('.$source_data_array['timestampformat'].') (valid = 1 or 2)'; - } elseif (!$this->IsWithinBitRange($source_data_array['position'], 32, false)) { - $this->errors[] = 'Invalid Position in '.$frame_name.' ('.$source_data_array['position'].') (range = 0 to 4294967295)'; - } else { - $framedata .= chr($source_data_array['timestampformat']); - $framedata .= getid3_lib::BigEndian2String($source_data_array['position'], 4, false); - } - break; - - case 'USER': - // 4.22 USER Terms of use (ID3v2.3+ only) - // Text encoding $xx - // Language $xx xx xx - // The actual text - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; - } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { - $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= strtolower($source_data_array['language']); - $framedata .= $source_data_array['data']; - } - break; - - case 'OWNE': - // 4.23 OWNE Ownership frame (ID3v2.3+ only) - // Text encoding $xx - // Price paid $00 - // Date of purch. - // Seller - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; - } elseif (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) { - $this->errors[] = 'Invalid Price Paid in '.$frame_name.' ('.$source_data_array['pricepaid']['value'].')'; - } elseif (!$this->IsValidDateStampString($source_data_array['purchasedate'])) { - $this->errors[] = 'Invalid Date Of Purchase in '.$frame_name.' ('.$source_data_array['purchasedate'].') (format = YYYYMMDD)'; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= str_replace("\x00", '', $source_data_array['pricepaid']['value'])."\x00"; - $framedata .= $source_data_array['purchasedate']; - $framedata .= $source_data_array['seller']; - } - break; - - case 'COMR': - // 4.24 COMR Commercial frame (ID3v2.3+ only) - // Text encoding $xx - // Price string $00 - // Valid until - // Contact URL $00 - // Received as $xx - // Name of seller $00 (00) - // Description $00 (00) - // Picture MIME type $00 - // Seller logo - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; - } elseif (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) { - $this->errors[] = 'Invalid Valid Until date in '.$frame_name.' ('.$source_data_array['pricevaliduntil'].') (format = YYYYMMDD)'; - } elseif (!$this->IsValidURL($source_data_array['contacturl'], false, true)) { - $this->errors[] = 'Invalid Contact URL in '.$frame_name.' ('.$source_data_array['contacturl'].') (allowed schemes: http, https, ftp, mailto)'; - } elseif (!$this->ID3v2IsValidCOMRreceivedAs($source_data_array['receivedasid'])) { - $this->errors[] = 'Invalid Received As byte in '.$frame_name.' ('.$source_data_array['contacturl'].') (range = 0 to 8)'; - } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { - $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; - } else { - $framedata .= chr($source_data_array['encodingid']); - unset($pricestring); - foreach ($source_data_array['price'] as $key => $val) { - if ($this->ID3v2IsValidPriceString($key.$val['value'])) { - $pricestrings[] = $key.$val['value']; - } else { - $this->errors[] = 'Invalid Price String in '.$frame_name.' ('.$key.$val['value'].')'; - } - } - $framedata .= implode('/', $pricestrings); - $framedata .= $source_data_array['pricevaliduntil']; - $framedata .= str_replace("\x00", '', $source_data_array['contacturl'])."\x00"; - $framedata .= chr($source_data_array['receivedasid']); - $framedata .= $source_data_array['sellername'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); - $framedata .= $source_data_array['mime']."\x00"; - $framedata .= $source_data_array['logo']; - } - break; - - case 'ENCR': - // 4.25 ENCR Encryption method registration (ID3v2.3+ only) - // Owner identifier $00 - // Method symbol $xx - // Encryption data - if (!$this->IsWithinBitRange($source_data_array['methodsymbol'], 8, false)) { - $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['methodsymbol'].') (range = 0 to 255)'; - } else { - $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; - $framedata .= ord($source_data_array['methodsymbol']); - $framedata .= $source_data_array['data']; - } - break; - - case 'GRID': - // 4.26 GRID Group identification registration (ID3v2.3+ only) - // Owner identifier $00 - // Group symbol $xx - // Group dependent data - if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { - $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; - } else { - $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; - $framedata .= ord($source_data_array['groupsymbol']); - $framedata .= $source_data_array['data']; - } - break; - - case 'PRIV': - // 4.27 PRIV Private frame (ID3v2.3+ only) - // Owner identifier $00 - // The private data - $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; - $framedata .= $source_data_array['data']; - break; - - case 'SIGN': - // 4.28 SIGN Signature frame (ID3v2.4+ only) - // Group symbol $xx - // Signature - if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { - $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; - } else { - $framedata .= ord($source_data_array['groupsymbol']); - $framedata .= $source_data_array['data']; - } - break; - - case 'SEEK': - // 4.29 SEEK Seek frame (ID3v2.4+ only) - // Minimum offset to next tag $xx xx xx xx - if (!$this->IsWithinBitRange($source_data_array['data'], 32, false)) { - $this->errors[] = 'Invalid Minimum Offset in '.$frame_name.' ('.$source_data_array['data'].') (range = 0 to 4294967295)'; - } else { - $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); - } - break; - - case 'ASPI': - // 4.30 ASPI Audio seek point index (ID3v2.4+ only) - // Indexed data start (S) $xx xx xx xx - // Indexed data length (L) $xx xx xx xx - // Number of index points (N) $xx xx - // Bits per index point (b) $xx - // Then for every index point the following data is included: - // Fraction at index (Fi) $xx (xx) - if (!$this->IsWithinBitRange($source_data_array['datastart'], 32, false)) { - $this->errors[] = 'Invalid Indexed Data Start in '.$frame_name.' ('.$source_data_array['datastart'].') (range = 0 to 4294967295)'; - } elseif (!$this->IsWithinBitRange($source_data_array['datalength'], 32, false)) { - $this->errors[] = 'Invalid Indexed Data Length in '.$frame_name.' ('.$source_data_array['datalength'].') (range = 0 to 4294967295)'; - } elseif (!$this->IsWithinBitRange($source_data_array['indexpoints'], 16, false)) { - $this->errors[] = 'Invalid Number Of Index Points in '.$frame_name.' ('.$source_data_array['indexpoints'].') (range = 0 to 65535)'; - } elseif (!$this->IsWithinBitRange($source_data_array['bitsperpoint'], 8, false)) { - $this->errors[] = 'Invalid Bits Per Index Point in '.$frame_name.' ('.$source_data_array['bitsperpoint'].') (range = 0 to 255)'; - } elseif ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) { - $this->errors[] = 'Number Of Index Points does not match actual supplied data in '.$frame_name; - } else { - $framedata .= getid3_lib::BigEndian2String($source_data_array['datastart'], 4, false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['datalength'], 4, false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['indexpoints'], 2, false); - $framedata .= getid3_lib::BigEndian2String($source_data_array['bitsperpoint'], 1, false); - foreach ($source_data_array['indexes'] as $key => $val) { - $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['bitsperpoint'] / 8), false); - } - } - break; - - case 'RGAD': - // RGAD Replay Gain Adjustment - // http://privatewww.essex.ac.uk/~djmrob/replaygain/ - // Peak Amplitude $xx $xx $xx $xx - // Radio Replay Gain Adjustment %aaabbbcd %dddddddd - // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd - // a - name code - // b - originator code - // c - sign bit - // d - replay gain adjustment - - if (($source_data_array['track_adjustment'] > 51) || ($source_data_array['track_adjustment'] < -51)) { - $this->errors[] = 'Invalid Track Adjustment in '.$frame_name.' ('.$source_data_array['track_adjustment'].') (range = -51.0 to +51.0)'; - } elseif (($source_data_array['album_adjustment'] > 51) || ($source_data_array['album_adjustment'] < -51)) { - $this->errors[] = 'Invalid Album Adjustment in '.$frame_name.' ('.$source_data_array['album_adjustment'].') (range = -51.0 to +51.0)'; - } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['track_name'])) { - $this->errors[] = 'Invalid Track Name Code in '.$frame_name.' ('.$source_data_array['raw']['track_name'].') (range = 0 to 2)'; - } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['album_name'])) { - $this->errors[] = 'Invalid Album Name Code in '.$frame_name.' ('.$source_data_array['raw']['album_name'].') (range = 0 to 2)'; - } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['track_originator'])) { - $this->errors[] = 'Invalid Track Originator Code in '.$frame_name.' ('.$source_data_array['raw']['track_originator'].') (range = 0 to 3)'; - } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['album_originator'])) { - $this->errors[] = 'Invalid Album Originator Code in '.$frame_name.' ('.$source_data_array['raw']['album_originator'].') (range = 0 to 3)'; - } else { - $framedata .= getid3_lib::Float2String($source_data_array['peakamplitude'], 32); - $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['track_name'], $source_data_array['raw']['track_originator'], $source_data_array['track_adjustment']); - $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['album_name'], $source_data_array['raw']['album_originator'], $source_data_array['album_adjustment']); - } - break; - - default: - if ((($this->majorversion == 2) && (strlen($frame_name) != 3)) || (($this->majorversion > 2) && (strlen($frame_name) != 4))) { - $this->errors[] = 'Invalid frame name "'.$frame_name.'" for ID3v2.'.$this->majorversion; - } elseif ($frame_name{0} == 'T') { - // 4.2. T??? Text information frames - // Text encoding $xx - // Information - $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); - if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { - $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; - } else { - $framedata .= chr($source_data_array['encodingid']); - $framedata .= $source_data_array['data']; - } - } elseif ($frame_name{0} == 'W') { - // 4.3. W??? URL link frames - // URL - if (!$this->IsValidURL($source_data_array['data'], false, false)) { - //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - // probably should be an error, need to rewrite IsValidURL() to handle other encodings - $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; - } else { - $framedata .= $source_data_array['data']; - } - } else { - $this->errors[] = $frame_name.' not yet supported in $this->GenerateID3v2FrameData()'; - } - break; - } - } - if (!empty($this->errors)) { - return false; - } - return $framedata; - } - - public function ID3v2FrameIsAllowed($frame_name, $source_data_array) { - static $PreviousFrames = array(); - - if ($frame_name === null) { - // if the writing functions are called multiple times, the static array needs to be - // cleared - this can be done by calling $this->ID3v2FrameIsAllowed(null, '') - $PreviousFrames = array(); - return true; - } - - if ($this->majorversion == 4) { - switch ($frame_name) { - case 'UFID': - case 'AENC': - case 'ENCR': - case 'GRID': - if (!isset($source_data_array['ownerid'])) { - $this->errors[] = '[ownerid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; - } - break; - - case 'TXXX': - case 'WXXX': - case 'RVA2': - case 'EQU2': - case 'APIC': - case 'GEOB': - if (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['description']; - } - break; - - case 'USER': - if (!isset($source_data_array['language'])) { - $this->errors[] = '[language] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['language']; - } - break; - - case 'USLT': - case 'SYLT': - case 'COMM': - if (!isset($source_data_array['language'])) { - $this->errors[] = '[language] not specified for '.$frame_name; - } elseif (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; - } - break; - - case 'POPM': - if (!isset($source_data_array['email'])) { - $this->errors[] = '[email] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['email']; - } - break; - - case 'IPLS': - case 'MCDI': - case 'ETCO': - case 'MLLT': - case 'SYTC': - case 'RVRB': - case 'PCNT': - case 'RBUF': - case 'POSS': - case 'OWNE': - case 'SEEK': - case 'ASPI': - case 'RGAD': - if (in_array($frame_name, $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed'; - } else { - $PreviousFrames[] = $frame_name; - } - break; - - case 'LINK': - // this isn't implemented quite right (yet) - it should check the target frame data for compliance - // but right now it just allows one linked frame of each type, to be safe. - if (!isset($source_data_array['frameid'])) { - $this->errors[] = '[frameid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; - } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { - // no links to singleton tags - $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type - $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type - } - break; - - case 'COMR': - // There may be more than one 'commercial frame' in a tag, but no two may be identical - // Checking isn't implemented at all (yet) - just assumes that it's OK. - break; - - case 'PRIV': - case 'SIGN': - if (!isset($source_data_array['ownerid'])) { - $this->errors[] = '[ownerid] not specified for '.$frame_name; - } elseif (!isset($source_data_array['data'])) { - $this->errors[] = '[data] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; - } - break; - - default: - if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { - $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; - } - break; - } - - } elseif ($this->majorversion == 3) { - - switch ($frame_name) { - case 'UFID': - case 'AENC': - case 'ENCR': - case 'GRID': - if (!isset($source_data_array['ownerid'])) { - $this->errors[] = '[ownerid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; - } - break; - - case 'TXXX': - case 'WXXX': - case 'APIC': - case 'GEOB': - if (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['description']; - } - break; - - case 'USER': - if (!isset($source_data_array['language'])) { - $this->errors[] = '[language] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['language']; - } - break; - - case 'USLT': - case 'SYLT': - case 'COMM': - if (!isset($source_data_array['language'])) { - $this->errors[] = '[language] not specified for '.$frame_name; - } elseif (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; - } - break; - - case 'POPM': - if (!isset($source_data_array['email'])) { - $this->errors[] = '[email] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['email']; - } - break; - - case 'IPLS': - case 'MCDI': - case 'ETCO': - case 'MLLT': - case 'SYTC': - case 'RVAD': - case 'EQUA': - case 'RVRB': - case 'PCNT': - case 'RBUF': - case 'POSS': - case 'OWNE': - case 'RGAD': - if (in_array($frame_name, $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed'; - } else { - $PreviousFrames[] = $frame_name; - } - break; - - case 'LINK': - // this isn't implemented quite right (yet) - it should check the target frame data for compliance - // but right now it just allows one linked frame of each type, to be safe. - if (!isset($source_data_array['frameid'])) { - $this->errors[] = '[frameid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; - } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { - // no links to singleton tags - $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type - $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type - } - break; - - case 'COMR': - // There may be more than one 'commercial frame' in a tag, but no two may be identical - // Checking isn't implemented at all (yet) - just assumes that it's OK. - break; - - case 'PRIV': - if (!isset($source_data_array['ownerid'])) { - $this->errors[] = '[ownerid] not specified for '.$frame_name; - } elseif (!isset($source_data_array['data'])) { - $this->errors[] = '[data] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; - } - break; - - default: - if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { - $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; - } - break; - } - - } elseif ($this->majorversion == 2) { - - switch ($frame_name) { - case 'UFI': - case 'CRM': - case 'CRA': - if (!isset($source_data_array['ownerid'])) { - $this->errors[] = '[ownerid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; - } - break; - - case 'TXX': - case 'WXX': - case 'PIC': - case 'GEO': - if (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['description']; - } - break; - - case 'ULT': - case 'SLT': - case 'COM': - if (!isset($source_data_array['language'])) { - $this->errors[] = '[language] not specified for '.$frame_name; - } elseif (!isset($source_data_array['description'])) { - $this->errors[] = '[description] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; - } - break; - - case 'POP': - if (!isset($source_data_array['email'])) { - $this->errors[] = '[email] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['email']; - } - break; - - case 'IPL': - case 'MCI': - case 'ETC': - case 'MLL': - case 'STC': - case 'RVA': - case 'EQU': - case 'REV': - case 'CNT': - case 'BUF': - if (in_array($frame_name, $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed'; - } else { - $PreviousFrames[] = $frame_name; - } - break; - - case 'LNK': - // this isn't implemented quite right (yet) - it should check the target frame data for compliance - // but right now it just allows one linked frame of each type, to be safe. - if (!isset($source_data_array['frameid'])) { - $this->errors[] = '[frameid] not specified for '.$frame_name; - } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { - $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; - } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { - // no links to singleton tags - $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; - } else { - $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type - $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type - } - break; - - default: - if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { - $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; - } - break; - } - } - - if (!empty($this->errors)) { - return false; - } - return true; - } - - public function GenerateID3v2Tag($noerrorsonly=true) { - $this->ID3v2FrameIsAllowed(null, ''); // clear static array in case this isn't the first call to $this->GenerateID3v2Tag() - - $tagstring = ''; - if (is_array($this->tag_data)) { - foreach ($this->tag_data as $frame_name => $frame_rawinputdata) { - foreach ($frame_rawinputdata as $irrelevantindex => $source_data_array) { - if (getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { - unset($frame_length); - unset($frame_flags); - $frame_data = false; - if ($this->ID3v2FrameIsAllowed($frame_name, $source_data_array)) { - if ($frame_data = $this->GenerateID3v2FrameData($frame_name, $source_data_array)) { - $FrameUnsynchronisation = false; - if ($this->majorversion >= 4) { - // frame-level unsynchronisation - $unsynchdata = $frame_data; - if ($this->id3v2_use_unsynchronisation) { - $unsynchdata = $this->Unsynchronise($frame_data); - } - if (strlen($unsynchdata) != strlen($frame_data)) { - // unsynchronisation needed - $FrameUnsynchronisation = true; - $frame_data = $unsynchdata; - if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) { - // only set to true if ALL frames are unsynchronised - } else { - $TagUnsynchronisation = true; - } - } else { - if (isset($TagUnsynchronisation)) { - $TagUnsynchronisation = false; - } - } - unset($unsynchdata); - - $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, true); - } else { - $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, false); - } - $frame_flags = $this->GenerateID3v2FrameFlags($this->ID3v2FrameFlagsLookupTagAlter($frame_name), $this->ID3v2FrameFlagsLookupFileAlter($frame_name), false, false, false, false, $FrameUnsynchronisation, false); - } - } else { - $this->errors[] = 'Frame "'.$frame_name.'" is NOT allowed'; - } - if ($frame_data === false) { - $this->errors[] = '$this->GenerateID3v2FrameData() failed for "'.$frame_name.'"'; - if ($noerrorsonly) { - return false; - } else { - unset($frame_name); - } - } - } else { - // ignore any invalid frame names, including 'title', 'header', etc - $this->warnings[] = 'Ignoring invalid ID3v2 frame type: "'.$frame_name.'"'; - unset($frame_name); - unset($frame_length); - unset($frame_flags); - unset($frame_data); - } - if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) { - $tagstring .= $frame_name.$frame_length.$frame_flags.$frame_data; - } - } - } - - if (!isset($TagUnsynchronisation)) { - $TagUnsynchronisation = false; - } - if (($this->majorversion <= 3) && $this->id3v2_use_unsynchronisation) { - // tag-level unsynchronisation - $unsynchdata = $this->Unsynchronise($tagstring); - if (strlen($unsynchdata) != strlen($tagstring)) { - // unsynchronisation needed - $TagUnsynchronisation = true; - $tagstring = $unsynchdata; - } - } - - while ($this->paddedlength < (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion))) { - $this->paddedlength += 1024; - } - - $footer = false; // ID3v2 footers not yet supported in getID3() - if (!$footer && ($this->paddedlength > (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)))) { - // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength - // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag." - if (($this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)) > 0) { - $tagstring .= str_repeat("\x00", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)); - } - } - if ($this->id3v2_use_unsynchronisation && (substr($tagstring, strlen($tagstring) - 1, 1) == "\xFF")) { - // special unsynchronisation case: - // if last byte == $FF then appended a $00 - $TagUnsynchronisation = true; - $tagstring .= "\x00"; - } - - $tagheader = 'ID3'; - $tagheader .= chr($this->majorversion); - $tagheader .= chr($this->minorversion); - $tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation'=>$TagUnsynchronisation)); - $tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true); - - return $tagheader.$tagstring; - } - $this->errors[] = 'tag_data is not an array in GenerateID3v2Tag()'; - return false; - } - - public function ID3v2IsValidPriceString($pricestring) { - if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') { - return false; - } elseif (!$this->IsANumber(substr($pricestring, 3), true)) { - return false; - } - return true; - } - - public function ID3v2FrameFlagsLookupTagAlter($framename) { - // unfinished - switch ($framename) { - case 'RGAD': - $allow = true; - default: - $allow = false; - break; - } - return $allow; - } - - public function ID3v2FrameFlagsLookupFileAlter($framename) { - // unfinished - switch ($framename) { - case 'RGAD': - return false; - break; - - default: - return false; - break; - } - } - - public function ID3v2IsValidETCOevent($eventid) { - if (($eventid < 0) || ($eventid > 0xFF)) { - // outside range of 1 byte - return false; - } elseif (($eventid >= 0xF0) && ($eventid <= 0xFC)) { - // reserved for future use - return false; - } elseif (($eventid >= 0x17) && ($eventid <= 0xDF)) { - // reserved for future use - return false; - } elseif (($eventid >= 0x0E) && ($eventid <= 0x16) && ($this->majorversion == 2)) { - // not defined in ID3v2.2 - return false; - } elseif (($eventid >= 0x15) && ($eventid <= 0x16) && ($this->majorversion == 3)) { - // not defined in ID3v2.3 - return false; - } - return true; - } - - public function ID3v2IsValidSYLTtype($contenttype) { - if (($contenttype >= 0) && ($contenttype <= 8) && ($this->majorversion == 4)) { - return true; - } elseif (($contenttype >= 0) && ($contenttype <= 6) && ($this->majorversion == 3)) { - return true; - } - return false; - } - - public function ID3v2IsValidRVA2channeltype($channeltype) { - if (($channeltype >= 0) && ($channeltype <= 8) && ($this->majorversion == 4)) { - return true; - } - return false; - } - - public function ID3v2IsValidAPICpicturetype($picturetype) { - if (($picturetype >= 0) && ($picturetype <= 0x14) && ($this->majorversion >= 2) && ($this->majorversion <= 4)) { - return true; - } - return false; - } - - public function ID3v2IsValidAPICimageformat($imageformat) { - if ($imageformat == '-->') { - return true; - } elseif ($this->majorversion == 2) { - if ((strlen($imageformat) == 3) && ($imageformat == strtoupper($imageformat))) { - return true; - } - } elseif (($this->majorversion == 3) || ($this->majorversion == 4)) { - if ($this->IsValidMIMEstring($imageformat)) { - return true; - } - } - return false; - } - - public function ID3v2IsValidCOMRreceivedAs($receivedas) { - if (($this->majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) { - return true; - } - return false; - } - - public function ID3v2IsValidRGADname($RGADname) { - if (($RGADname >= 0) && ($RGADname <= 2)) { - return true; - } - return false; - } - - public function ID3v2IsValidRGADoriginator($RGADoriginator) { - if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) { - return true; - } - return false; - } - - public function ID3v2IsValidTextEncoding($textencodingbyte) { - static $ID3v2IsValidTextEncoding_cache = array( - 2 => array(true, true), - 3 => array(true, true), - 4 => array(true, true, true, true)); - return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]); - } - - public function Unsynchronise($data) { - // Whenever a false synchronisation is found within the tag, one zeroed - // byte is inserted after the first false synchronisation byte. The - // format of a correct sync that should be altered by ID3 encoders is as - // follows: - // %11111111 111xxxxx - // And should be replaced with: - // %11111111 00000000 111xxxxx - // This has the side effect that all $FF 00 combinations have to be - // altered, so they won't be affected by the decoding process. Therefore - // all the $FF 00 combinations have to be replaced with the $FF 00 00 - // combination during the unsynchronisation. - - $data = str_replace("\xFF\x00", "\xFF\x00\x00", $data); - $unsyncheddata = ''; - $datalength = strlen($data); - for ($i = 0; $i < $datalength; $i++) { - $thischar = $data{$i}; - $unsyncheddata .= $thischar; - if ($thischar == "\xFF") { - $nextchar = ord($data{$i + 1}); - if (($nextchar & 0xE0) == 0xE0) { - // previous byte = 11111111, this byte = 111????? - $unsyncheddata .= "\x00"; - } - } - } - return $unsyncheddata; - } - - public function is_hash($var) { - // written by dev-nullØchristophe*vg - // taken from http://www.php.net/manual/en/function.array-merge-recursive.php - if (is_array($var)) { - $keys = array_keys($var); - $all_num = true; - for ($i = 0; $i < count($keys); $i++) { - if (is_string($keys[$i])) { - return true; - } - } - } - return false; - } - - public function array_join_merge($arr1, $arr2) { - // written by dev-nullØchristophe*vg - // taken from http://www.php.net/manual/en/function.array-merge-recursive.php - if (is_array($arr1) && is_array($arr2)) { - // the same -> merge - $new_array = array(); - - if ($this->is_hash($arr1) && $this->is_hash($arr2)) { - // hashes -> merge based on keys - $keys = array_merge(array_keys($arr1), array_keys($arr2)); - foreach ($keys as $key) { - $new_array[$key] = $this->array_join_merge((isset($arr1[$key]) ? $arr1[$key] : ''), (isset($arr2[$key]) ? $arr2[$key] : '')); - } - } else { - // two real arrays -> merge - $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1, $arr2)))); - } - return $new_array; - } else { - // not the same ... take new one if defined, else the old one stays - return $arr2 ? $arr2 : $arr1; - } - } - - public function IsValidMIMEstring($mimestring) { - if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) { - return true; - } - return false; - } - - public function IsWithinBitRange($number, $maxbits, $signed=false) { - if ($signed) { - if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) { - return true; - } - } else { - if (($number >= 0) && ($number <= pow(2, $maxbits))) { - return true; - } - } - return false; - } - - public function safe_parse_url($url) { - $parts = @parse_url($url); - $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : ''); - $parts['host'] = (isset($parts['host']) ? $parts['host'] : ''); - $parts['user'] = (isset($parts['user']) ? $parts['user'] : ''); - $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : ''); - $parts['path'] = (isset($parts['path']) ? $parts['path'] : ''); - $parts['query'] = (isset($parts['query']) ? $parts['query'] : ''); - return $parts; - } - - public function IsValidURL($url, $allowUserPass=false) { - if ($url == '') { - return false; - } - if ($allowUserPass !== true) { - if (strstr($url, '@')) { - // in the format http://user:pass@example.com or http://user@example.com - // but could easily be somebody incorrectly entering an email address in place of a URL - return false; - } - } - if ($parts = $this->safe_parse_url($url)) { - if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) { - return false; - } elseif (!preg_match('#^[[:alnum:]]([-.]?[0-9a-z])*\\.[a-z]{2,3}$#i', $parts['host'], $regs) && !preg_match('#^[0-9]{1,3}(\\.[0-9]{1,3}){3}$#', $parts['host'])) { - return false; - } elseif (!preg_match('#^([[:alnum:]-]|[\\_])*$#i', $parts['user'], $regs)) { - return false; - } elseif (!preg_match('#^([[:alnum:]-]|[\\_])*$#i', $parts['pass'], $regs)) { - return false; - } elseif (!preg_match('#^[[:alnum:]/_\\.@~-]*$#i', $parts['path'], $regs)) { - return false; - } elseif (!empty($parts['query']) && !preg_match('#^[[:alnum:]?&=+:;_()%\\#/,\\.-]*$#i', $parts['query'], $regs)) { - return false; - } else { - return true; - } - } - return false; - } - - public static function ID3v2ShortFrameNameLookup($majorversion, $long_description) { - $long_description = str_replace(' ', '_', strtolower(trim($long_description))); - static $ID3v2ShortFrameNameLookup = array(); - if (empty($ID3v2ShortFrameNameLookup)) { - - // The following are unique to ID3v2.2 - $ID3v2ShortFrameNameLookup[2]['comment'] = 'COM'; - $ID3v2ShortFrameNameLookup[2]['album'] = 'TAL'; - $ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP'; - $ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM'; - $ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO'; - $ID3v2ShortFrameNameLookup[2]['itunescompilation'] = 'TCP'; - $ID3v2ShortFrameNameLookup[2]['copyright'] = 'TCR'; - $ID3v2ShortFrameNameLookup[2]['encoded_by'] = 'TEN'; - $ID3v2ShortFrameNameLookup[2]['language'] = 'TLA'; - $ID3v2ShortFrameNameLookup[2]['length'] = 'TLE'; - $ID3v2ShortFrameNameLookup[2]['original_artist'] = 'TOA'; - $ID3v2ShortFrameNameLookup[2]['original_filename'] = 'TOF'; - $ID3v2ShortFrameNameLookup[2]['original_lyricist'] = 'TOL'; - $ID3v2ShortFrameNameLookup[2]['original_album_title'] = 'TOT'; - $ID3v2ShortFrameNameLookup[2]['artist'] = 'TP1'; - $ID3v2ShortFrameNameLookup[2]['band'] = 'TP2'; - $ID3v2ShortFrameNameLookup[2]['conductor'] = 'TP3'; - $ID3v2ShortFrameNameLookup[2]['remixer'] = 'TP4'; - $ID3v2ShortFrameNameLookup[2]['publisher'] = 'TPB'; - $ID3v2ShortFrameNameLookup[2]['isrc'] = 'TRC'; - $ID3v2ShortFrameNameLookup[2]['tracknumber'] = 'TRK'; - $ID3v2ShortFrameNameLookup[2]['size'] = 'TSI'; - $ID3v2ShortFrameNameLookup[2]['encoder_settings'] = 'TSS'; - $ID3v2ShortFrameNameLookup[2]['description'] = 'TT1'; - $ID3v2ShortFrameNameLookup[2]['title'] = 'TT2'; - $ID3v2ShortFrameNameLookup[2]['subtitle'] = 'TT3'; - $ID3v2ShortFrameNameLookup[2]['lyricist'] = 'TXT'; - $ID3v2ShortFrameNameLookup[2]['user_text'] = 'TXX'; - $ID3v2ShortFrameNameLookup[2]['year'] = 'TYE'; - $ID3v2ShortFrameNameLookup[2]['unique_file_identifier'] = 'UFI'; - $ID3v2ShortFrameNameLookup[2]['unsynchronised_lyrics'] = 'ULT'; - $ID3v2ShortFrameNameLookup[2]['url_file'] = 'WAF'; - $ID3v2ShortFrameNameLookup[2]['url_artist'] = 'WAR'; - $ID3v2ShortFrameNameLookup[2]['url_source'] = 'WAS'; - $ID3v2ShortFrameNameLookup[2]['copyright_information'] = 'WCP'; - $ID3v2ShortFrameNameLookup[2]['url_publisher'] = 'WPB'; - $ID3v2ShortFrameNameLookup[2]['url_user'] = 'WXX'; - - // The following are common to ID3v2.3 and ID3v2.4 - $ID3v2ShortFrameNameLookup[3]['audio_encryption'] = 'AENC'; - $ID3v2ShortFrameNameLookup[3]['attached_picture'] = 'APIC'; - $ID3v2ShortFrameNameLookup[3]['comment'] = 'COMM'; - $ID3v2ShortFrameNameLookup[3]['commercial'] = 'COMR'; - $ID3v2ShortFrameNameLookup[3]['encryption_method_registration'] = 'ENCR'; - $ID3v2ShortFrameNameLookup[3]['event_timing_codes'] = 'ETCO'; - $ID3v2ShortFrameNameLookup[3]['general_encapsulated_object'] = 'GEOB'; - $ID3v2ShortFrameNameLookup[3]['group_identification_registration'] = 'GRID'; - $ID3v2ShortFrameNameLookup[3]['linked_information'] = 'LINK'; - $ID3v2ShortFrameNameLookup[3]['music_cd_identifier'] = 'MCDI'; - $ID3v2ShortFrameNameLookup[3]['mpeg_location_lookup_table'] = 'MLLT'; - $ID3v2ShortFrameNameLookup[3]['ownership'] = 'OWNE'; - $ID3v2ShortFrameNameLookup[3]['play_counter'] = 'PCNT'; - $ID3v2ShortFrameNameLookup[3]['popularimeter'] = 'POPM'; - $ID3v2ShortFrameNameLookup[3]['position_synchronisation'] = 'POSS'; - $ID3v2ShortFrameNameLookup[3]['private'] = 'PRIV'; - $ID3v2ShortFrameNameLookup[3]['recommended_buffer_size'] = 'RBUF'; - $ID3v2ShortFrameNameLookup[3]['reverb'] = 'RVRB'; - $ID3v2ShortFrameNameLookup[3]['synchronised_lyrics'] = 'SYLT'; - $ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC'; - $ID3v2ShortFrameNameLookup[3]['album'] = 'TALB'; - $ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM'; - $ID3v2ShortFrameNameLookup[3]['itunescompilation'] = 'TCMP'; - $ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM'; - $ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON'; - $ID3v2ShortFrameNameLookup[3]['copyright'] = 'TCOP'; - $ID3v2ShortFrameNameLookup[3]['playlist_delay'] = 'TDLY'; - $ID3v2ShortFrameNameLookup[3]['encoded_by'] = 'TENC'; - $ID3v2ShortFrameNameLookup[3]['lyricist'] = 'TEXT'; - $ID3v2ShortFrameNameLookup[3]['file_type'] = 'TFLT'; - $ID3v2ShortFrameNameLookup[3]['content_group_description'] = 'TIT1'; - $ID3v2ShortFrameNameLookup[3]['title'] = 'TIT2'; - $ID3v2ShortFrameNameLookup[3]['subtitle'] = 'TIT3'; - $ID3v2ShortFrameNameLookup[3]['initial_key'] = 'TKEY'; - $ID3v2ShortFrameNameLookup[3]['language'] = 'TLAN'; - $ID3v2ShortFrameNameLookup[3]['length'] = 'TLEN'; - $ID3v2ShortFrameNameLookup[3]['media_type'] = 'TMED'; - $ID3v2ShortFrameNameLookup[3]['original_album_title'] = 'TOAL'; - $ID3v2ShortFrameNameLookup[3]['original_filename'] = 'TOFN'; - $ID3v2ShortFrameNameLookup[3]['original_lyricist'] = 'TOLY'; - $ID3v2ShortFrameNameLookup[3]['original_artist'] = 'TOPE'; - $ID3v2ShortFrameNameLookup[3]['file_owner'] = 'TOWN'; - $ID3v2ShortFrameNameLookup[3]['artist'] = 'TPE1'; - $ID3v2ShortFrameNameLookup[3]['band'] = 'TPE2'; - $ID3v2ShortFrameNameLookup[3]['conductor'] = 'TPE3'; - $ID3v2ShortFrameNameLookup[3]['remixer'] = 'TPE4'; - $ID3v2ShortFrameNameLookup[3]['part_of_a_set'] = 'TPOS'; - $ID3v2ShortFrameNameLookup[3]['publisher'] = 'TPUB'; - $ID3v2ShortFrameNameLookup[3]['tracknumber'] = 'TRCK'; - $ID3v2ShortFrameNameLookup[3]['internet_radio_station_name'] = 'TRSN'; - $ID3v2ShortFrameNameLookup[3]['internet_radio_station_owner'] = 'TRSO'; - $ID3v2ShortFrameNameLookup[3]['isrc'] = 'TSRC'; - $ID3v2ShortFrameNameLookup[3]['encoder_settings'] = 'TSSE'; - $ID3v2ShortFrameNameLookup[3]['user_text'] = 'TXXX'; - $ID3v2ShortFrameNameLookup[3]['unique_file_identifier'] = 'UFID'; - $ID3v2ShortFrameNameLookup[3]['terms_of_use'] = 'USER'; - $ID3v2ShortFrameNameLookup[3]['unsynchronised_lyrics'] = 'USLT'; - $ID3v2ShortFrameNameLookup[3]['commercial'] = 'WCOM'; - $ID3v2ShortFrameNameLookup[3]['copyright_information'] = 'WCOP'; - $ID3v2ShortFrameNameLookup[3]['url_file'] = 'WOAF'; - $ID3v2ShortFrameNameLookup[3]['url_artist'] = 'WOAR'; - $ID3v2ShortFrameNameLookup[3]['url_source'] = 'WOAS'; - $ID3v2ShortFrameNameLookup[3]['url_station'] = 'WORS'; - $ID3v2ShortFrameNameLookup[3]['payment'] = 'WPAY'; - $ID3v2ShortFrameNameLookup[3]['url_publisher'] = 'WPUB'; - $ID3v2ShortFrameNameLookup[3]['url_user'] = 'WXXX'; - - // The above are common to ID3v2.3 and ID3v2.4 - // so copy them to ID3v2.4 before adding specifics for 2.3 and 2.4 - $ID3v2ShortFrameNameLookup[4] = $ID3v2ShortFrameNameLookup[3]; - - // The following are unique to ID3v2.3 - $ID3v2ShortFrameNameLookup[3]['equalisation'] = 'EQUA'; - $ID3v2ShortFrameNameLookup[3]['involved_people_list'] = 'IPLS'; - $ID3v2ShortFrameNameLookup[3]['relative_volume_adjustment'] = 'RVAD'; - $ID3v2ShortFrameNameLookup[3]['date'] = 'TDAT'; - $ID3v2ShortFrameNameLookup[3]['time'] = 'TIME'; - $ID3v2ShortFrameNameLookup[3]['original_release_year'] = 'TORY'; - $ID3v2ShortFrameNameLookup[3]['recording_dates'] = 'TRDA'; - $ID3v2ShortFrameNameLookup[3]['size'] = 'TSIZ'; - $ID3v2ShortFrameNameLookup[3]['year'] = 'TYER'; - - - // The following are unique to ID3v2.4 - $ID3v2ShortFrameNameLookup[4]['audio_seek_point_index'] = 'ASPI'; - $ID3v2ShortFrameNameLookup[4]['equalisation'] = 'EQU2'; - $ID3v2ShortFrameNameLookup[4]['relative_volume_adjustment'] = 'RVA2'; - $ID3v2ShortFrameNameLookup[4]['seek'] = 'SEEK'; - $ID3v2ShortFrameNameLookup[4]['signature'] = 'SIGN'; - $ID3v2ShortFrameNameLookup[4]['encoding_time'] = 'TDEN'; - $ID3v2ShortFrameNameLookup[4]['original_release_time'] = 'TDOR'; - $ID3v2ShortFrameNameLookup[4]['recording_time'] = 'TDRC'; - $ID3v2ShortFrameNameLookup[4]['release_time'] = 'TDRL'; - $ID3v2ShortFrameNameLookup[4]['tagging_time'] = 'TDTG'; - $ID3v2ShortFrameNameLookup[4]['involved_people_list'] = 'TIPL'; - $ID3v2ShortFrameNameLookup[4]['musician_credits_list'] = 'TMCL'; - $ID3v2ShortFrameNameLookup[4]['mood'] = 'TMOO'; - $ID3v2ShortFrameNameLookup[4]['produced_notice'] = 'TPRO'; - $ID3v2ShortFrameNameLookup[4]['album_sort_order'] = 'TSOA'; - $ID3v2ShortFrameNameLookup[4]['performer_sort_order'] = 'TSOP'; - $ID3v2ShortFrameNameLookup[4]['title_sort_order'] = 'TSOT'; - $ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST'; - } - return (isset($ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)]) ? $ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)] : ''); - - } - -} - + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// write.id3v2.php // +// module for writing ID3v2 tags // +// dependencies: module.tag.id3v2.php // +// /// +///////////////////////////////////////////////////////////////// + +getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'module.tag.id3v2.php', __FILE__, true); + +class getid3_write_id3v2 +{ + public $filename; + public $tag_data; + public $fread_buffer_size = 32768; // read buffer size in bytes + public $paddedlength = 4096; // minimum length of ID3v2 tag in bytes + public $majorversion = 3; // ID3v2 major version (2, 3 (recommended), 4) + public $minorversion = 0; // ID3v2 minor version - always 0 + public $merge_existing_data = false; // if true, merge new data with existing tags; if false, delete old tag data and only write new tags + public $id3v2_default_encodingid = 0; // default text encoding (ISO-8859-1) if not explicitly passed + public $id3v2_use_unsynchronisation = false; // the specs say it should be TRUE, but most other ID3v2-aware programs are broken if unsynchronization is used, so by default don't use it. + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_id3v2() { + return true; + } + + public function WriteID3v2() { + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + + if (!empty($this->filename) && (is_writeable($this->filename) || (!file_exists($this->filename) && is_writeable(dirname($this->filename))))) { + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { + $this->errors[] = 'Unable to write ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + fclose($fp_source); + return false; + } + if ($this->merge_existing_data) { + // merge with existing data + if (!empty($OldThisFileInfo['id3v2'])) { + $this->tag_data = $this->array_join_merge($OldThisFileInfo['id3v2'], $this->tag_data); + } + } + $this->paddedlength = (isset($OldThisFileInfo['id3v2']['headerlength']) ? max($OldThisFileInfo['id3v2']['headerlength'], $this->paddedlength) : $this->paddedlength); + + if ($NewID3v2Tag = $this->GenerateID3v2Tag()) { + + if (file_exists($this->filename) && is_writeable($this->filename) && isset($OldThisFileInfo['id3v2']['headerlength']) && ($OldThisFileInfo['id3v2']['headerlength'] == strlen($NewID3v2Tag))) { + + // best and fastest method - insert-overwrite existing tag (padded to length of old tag if neccesary) + if (file_exists($this->filename)) { + + if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'r+b'))) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; + } + + } else { + + if (is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'wb'))) { + rewind($fp); + fwrite($fp, $NewID3v2Tag, strlen($NewID3v2Tag)); + fclose($fp); + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; + } + + } + + } else { + + if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { + if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { + if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { + + fwrite($fp_temp, $NewID3v2Tag, strlen($NewID3v2Tag)); + + rewind($fp_source); + if (!empty($OldThisFileInfo['avdataoffset'])) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + + while ($buffer = fread($fp_source, $this->fread_buffer_size)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + + fclose($fp_temp); + fclose($fp_source); + copy($tempfilename, $this->filename); + unlink($tempfilename); + return true; + + } else { + $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; + } + fclose($fp_source); + + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; + } + } + return false; + + } + + } else { + + $this->errors[] = '$this->GenerateID3v2Tag() failed'; + + } + + if (!empty($this->errors)) { + return false; + } + return true; + } else { + $this->errors[] = 'WriteID3v2() failed: !is_writeable('.$this->filename.')'; + } + return false; + } + + public function RemoveID3v2() { + // File MUST be writeable - CHMOD(646) at least. It's best if the + // directory is also writeable, because that method is both faster and less susceptible to errors. + if (is_writeable(dirname($this->filename))) { + + // preferred method - only one copying operation, minimal chance of corrupting + // original file if script is interrupted, but required directory to be writeable + if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { + $this->errors[] = 'Unable to remove ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + fclose($fp_source); + return false; + } + rewind($fp_source); + if ($OldThisFileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + if (is_writable($this->filename) && is_file($this->filename) && ($fp_temp = fopen($this->filename.'getid3tmp', 'w+b'))) { + while ($buffer = fread($fp_source, $this->fread_buffer_size)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'getid3tmp", "w+b")'; + } + fclose($fp_source); + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; + } + if (file_exists($this->filename)) { + unlink($this->filename); + } + rename($this->filename.'getid3tmp', $this->filename); + + } elseif (is_writable($this->filename)) { + + // less desirable alternate method - double-copies the file, overwrites original file + // and could corrupt source file if the script is interrupted or an error occurs. + if (is_readable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'rb'))) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (!getid3_lib::intValueSupported($OldThisFileInfo['filesize'])) { + $this->errors[] = 'Unable to remove ID3v2 because file is larger than '.round(PHP_INT_MAX / 1073741824).'GB'; + fclose($fp_source); + return false; + } + rewind($fp_source); + if ($OldThisFileInfo['avdataoffset'] !== false) { + fseek($fp_source, $OldThisFileInfo['avdataoffset'], SEEK_SET); + } + if ($fp_temp = tmpfile()) { + while ($buffer = fread($fp_source, $this->fread_buffer_size)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_source); + if (is_writable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'wb'))) { + rewind($fp_temp); + while ($buffer = fread($fp_temp, $this->fread_buffer_size)) { + fwrite($fp_source, $buffer, strlen($buffer)); + } + fseek($fp_temp, -128, SEEK_END); + fclose($fp_source); + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "wb")'; + } + fclose($fp_temp); + } else { + $this->errors[] = 'Could not create tmpfile()'; + } + } else { + $this->errors[] = 'Could not fopen("'.$this->filename.'", "rb")'; + } + + } else { + + $this->errors[] = 'Directory and file both not writeable'; + + } + + if (!empty($this->errors)) { + return false; + } + return true; + } + + + public function GenerateID3v2TagFlags($flags) { + switch ($this->majorversion) { + case 4: + // %abcd0000 + $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation + $flag .= (!empty($flags['extendedheader'] ) ? '1' : '0'); // b - Extended header + $flag .= (!empty($flags['experimental'] ) ? '1' : '0'); // c - Experimental indicator + $flag .= (!empty($flags['footer'] ) ? '1' : '0'); // d - Footer present + $flag .= '0000'; + break; + + case 3: + // %abc00000 + $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation + $flag .= (!empty($flags['extendedheader'] ) ? '1' : '0'); // b - Extended header + $flag .= (!empty($flags['experimental'] ) ? '1' : '0'); // c - Experimental indicator + $flag .= '00000'; + break; + + case 2: + // %ab000000 + $flag = (!empty($flags['unsynchronisation']) ? '1' : '0'); // a - Unsynchronisation + $flag .= (!empty($flags['compression'] ) ? '1' : '0'); // b - Compression + $flag .= '000000'; + break; + + default: + return false; + break; + } + return chr(bindec($flag)); + } + + + public function GenerateID3v2FrameFlags($TagAlter=false, $FileAlter=false, $ReadOnly=false, $Compression=false, $Encryption=false, $GroupingIdentity=false, $Unsynchronisation=false, $DataLengthIndicator=false) { + switch ($this->majorversion) { + case 4: + // %0abc0000 %0h00kmnp + $flag1 = '0'; + $flag1 .= $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) + $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) + $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) + $flag1 .= '0000'; + + $flag2 = '0'; + $flag2 .= $GroupingIdentity ? '1' : '0'; // h - Grouping identity (true == contains group information) + $flag2 .= '00'; + $flag2 .= $Compression ? '1' : '0'; // k - Compression (true == compressed) + $flag2 .= $Encryption ? '1' : '0'; // m - Encryption (true == encrypted) + $flag2 .= $Unsynchronisation ? '1' : '0'; // n - Unsynchronisation (true == unsynchronised) + $flag2 .= $DataLengthIndicator ? '1' : '0'; // p - Data length indicator (true == data length indicator added) + break; + + case 3: + // %abc00000 %ijk00000 + $flag1 = $TagAlter ? '1' : '0'; // a - Tag alter preservation (true == discard) + $flag1 .= $FileAlter ? '1' : '0'; // b - File alter preservation (true == discard) + $flag1 .= $ReadOnly ? '1' : '0'; // c - Read only (true == read only) + $flag1 .= '00000'; + + $flag2 = $Compression ? '1' : '0'; // i - Compression (true == compressed) + $flag2 .= $Encryption ? '1' : '0'; // j - Encryption (true == encrypted) + $flag2 .= $GroupingIdentity ? '1' : '0'; // k - Grouping identity (true == contains group information) + $flag2 .= '00000'; + break; + + default: + return false; + break; + + } + return chr(bindec($flag1)).chr(bindec($flag2)); + } + + public function GenerateID3v2FrameData($frame_name, $source_data_array) { + if (!getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { + return false; + } + $framedata = ''; + + if (($this->majorversion < 3) || ($this->majorversion > 4)) { + + $this->errors[] = 'Only ID3v2.3 and ID3v2.4 are supported in GenerateID3v2FrameData()'; + + } else { // $this->majorversion 3 or 4 + + switch ($frame_name) { + case 'UFID': + // 4.1 UFID Unique file identifier + // Owner identifier $00 + // Identifier + if (strlen($source_data_array['data']) > 64) { + $this->errors[] = 'Identifier not allowed to be longer than 64 bytes in '.$frame_name.' (supplied data was '.strlen($source_data_array['data']).' bytes long)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= substr($source_data_array['data'], 0, 64); // max 64 bytes - truncate anything longer + } + break; + + case 'TXXX': + // 4.2.2 TXXX User defined text information frame + // Text encoding $xx + // Description $00 (00) + // Value + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'WXXX': + // 4.3.2 WXXX User defined URL link frame + // Text encoding $xx + // Description $00 (00) + // URL + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!isset($source_data_array['data']) || !$this->IsValidURL($source_data_array['data'], false, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'IPLS': + // 4.4 IPLS Involved people list (ID3v2.3 only) + // Text encoding $xx + // People list strings + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'], $this->majorversion)) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'MCDI': + // 4.4 MCDI Music CD identifier + // CD TOC + $framedata .= $source_data_array['data']; + break; + + case 'ETCO': + // 4.5 ETCO Event timing codes + // Time stamp format $xx + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Followed by a list of key events in the following format: + // Type of event $xx + // Time stamp $xx (xx ...) + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + foreach ($source_data_array as $key => $val) { + if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { + $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['timestamp'] > 0) && ($previousETCOtimestamp >= $val['timestamp'])) { + // The 'Time stamp' is set to zero if directly at the beginning of the sound + // or after the previous event. All events MUST be sorted in chronological order. + $this->errors[] = 'Out-of-order timestamp in '.$frame_name.' ('.$val['timestamp'].') for Event Type ('.$val['typeid'].')'; + } else { + $framedata .= chr($val['typeid']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + + case 'MLLT': + // 4.6 MLLT MPEG location lookup table + // MPEG frames between reference $xx xx + // Bytes between reference $xx xx xx + // Milliseconds between reference $xx xx xx + // Bits for bytes deviation $xx + // Bits for milliseconds dev. $xx + // Then for every reference the following data is included; + // Deviation in bytes %xxx.... + // Deviation in milliseconds %xxx.... + if (($source_data_array['framesbetweenreferences'] > 0) && ($source_data_array['framesbetweenreferences'] <= 65535)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['framesbetweenreferences'], 2, false); + } else { + $this->errors[] = 'Invalid MPEG Frames Between References in '.$frame_name.' ('.$source_data_array['framesbetweenreferences'].')'; + } + if (($source_data_array['bytesbetweenreferences'] > 0) && ($source_data_array['bytesbetweenreferences'] <= 16777215)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['bytesbetweenreferences'], 3, false); + } else { + $this->errors[] = 'Invalid bytes Between References in '.$frame_name.' ('.$source_data_array['bytesbetweenreferences'].')'; + } + if (($source_data_array['msbetweenreferences'] > 0) && ($source_data_array['msbetweenreferences'] <= 16777215)) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['msbetweenreferences'], 3, false); + } else { + $this->errors[] = 'Invalid Milliseconds Between References in '.$frame_name.' ('.$source_data_array['msbetweenreferences'].')'; + } + if (!$this->IsWithinBitRange($source_data_array['bitsforbytesdeviation'], 8, false)) { + if (($source_data_array['bitsforbytesdeviation'] % 4) == 0) { + $framedata .= chr($source_data_array['bitsforbytesdeviation']); + } else { + $this->errors[] = 'Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; + } + } else { + $this->errors[] = 'Invalid Bits For Bytes Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].')'; + } + if (!$this->IsWithinBitRange($source_data_array['bitsformsdeviation'], 8, false)) { + if (($source_data_array['bitsformsdeviation'] % 4) == 0) { + $framedata .= chr($source_data_array['bitsformsdeviation']); + } else { + $this->errors[] = 'Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsforbytesdeviation'].') must be a multiple of 4.'; + } + } else { + $this->errors[] = 'Invalid Bits For Milliseconds Deviation in '.$frame_name.' ('.$source_data_array['bitsformsdeviation'].')'; + } + foreach ($source_data_array as $key => $val) { + if (($key != 'framesbetweenreferences') && ($key != 'bytesbetweenreferences') && ($key != 'msbetweenreferences') && ($key != 'bitsforbytesdeviation') && ($key != 'bitsformsdeviation') && ($key != 'flags')) { + $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['bytedeviation']), $source_data_array['bitsforbytesdeviation'], '0', STR_PAD_LEFT); + $unwrittenbitstream .= str_pad(getid3_lib::Dec2Bin($val['msdeviation']), $source_data_array['bitsformsdeviation'], '0', STR_PAD_LEFT); + } + } + for ($i = 0; $i < strlen($unwrittenbitstream); $i += 8) { + $highnibble = bindec(substr($unwrittenbitstream, $i, 4)) << 4; + $lownibble = bindec(substr($unwrittenbitstream, $i + 4, 4)); + $framedata .= chr($highnibble & $lownibble); + } + break; + + case 'SYTC': + // 4.7 SYTC Synchronised tempo codes + // Time stamp format $xx + // Tempo data + // Where time stamp format is: + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + if (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + foreach ($source_data_array as $key => $val) { + if (!$this->ID3v2IsValidETCOevent($val['typeid'])) { + $this->errors[] = 'Invalid Event Type byte in '.$frame_name.' ('.$val['typeid'].')'; + } elseif (($key != 'timestampformat') && ($key != 'flags')) { + if (($val['tempo'] < 0) || ($val['tempo'] > 510)) { + $this->errors[] = 'Invalid Tempo (max = 510) in '.$frame_name.' ('.$val['tempo'].') at timestamp ('.$val['timestamp'].')'; + } else { + if ($val['tempo'] > 255) { + $framedata .= chr(255); + $val['tempo'] -= 255; + } + $framedata .= chr($val['tempo']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + } + } + break; + + case 'USLT': + // 4.8 USLT Unsynchronised lyric/text transcription + // Text encoding $xx + // Language $xx xx xx + // Content descriptor $00 (00) + // Lyrics/text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'SYLT': + // 4.9 SYLT Synchronised lyric/text + // Text encoding $xx + // Language $xx xx xx + // Time stamp format $xx + // $01 (32-bit value) MPEG frames from beginning of file + // $02 (32-bit value) milliseconds from beginning of file + // Content type $xx + // Content descriptor $00 (00) + // Terminated text to be synced (typically a syllable) + // Sync identifier (terminator to above string) $00 (00) + // Time stamp $xx (xx ...) + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } elseif (($source_data_array['timestampformat'] > 2) || ($source_data_array['timestampformat'] < 1)) { + $this->errors[] = 'Invalid Time Stamp Format byte in '.$frame_name.' ('.$source_data_array['timestampformat'].')'; + } elseif (!$this->ID3v2IsValidSYLTtype($source_data_array['contenttypeid'])) { + $this->errors[] = 'Invalid Content Type byte in '.$frame_name.' ('.$source_data_array['contenttypeid'].')'; + } elseif (!is_array($source_data_array['data'])) { + $this->errors[] = 'Invalid Lyric/Timestamp data in '.$frame_name.' (must be an array)'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= chr($source_data_array['timestampformat']); + $framedata .= chr($source_data_array['contenttypeid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + ksort($source_data_array['data']); + foreach ($source_data_array['data'] as $key => $val) { + $framedata .= $val['data'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= getid3_lib::BigEndian2String($val['timestamp'], 4, false); + } + } + break; + + case 'COMM': + // 4.10 COMM Comments + // Text encoding $xx + // Language $xx xx xx + // Short content descrip. $00 (00) + // The actual text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'RVA2': + // 4.11 RVA2 Relative volume adjustment (2) (ID3v2.4+ only) + // Identification $00 + // The 'identification' string is used to identify the situation and/or + // device where this adjustment should apply. The following is then + // repeated for every channel: + // Type of channel $xx + // Volume adjustment $xx xx + // Bits representing peak $xx + // Peak volume $xx (xx ...) + $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; + foreach ($source_data_array as $key => $val) { + if ($key != 'description') { + $framedata .= chr($val['channeltypeid']); + $framedata .= getid3_lib::BigEndian2String($val['volumeadjust'], 2, false, true); // signed 16-bit + if (!$this->IsWithinBitRange($source_data_array['bitspeakvolume'], 8, false)) { + $framedata .= chr($val['bitspeakvolume']); + if ($val['bitspeakvolume'] > 0) { + $framedata .= getid3_lib::BigEndian2String($val['peakvolume'], ceil($val['bitspeakvolume'] / 8), false, false); + } + } else { + $this->errors[] = 'Invalid Bits Representing Peak Volume in '.$frame_name.' ('.$val['bitspeakvolume'].') (range = 0 to 255)'; + } + } + } + break; + + case 'RVAD': + // 4.12 RVAD Relative volume adjustment (ID3v2.3 only) + // Increment/decrement %00fedcba + // Bits used for volume descr. $xx + // Relative volume change, right $xx xx (xx ...) // a + // Relative volume change, left $xx xx (xx ...) // b + // Peak volume right $xx xx (xx ...) + // Peak volume left $xx xx (xx ...) + // Relative volume change, right back $xx xx (xx ...) // c + // Relative volume change, left back $xx xx (xx ...) // d + // Peak volume right back $xx xx (xx ...) + // Peak volume left back $xx xx (xx ...) + // Relative volume change, center $xx xx (xx ...) // e + // Peak volume center $xx xx (xx ...) + // Relative volume change, bass $xx xx (xx ...) // f + // Peak volume bass $xx xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { + $this->errors[] = 'Invalid Bits For Volume Description byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; + } else { + $incdecflag .= '00'; + $incdecflag .= $source_data_array['incdec']['right'] ? '1' : '0'; // a - Relative volume change, right + $incdecflag .= $source_data_array['incdec']['left'] ? '1' : '0'; // b - Relative volume change, left + $incdecflag .= $source_data_array['incdec']['rightrear'] ? '1' : '0'; // c - Relative volume change, right back + $incdecflag .= $source_data_array['incdec']['leftrear'] ? '1' : '0'; // d - Relative volume change, left back + $incdecflag .= $source_data_array['incdec']['center'] ? '1' : '0'; // e - Relative volume change, center + $incdecflag .= $source_data_array['incdec']['bass'] ? '1' : '0'; // f - Relative volume change, bass + $framedata .= chr(bindec($incdecflag)); + $framedata .= chr($source_data_array['bitsvolume']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['right'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['left'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['right'], ceil($source_data_array['bitsvolume'] / 8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['left'], ceil($source_data_array['bitsvolume'] / 8), false); + if ($source_data_array['volumechange']['rightrear'] || $source_data_array['volumechange']['leftrear'] || + $source_data_array['peakvolume']['rightrear'] || $source_data_array['peakvolume']['leftrear'] || + $source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || + $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['rightrear'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['leftrear'], ceil($source_data_array['bitsvolume']/8), false); + } + if ($source_data_array['volumechange']['center'] || $source_data_array['peakvolume']['center'] || + $source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['center'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['center'], ceil($source_data_array['bitsvolume']/8), false); + } + if ($source_data_array['volumechange']['bass'] || $source_data_array['peakvolume']['bass']) { + $framedata .= getid3_lib::BigEndian2String($source_data_array['volumechange']['bass'], ceil($source_data_array['bitsvolume']/8), false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['peakvolume']['bass'], ceil($source_data_array['bitsvolume']/8), false); + } + } + break; + + case 'EQU2': + // 4.12 EQU2 Equalisation (2) (ID3v2.4+ only) + // Interpolation method $xx + // $00 Band + // $01 Linear + // Identification $00 + // The following is then repeated for every adjustment point + // Frequency $xx xx + // Volume adjustment $xx xx + if (($source_data_array['interpolationmethod'] < 0) || ($source_data_array['interpolationmethod'] > 1)) { + $this->errors[] = 'Invalid Interpolation Method byte in '.$frame_name.' ('.$source_data_array['interpolationmethod'].') (valid = 0 or 1)'; + } else { + $framedata .= chr($source_data_array['interpolationmethod']); + $framedata .= str_replace("\x00", '', $source_data_array['description'])."\x00"; + foreach ($source_data_array['data'] as $key => $val) { + $framedata .= getid3_lib::BigEndian2String(intval(round($key * 2)), 2, false); + $framedata .= getid3_lib::BigEndian2String($val, 2, false, true); // signed 16-bit + } + } + break; + + case 'EQUA': + // 4.12 EQUA Equalisation (ID3v2.3 only) + // Adjustment bits $xx + // This is followed by 2 bytes + ('adjustment bits' rounded up to the + // nearest byte) for every equalisation band in the following format, + // giving a frequency range of 0 - 32767Hz: + // Increment/decrement %x (MSB of the Frequency) + // Frequency (lower 15 bits) + // Adjustment $xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['bitsvolume'], 8, false)) { + $this->errors[] = 'Invalid Adjustment Bits byte in '.$frame_name.' ('.$source_data_array['bitsvolume'].') (range = 1 to 255)'; + } else { + $framedata .= chr($source_data_array['adjustmentbits']); + foreach ($source_data_array as $key => $val) { + if ($key != 'bitsvolume') { + if (($key > 32767) || ($key < 0)) { + $this->errors[] = 'Invalid Frequency in '.$frame_name.' ('.$key.') (range = 0 to 32767)'; + } else { + if ($val >= 0) { + // put MSB of frequency to 1 if increment, 0 if decrement + $key |= 0x8000; + } + $framedata .= getid3_lib::BigEndian2String($key, 2, false); + $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['adjustmentbits'] / 8), false); + } + } + } + } + break; + + case 'RVRB': + // 4.13 RVRB Reverb + // Reverb left (ms) $xx xx + // Reverb right (ms) $xx xx + // Reverb bounces, left $xx + // Reverb bounces, right $xx + // Reverb feedback, left to left $xx + // Reverb feedback, left to right $xx + // Reverb feedback, right to right $xx + // Reverb feedback, right to left $xx + // Premix left to right $xx + // Premix right to left $xx + if (!$this->IsWithinBitRange($source_data_array['left'], 16, false)) { + $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['left'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['right'], 16, false)) { + $this->errors[] = 'Invalid Reverb Left in '.$frame_name.' ('.$source_data_array['right'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bouncesL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Bounces, Left in '.$frame_name.' ('.$source_data_array['bouncesL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bouncesR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Bounces, Right in '.$frame_name.' ('.$source_data_array['bouncesR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Left-To-Left in '.$frame_name.' ('.$source_data_array['feedbackLL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackLR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Left-To-Right in '.$frame_name.' ('.$source_data_array['feedbackLR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRR'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Right-To-Right in '.$frame_name.' ('.$source_data_array['feedbackRR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['feedbackRL'], 8, false)) { + $this->errors[] = 'Invalid Reverb Feedback, Right-To-Left in '.$frame_name.' ('.$source_data_array['feedbackRL'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['premixLR'], 8, false)) { + $this->errors[] = 'Invalid Premix, Left-To-Right in '.$frame_name.' ('.$source_data_array['premixLR'].') (range = 0 to 255)'; + } elseif (!$this->IsWithinBitRange($source_data_array['premixRL'], 8, false)) { + $this->errors[] = 'Invalid Premix, Right-To-Left in '.$frame_name.' ('.$source_data_array['premixRL'].') (range = 0 to 255)'; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['left'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['right'], 2, false); + $framedata .= chr($source_data_array['bouncesL']); + $framedata .= chr($source_data_array['bouncesR']); + $framedata .= chr($source_data_array['feedbackLL']); + $framedata .= chr($source_data_array['feedbackLR']); + $framedata .= chr($source_data_array['feedbackRR']); + $framedata .= chr($source_data_array['feedbackRL']); + $framedata .= chr($source_data_array['premixLR']); + $framedata .= chr($source_data_array['premixRL']); + } + break; + + case 'APIC': + // 4.14 APIC Attached picture + // Text encoding $xx + // MIME type $00 + // Picture type $xx + // Description $00 (00) + // Picture data + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!$this->ID3v2IsValidAPICpicturetype($source_data_array['picturetypeid'])) { + $this->errors[] = 'Invalid Picture Type byte in '.$frame_name.' ('.$source_data_array['picturetypeid'].') for ID3v2.'.$this->majorversion; + } elseif (($this->majorversion >= 3) && (!$this->ID3v2IsValidAPICimageformat($source_data_array['mime']))) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].') for ID3v2.'.$this->majorversion; + } elseif (($source_data_array['mime'] == '-->') && (!$this->IsValidURL($source_data_array['data'], false, false))) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; + $framedata .= chr($source_data_array['picturetypeid']); + $framedata .= (!empty($source_data_array['description']) ? $source_data_array['description'] : '').getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'GEOB': + // 4.15 GEOB General encapsulated object + // Text encoding $xx + // MIME type $00 + // Filename $00 (00) + // Content description $00 (00) + // Encapsulated object + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; + } elseif (!$source_data_array['description']) { + $this->errors[] = 'Missing Description in '.$frame_name; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['mime'])."\x00"; + $framedata .= $source_data_array['filename'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + break; + + case 'PCNT': + // 4.16 PCNT Play counter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Counter $xx xx xx xx (xx ...) + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + break; + + case 'POPM': + // 4.17 POPM Popularimeter + // When the counter reaches all one's, one byte is inserted in + // front of the counter thus making the counter eight bits bigger + // Email to user $00 + // Rating $xx + // Counter $xx xx xx xx (xx ...) + if (!$this->IsWithinBitRange($source_data_array['rating'], 8, false)) { + $this->errors[] = 'Invalid Rating byte in '.$frame_name.' ('.$source_data_array['rating'].') (range = 0 to 255)'; + } elseif (!IsValidEmail($source_data_array['email'])) { + $this->errors[] = 'Invalid Email in '.$frame_name.' ('.$source_data_array['email'].')'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['email'])."\x00"; + $framedata .= chr($source_data_array['rating']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + } + break; + + case 'RBUF': + // 4.18 RBUF Recommended buffer size + // Buffer size $xx xx xx + // Embedded info flag %0000000x + // Offset to next tag $xx xx xx xx + if (!$this->IsWithinBitRange($source_data_array['buffersize'], 24, false)) { + $this->errors[] = 'Invalid Buffer Size in '.$frame_name; + } elseif (!$this->IsWithinBitRange($source_data_array['nexttagoffset'], 32, false)) { + $this->errors[] = 'Invalid Offset To Next Tag in '.$frame_name; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['buffersize'], 3, false); + $flag .= '0000000'; + $flag .= $source_data_array['flags']['embededinfo'] ? '1' : '0'; + $framedata .= chr(bindec($flag)); + $framedata .= getid3_lib::BigEndian2String($source_data_array['nexttagoffset'], 4, false); + } + break; + + case 'AENC': + // 4.19 AENC Audio encryption + // Owner identifier $00 + // Preview start $xx xx + // Preview length $xx xx + // Encryption info + if (!$this->IsWithinBitRange($source_data_array['previewstart'], 16, false)) { + $this->errors[] = 'Invalid Preview Start in '.$frame_name.' ('.$source_data_array['previewstart'].')'; + } elseif (!$this->IsWithinBitRange($source_data_array['previewlength'], 16, false)) { + $this->errors[] = 'Invalid Preview Length in '.$frame_name.' ('.$source_data_array['previewlength'].')'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= getid3_lib::BigEndian2String($source_data_array['previewstart'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['previewlength'], 2, false); + $framedata .= $source_data_array['encryptioninfo']; + } + break; + + case 'LINK': + // 4.20 LINK Linked information + // Frame identifier $xx xx xx xx + // URL $00 + // ID and additional data + if (!getid3_id3v2::IsValidID3v2FrameName($source_data_array['frameid'], $this->majorversion)) { + $this->errors[] = 'Invalid Frame Identifier in '.$frame_name.' ('.$source_data_array['frameid'].')'; + } elseif (!$this->IsValidURL($source_data_array['data'], true, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } elseif ((($source_data_array['frameid'] == 'AENC') || ($source_data_array['frameid'] == 'APIC') || ($source_data_array['frameid'] == 'GEOB') || ($source_data_array['frameid'] == 'TXXX')) && ($source_data_array['additionaldata'] == '')) { + $this->errors[] = 'Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif (($source_data_array['frameid'] == 'USER') && (getid3_id3v2::LanguageLookup($source_data_array['additionaldata'], true) == '')) { + $this->errors[] = 'Language must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif (($source_data_array['frameid'] == 'PRIV') && ($source_data_array['additionaldata'] == '')) { + $this->errors[] = 'Owner Identifier must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } elseif ((($source_data_array['frameid'] == 'COMM') || ($source_data_array['frameid'] == 'SYLT') || ($source_data_array['frameid'] == 'USLT')) && ((getid3_id3v2::LanguageLookup(substr($source_data_array['additionaldata'], 0, 3), true) == '') || (substr($source_data_array['additionaldata'], 3) == ''))) { + $this->errors[] = 'Language followed by Content Descriptor must be specified as additional data for Frame Identifier of '.$source_data_array['frameid'].' in '.$frame_name; + } else { + $framedata .= $source_data_array['frameid']; + $framedata .= str_replace("\x00", '', $source_data_array['data'])."\x00"; + switch ($source_data_array['frameid']) { + case 'COMM': + case 'SYLT': + case 'USLT': + case 'PRIV': + case 'USER': + case 'AENC': + case 'APIC': + case 'GEOB': + case 'TXXX': + $framedata .= $source_data_array['additionaldata']; + break; + case 'ASPI': + case 'ETCO': + case 'EQU2': + case 'MCID': + case 'MLLT': + case 'OWNE': + case 'RVA2': + case 'RVRB': + case 'SYTC': + case 'IPLS': + case 'RVAD': + case 'EQUA': + // no additional data required + break; + case 'RBUF': + if ($this->majorversion == 3) { + // no additional data required + } else { + $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; + } + + default: + if ((substr($source_data_array['frameid'], 0, 1) == 'T') || (substr($source_data_array['frameid'], 0, 1) == 'W')) { + // no additional data required + } else { + $this->errors[] = $source_data_array['frameid'].' is not a valid Frame Identifier in '.$frame_name.' (in ID3v2.'.$this->majorversion.')'; + } + break; + } + } + break; + + case 'POSS': + // 4.21 POSS Position synchronisation frame (ID3v2.3+ only) + // Time stamp format $xx + // Position $xx (xx ...) + if (($source_data_array['timestampformat'] < 1) || ($source_data_array['timestampformat'] > 2)) { + $this->errors[] = 'Invalid Time Stamp Format in '.$frame_name.' ('.$source_data_array['timestampformat'].') (valid = 1 or 2)'; + } elseif (!$this->IsWithinBitRange($source_data_array['position'], 32, false)) { + $this->errors[] = 'Invalid Position in '.$frame_name.' ('.$source_data_array['position'].') (range = 0 to 4294967295)'; + } else { + $framedata .= chr($source_data_array['timestampformat']); + $framedata .= getid3_lib::BigEndian2String($source_data_array['position'], 4, false); + } + break; + + case 'USER': + // 4.22 USER Terms of use (ID3v2.3+ only) + // Text encoding $xx + // Language $xx xx xx + // The actual text + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (getid3_id3v2::LanguageLookup($source_data_array['language'], true) == '') { + $this->errors[] = 'Invalid Language in '.$frame_name.' ('.$source_data_array['language'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= strtolower($source_data_array['language']); + $framedata .= $source_data_array['data']; + } + break; + + case 'OWNE': + // 4.23 OWNE Ownership frame (ID3v2.3+ only) + // Text encoding $xx + // Price paid $00 + // Date of purch. + // Seller + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (!$this->IsANumber($source_data_array['pricepaid']['value'], false)) { + $this->errors[] = 'Invalid Price Paid in '.$frame_name.' ('.$source_data_array['pricepaid']['value'].')'; + } elseif (!$this->IsValidDateStampString($source_data_array['purchasedate'])) { + $this->errors[] = 'Invalid Date Of Purchase in '.$frame_name.' ('.$source_data_array['purchasedate'].') (format = YYYYMMDD)'; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= str_replace("\x00", '', $source_data_array['pricepaid']['value'])."\x00"; + $framedata .= $source_data_array['purchasedate']; + $framedata .= $source_data_array['seller']; + } + break; + + case 'COMR': + // 4.24 COMR Commercial frame (ID3v2.3+ only) + // Text encoding $xx + // Price string $00 + // Valid until + // Contact URL $00 + // Received as $xx + // Name of seller $00 (00) + // Description $00 (00) + // Picture MIME type $00 + // Seller logo + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].')'; + } elseif (!$this->IsValidDateStampString($source_data_array['pricevaliduntil'])) { + $this->errors[] = 'Invalid Valid Until date in '.$frame_name.' ('.$source_data_array['pricevaliduntil'].') (format = YYYYMMDD)'; + } elseif (!$this->IsValidURL($source_data_array['contacturl'], false, true)) { + $this->errors[] = 'Invalid Contact URL in '.$frame_name.' ('.$source_data_array['contacturl'].') (allowed schemes: http, https, ftp, mailto)'; + } elseif (!$this->ID3v2IsValidCOMRreceivedAs($source_data_array['receivedasid'])) { + $this->errors[] = 'Invalid Received As byte in '.$frame_name.' ('.$source_data_array['contacturl'].') (range = 0 to 8)'; + } elseif (!$this->IsValidMIMEstring($source_data_array['mime'])) { + $this->errors[] = 'Invalid MIME Type in '.$frame_name.' ('.$source_data_array['mime'].')'; + } else { + $framedata .= chr($source_data_array['encodingid']); + unset($pricestring); + foreach ($source_data_array['price'] as $key => $val) { + if ($this->ID3v2IsValidPriceString($key.$val['value'])) { + $pricestrings[] = $key.$val['value']; + } else { + $this->errors[] = 'Invalid Price String in '.$frame_name.' ('.$key.$val['value'].')'; + } + } + $framedata .= implode('/', $pricestrings); + $framedata .= $source_data_array['pricevaliduntil']; + $framedata .= str_replace("\x00", '', $source_data_array['contacturl'])."\x00"; + $framedata .= chr($source_data_array['receivedasid']); + $framedata .= $source_data_array['sellername'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['description'].getid3_id3v2::TextEncodingTerminatorLookup($source_data_array['encodingid']); + $framedata .= $source_data_array['mime']."\x00"; + $framedata .= $source_data_array['logo']; + } + break; + + case 'ENCR': + // 4.25 ENCR Encryption method registration (ID3v2.3+ only) + // Owner identifier $00 + // Method symbol $xx + // Encryption data + if (!$this->IsWithinBitRange($source_data_array['methodsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['methodsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= ord($source_data_array['methodsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'GRID': + // 4.26 GRID Group identification registration (ID3v2.3+ only) + // Owner identifier $00 + // Group symbol $xx + // Group dependent data + if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= ord($source_data_array['groupsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'PRIV': + // 4.27 PRIV Private frame (ID3v2.3+ only) + // Owner identifier $00 + // The private data + $framedata .= str_replace("\x00", '', $source_data_array['ownerid'])."\x00"; + $framedata .= $source_data_array['data']; + break; + + case 'SIGN': + // 4.28 SIGN Signature frame (ID3v2.4+ only) + // Group symbol $xx + // Signature + if (!$this->IsWithinBitRange($source_data_array['groupsymbol'], 8, false)) { + $this->errors[] = 'Invalid Group Symbol in '.$frame_name.' ('.$source_data_array['groupsymbol'].') (range = 0 to 255)'; + } else { + $framedata .= ord($source_data_array['groupsymbol']); + $framedata .= $source_data_array['data']; + } + break; + + case 'SEEK': + // 4.29 SEEK Seek frame (ID3v2.4+ only) + // Minimum offset to next tag $xx xx xx xx + if (!$this->IsWithinBitRange($source_data_array['data'], 32, false)) { + $this->errors[] = 'Invalid Minimum Offset in '.$frame_name.' ('.$source_data_array['data'].') (range = 0 to 4294967295)'; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['data'], 4, false); + } + break; + + case 'ASPI': + // 4.30 ASPI Audio seek point index (ID3v2.4+ only) + // Indexed data start (S) $xx xx xx xx + // Indexed data length (L) $xx xx xx xx + // Number of index points (N) $xx xx + // Bits per index point (b) $xx + // Then for every index point the following data is included: + // Fraction at index (Fi) $xx (xx) + if (!$this->IsWithinBitRange($source_data_array['datastart'], 32, false)) { + $this->errors[] = 'Invalid Indexed Data Start in '.$frame_name.' ('.$source_data_array['datastart'].') (range = 0 to 4294967295)'; + } elseif (!$this->IsWithinBitRange($source_data_array['datalength'], 32, false)) { + $this->errors[] = 'Invalid Indexed Data Length in '.$frame_name.' ('.$source_data_array['datalength'].') (range = 0 to 4294967295)'; + } elseif (!$this->IsWithinBitRange($source_data_array['indexpoints'], 16, false)) { + $this->errors[] = 'Invalid Number Of Index Points in '.$frame_name.' ('.$source_data_array['indexpoints'].') (range = 0 to 65535)'; + } elseif (!$this->IsWithinBitRange($source_data_array['bitsperpoint'], 8, false)) { + $this->errors[] = 'Invalid Bits Per Index Point in '.$frame_name.' ('.$source_data_array['bitsperpoint'].') (range = 0 to 255)'; + } elseif ($source_data_array['indexpoints'] != count($source_data_array['indexes'])) { + $this->errors[] = 'Number Of Index Points does not match actual supplied data in '.$frame_name; + } else { + $framedata .= getid3_lib::BigEndian2String($source_data_array['datastart'], 4, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['datalength'], 4, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['indexpoints'], 2, false); + $framedata .= getid3_lib::BigEndian2String($source_data_array['bitsperpoint'], 1, false); + foreach ($source_data_array['indexes'] as $key => $val) { + $framedata .= getid3_lib::BigEndian2String($val, ceil($source_data_array['bitsperpoint'] / 8), false); + } + } + break; + + case 'RGAD': + // RGAD Replay Gain Adjustment + // http://privatewww.essex.ac.uk/~djmrob/replaygain/ + // Peak Amplitude $xx $xx $xx $xx + // Radio Replay Gain Adjustment %aaabbbcd %dddddddd + // Audiophile Replay Gain Adjustment %aaabbbcd %dddddddd + // a - name code + // b - originator code + // c - sign bit + // d - replay gain adjustment + + if (($source_data_array['track_adjustment'] > 51) || ($source_data_array['track_adjustment'] < -51)) { + $this->errors[] = 'Invalid Track Adjustment in '.$frame_name.' ('.$source_data_array['track_adjustment'].') (range = -51.0 to +51.0)'; + } elseif (($source_data_array['album_adjustment'] > 51) || ($source_data_array['album_adjustment'] < -51)) { + $this->errors[] = 'Invalid Album Adjustment in '.$frame_name.' ('.$source_data_array['album_adjustment'].') (range = -51.0 to +51.0)'; + } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['track_name'])) { + $this->errors[] = 'Invalid Track Name Code in '.$frame_name.' ('.$source_data_array['raw']['track_name'].') (range = 0 to 2)'; + } elseif (!$this->ID3v2IsValidRGADname($source_data_array['raw']['album_name'])) { + $this->errors[] = 'Invalid Album Name Code in '.$frame_name.' ('.$source_data_array['raw']['album_name'].') (range = 0 to 2)'; + } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['track_originator'])) { + $this->errors[] = 'Invalid Track Originator Code in '.$frame_name.' ('.$source_data_array['raw']['track_originator'].') (range = 0 to 3)'; + } elseif (!$this->ID3v2IsValidRGADoriginator($source_data_array['raw']['album_originator'])) { + $this->errors[] = 'Invalid Album Originator Code in '.$frame_name.' ('.$source_data_array['raw']['album_originator'].') (range = 0 to 3)'; + } else { + $framedata .= getid3_lib::Float2String($source_data_array['peakamplitude'], 32); + $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['track_name'], $source_data_array['raw']['track_originator'], $source_data_array['track_adjustment']); + $framedata .= getid3_lib::RGADgainString($source_data_array['raw']['album_name'], $source_data_array['raw']['album_originator'], $source_data_array['album_adjustment']); + } + break; + + default: + if ((($this->majorversion == 2) && (strlen($frame_name) != 3)) || (($this->majorversion > 2) && (strlen($frame_name) != 4))) { + $this->errors[] = 'Invalid frame name "'.$frame_name.'" for ID3v2.'.$this->majorversion; + } elseif ($frame_name{0} == 'T') { + // 4.2. T??? Text information frames + // Text encoding $xx + // Information + $source_data_array['encodingid'] = (isset($source_data_array['encodingid']) ? $source_data_array['encodingid'] : $this->id3v2_default_encodingid); + if (!$this->ID3v2IsValidTextEncoding($source_data_array['encodingid'])) { + $this->errors[] = 'Invalid Text Encoding in '.$frame_name.' ('.$source_data_array['encodingid'].') for ID3v2.'.$this->majorversion; + } else { + $framedata .= chr($source_data_array['encodingid']); + $framedata .= $source_data_array['data']; + } + } elseif ($frame_name{0} == 'W') { + // 4.3. W??? URL link frames + // URL + if (!$this->IsValidURL($source_data_array['data'], false, false)) { + //$this->errors[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + // probably should be an error, need to rewrite IsValidURL() to handle other encodings + $this->warnings[] = 'Invalid URL in '.$frame_name.' ('.$source_data_array['data'].')'; + } else { + $framedata .= $source_data_array['data']; + } + } else { + $this->errors[] = $frame_name.' not yet supported in $this->GenerateID3v2FrameData()'; + } + break; + } + } + if (!empty($this->errors)) { + return false; + } + return $framedata; + } + + public function ID3v2FrameIsAllowed($frame_name, $source_data_array) { + static $PreviousFrames = array(); + + if ($frame_name === null) { + // if the writing functions are called multiple times, the static array needs to be + // cleared - this can be done by calling $this->ID3v2FrameIsAllowed(null, '') + $PreviousFrames = array(); + return true; + } + + if ($this->majorversion == 4) { + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXXX': + case 'WXXX': + case 'RVA2': + case 'EQU2': + case 'APIC': + case 'GEOB': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'USER': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language']; + } + break; + + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POPM': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'SEEK': + case 'ASPI': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + + case 'PRIV': + case 'SIGN': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (!isset($source_data_array['data'])) { + $this->errors[] = '[data] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + + } elseif ($this->majorversion == 3) { + + switch ($frame_name) { + case 'UFID': + case 'AENC': + case 'ENCR': + case 'GRID': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXXX': + case 'WXXX': + case 'APIC': + case 'GEOB': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'USER': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language ('.$source_data_array['language'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language']; + } + break; + + case 'USLT': + case 'SYLT': + case 'COMM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POPM': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPLS': + case 'MCDI': + case 'ETCO': + case 'MLLT': + case 'SYTC': + case 'RVAD': + case 'EQUA': + case 'RVRB': + case 'PCNT': + case 'RBUF': + case 'POSS': + case 'OWNE': + case 'RGAD': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LINK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + case 'COMR': + // There may be more than one 'commercial frame' in a tag, but no two may be identical + // Checking isn't implemented at all (yet) - just assumes that it's OK. + break; + + case 'PRIV': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (!isset($source_data_array['data'])) { + $this->errors[] = '[data] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'].$source_data_array['data'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID + Data ('.$source_data_array['ownerid'].' + '.$source_data_array['data'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid'].$source_data_array['data']; + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + + } elseif ($this->majorversion == 2) { + + switch ($frame_name) { + case 'UFI': + case 'CRM': + case 'CRA': + if (!isset($source_data_array['ownerid'])) { + $this->errors[] = '[ownerid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['ownerid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same OwnerID ('.$source_data_array['ownerid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['ownerid']; + } + break; + + case 'TXX': + case 'WXX': + case 'PIC': + case 'GEO': + if (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Description ('.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['description']; + } + break; + + case 'ULT': + case 'SLT': + case 'COM': + if (!isset($source_data_array['language'])) { + $this->errors[] = '[language] not specified for '.$frame_name; + } elseif (!isset($source_data_array['description'])) { + $this->errors[] = '[description] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['language'].$source_data_array['description'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Language + Description ('.$source_data_array['language'].' + '.$source_data_array['description'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['language'].$source_data_array['description']; + } + break; + + case 'POP': + if (!isset($source_data_array['email'])) { + $this->errors[] = '[email] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['email'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same Email ('.$source_data_array['email'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['email']; + } + break; + + case 'IPL': + case 'MCI': + case 'ETC': + case 'MLL': + case 'STC': + case 'RVA': + case 'EQU': + case 'REV': + case 'CNT': + case 'BUF': + if (in_array($frame_name, $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed'; + } else { + $PreviousFrames[] = $frame_name; + } + break; + + case 'LNK': + // this isn't implemented quite right (yet) - it should check the target frame data for compliance + // but right now it just allows one linked frame of each type, to be safe. + if (!isset($source_data_array['frameid'])) { + $this->errors[] = '[frameid] not specified for '.$frame_name; + } elseif (in_array($frame_name.$source_data_array['frameid'], $PreviousFrames)) { + $this->errors[] = 'Only one '.$frame_name.' tag allowed with the same FrameID ('.$source_data_array['frameid'].')'; + } elseif (in_array($source_data_array['frameid'], $PreviousFrames)) { + // no links to singleton tags + $this->errors[] = 'Cannot specify a '.$frame_name.' tag to a singleton tag that already exists ('.$source_data_array['frameid'].')'; + } else { + $PreviousFrames[] = $frame_name.$source_data_array['frameid']; // only one linked tag of this type + $PreviousFrames[] = $source_data_array['frameid']; // no non-linked singleton tags of this type + } + break; + + default: + if (($frame_name{0} != 'T') && ($frame_name{0} != 'W')) { + $this->errors[] = 'Frame not allowed in ID3v2.'.$this->majorversion.': '.$frame_name; + } + break; + } + } + + if (!empty($this->errors)) { + return false; + } + return true; + } + + public function GenerateID3v2Tag($noerrorsonly=true) { + $this->ID3v2FrameIsAllowed(null, ''); // clear static array in case this isn't the first call to $this->GenerateID3v2Tag() + + $tagstring = ''; + if (is_array($this->tag_data)) { + foreach ($this->tag_data as $frame_name => $frame_rawinputdata) { + foreach ($frame_rawinputdata as $irrelevantindex => $source_data_array) { + if (getid3_id3v2::IsValidID3v2FrameName($frame_name, $this->majorversion)) { + unset($frame_length); + unset($frame_flags); + $frame_data = false; + if ($this->ID3v2FrameIsAllowed($frame_name, $source_data_array)) { + if ($frame_data = $this->GenerateID3v2FrameData($frame_name, $source_data_array)) { + $FrameUnsynchronisation = false; + if ($this->majorversion >= 4) { + // frame-level unsynchronisation + $unsynchdata = $frame_data; + if ($this->id3v2_use_unsynchronisation) { + $unsynchdata = $this->Unsynchronise($frame_data); + } + if (strlen($unsynchdata) != strlen($frame_data)) { + // unsynchronisation needed + $FrameUnsynchronisation = true; + $frame_data = $unsynchdata; + if (isset($TagUnsynchronisation) && $TagUnsynchronisation === false) { + // only set to true if ALL frames are unsynchronised + } else { + $TagUnsynchronisation = true; + } + } else { + if (isset($TagUnsynchronisation)) { + $TagUnsynchronisation = false; + } + } + unset($unsynchdata); + + $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, true); + } else { + $frame_length = getid3_lib::BigEndian2String(strlen($frame_data), 4, false); + } + $frame_flags = $this->GenerateID3v2FrameFlags($this->ID3v2FrameFlagsLookupTagAlter($frame_name), $this->ID3v2FrameFlagsLookupFileAlter($frame_name), false, false, false, false, $FrameUnsynchronisation, false); + } + } else { + $this->errors[] = 'Frame "'.$frame_name.'" is NOT allowed'; + } + if ($frame_data === false) { + $this->errors[] = '$this->GenerateID3v2FrameData() failed for "'.$frame_name.'"'; + if ($noerrorsonly) { + return false; + } else { + unset($frame_name); + } + } + } else { + // ignore any invalid frame names, including 'title', 'header', etc + $this->warnings[] = 'Ignoring invalid ID3v2 frame type: "'.$frame_name.'"'; + unset($frame_name); + unset($frame_length); + unset($frame_flags); + unset($frame_data); + } + if (isset($frame_name) && isset($frame_length) && isset($frame_flags) && isset($frame_data)) { + $tagstring .= $frame_name.$frame_length.$frame_flags.$frame_data; + } + } + } + + if (!isset($TagUnsynchronisation)) { + $TagUnsynchronisation = false; + } + if (($this->majorversion <= 3) && $this->id3v2_use_unsynchronisation) { + // tag-level unsynchronisation + $unsynchdata = $this->Unsynchronise($tagstring); + if (strlen($unsynchdata) != strlen($tagstring)) { + // unsynchronisation needed + $TagUnsynchronisation = true; + $tagstring = $unsynchdata; + } + } + + while ($this->paddedlength < (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion))) { + $this->paddedlength += 1024; + } + + $footer = false; // ID3v2 footers not yet supported in getID3() + if (!$footer && ($this->paddedlength > (strlen($tagstring) + getid3_id3v2::ID3v2HeaderLength($this->majorversion)))) { + // pad up to $paddedlength bytes if unpadded tag is shorter than $paddedlength + // "Furthermore it MUST NOT have any padding when a tag footer is added to the tag." + if (($this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)) > 0) { + $tagstring .= str_repeat("\x00", $this->paddedlength - strlen($tagstring) - getid3_id3v2::ID3v2HeaderLength($this->majorversion)); + } + } + if ($this->id3v2_use_unsynchronisation && (substr($tagstring, strlen($tagstring) - 1, 1) == "\xFF")) { + // special unsynchronisation case: + // if last byte == $FF then appended a $00 + $TagUnsynchronisation = true; + $tagstring .= "\x00"; + } + + $tagheader = 'ID3'; + $tagheader .= chr($this->majorversion); + $tagheader .= chr($this->minorversion); + $tagheader .= $this->GenerateID3v2TagFlags(array('unsynchronisation'=>$TagUnsynchronisation)); + $tagheader .= getid3_lib::BigEndian2String(strlen($tagstring), 4, true); + + return $tagheader.$tagstring; + } + $this->errors[] = 'tag_data is not an array in GenerateID3v2Tag()'; + return false; + } + + public function ID3v2IsValidPriceString($pricestring) { + if (getid3_id3v2::LanguageLookup(substr($pricestring, 0, 3), true) == '') { + return false; + } elseif (!$this->IsANumber(substr($pricestring, 3), true)) { + return false; + } + return true; + } + + public function ID3v2FrameFlagsLookupTagAlter($framename) { + // unfinished + switch ($framename) { + case 'RGAD': + $allow = true; + default: + $allow = false; + break; + } + return $allow; + } + + public function ID3v2FrameFlagsLookupFileAlter($framename) { + // unfinished + switch ($framename) { + case 'RGAD': + return false; + break; + + default: + return false; + break; + } + } + + public function ID3v2IsValidETCOevent($eventid) { + if (($eventid < 0) || ($eventid > 0xFF)) { + // outside range of 1 byte + return false; + } elseif (($eventid >= 0xF0) && ($eventid <= 0xFC)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x17) && ($eventid <= 0xDF)) { + // reserved for future use + return false; + } elseif (($eventid >= 0x0E) && ($eventid <= 0x16) && ($this->majorversion == 2)) { + // not defined in ID3v2.2 + return false; + } elseif (($eventid >= 0x15) && ($eventid <= 0x16) && ($this->majorversion == 3)) { + // not defined in ID3v2.3 + return false; + } + return true; + } + + public function ID3v2IsValidSYLTtype($contenttype) { + if (($contenttype >= 0) && ($contenttype <= 8) && ($this->majorversion == 4)) { + return true; + } elseif (($contenttype >= 0) && ($contenttype <= 6) && ($this->majorversion == 3)) { + return true; + } + return false; + } + + public function ID3v2IsValidRVA2channeltype($channeltype) { + if (($channeltype >= 0) && ($channeltype <= 8) && ($this->majorversion == 4)) { + return true; + } + return false; + } + + public function ID3v2IsValidAPICpicturetype($picturetype) { + if (($picturetype >= 0) && ($picturetype <= 0x14) && ($this->majorversion >= 2) && ($this->majorversion <= 4)) { + return true; + } + return false; + } + + public function ID3v2IsValidAPICimageformat($imageformat) { + if ($imageformat == '-->') { + return true; + } elseif ($this->majorversion == 2) { + if ((strlen($imageformat) == 3) && ($imageformat == strtoupper($imageformat))) { + return true; + } + } elseif (($this->majorversion == 3) || ($this->majorversion == 4)) { + if ($this->IsValidMIMEstring($imageformat)) { + return true; + } + } + return false; + } + + public function ID3v2IsValidCOMRreceivedAs($receivedas) { + if (($this->majorversion >= 3) && ($receivedas >= 0) && ($receivedas <= 8)) { + return true; + } + return false; + } + + public function ID3v2IsValidRGADname($RGADname) { + if (($RGADname >= 0) && ($RGADname <= 2)) { + return true; + } + return false; + } + + public function ID3v2IsValidRGADoriginator($RGADoriginator) { + if (($RGADoriginator >= 0) && ($RGADoriginator <= 3)) { + return true; + } + return false; + } + + public function ID3v2IsValidTextEncoding($textencodingbyte) { + static $ID3v2IsValidTextEncoding_cache = array( + 2 => array(true, true), + 3 => array(true, true), + 4 => array(true, true, true, true)); + return isset($ID3v2IsValidTextEncoding_cache[$this->majorversion][$textencodingbyte]); + } + + public function Unsynchronise($data) { + // Whenever a false synchronisation is found within the tag, one zeroed + // byte is inserted after the first false synchronisation byte. The + // format of a correct sync that should be altered by ID3 encoders is as + // follows: + // %11111111 111xxxxx + // And should be replaced with: + // %11111111 00000000 111xxxxx + // This has the side effect that all $FF 00 combinations have to be + // altered, so they won't be affected by the decoding process. Therefore + // all the $FF 00 combinations have to be replaced with the $FF 00 00 + // combination during the unsynchronisation. + + $data = str_replace("\xFF\x00", "\xFF\x00\x00", $data); + $unsyncheddata = ''; + $datalength = strlen($data); + for ($i = 0; $i < $datalength; $i++) { + $thischar = $data{$i}; + $unsyncheddata .= $thischar; + if ($thischar == "\xFF") { + $nextchar = ord($data{$i + 1}); + if (($nextchar & 0xE0) == 0xE0) { + // previous byte = 11111111, this byte = 111????? + $unsyncheddata .= "\x00"; + } + } + } + return $unsyncheddata; + } + + public function is_hash($var) { + // written by dev-nullØchristophe*vg + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (is_array($var)) { + $keys = array_keys($var); + $all_num = true; + for ($i = 0; $i < count($keys); $i++) { + if (is_string($keys[$i])) { + return true; + } + } + } + return false; + } + + public function array_join_merge($arr1, $arr2) { + // written by dev-nullØchristophe*vg + // taken from http://www.php.net/manual/en/function.array-merge-recursive.php + if (is_array($arr1) && is_array($arr2)) { + // the same -> merge + $new_array = array(); + + if ($this->is_hash($arr1) && $this->is_hash($arr2)) { + // hashes -> merge based on keys + $keys = array_merge(array_keys($arr1), array_keys($arr2)); + foreach ($keys as $key) { + $new_array[$key] = $this->array_join_merge((isset($arr1[$key]) ? $arr1[$key] : ''), (isset($arr2[$key]) ? $arr2[$key] : '')); + } + } else { + // two real arrays -> merge + $new_array = array_reverse(array_unique(array_reverse(array_merge($arr1, $arr2)))); + } + return $new_array; + } else { + // not the same ... take new one if defined, else the old one stays + return $arr2 ? $arr2 : $arr1; + } + } + + public function IsValidMIMEstring($mimestring) { + if ((strlen($mimestring) >= 3) && (strpos($mimestring, '/') > 0) && (strpos($mimestring, '/') < (strlen($mimestring) - 1))) { + return true; + } + return false; + } + + public function IsWithinBitRange($number, $maxbits, $signed=false) { + if ($signed) { + if (($number > (0 - pow(2, $maxbits - 1))) && ($number <= pow(2, $maxbits - 1))) { + return true; + } + } else { + if (($number >= 0) && ($number <= pow(2, $maxbits))) { + return true; + } + } + return false; + } + + public function safe_parse_url($url) { + $parts = @parse_url($url); + $parts['scheme'] = (isset($parts['scheme']) ? $parts['scheme'] : ''); + $parts['host'] = (isset($parts['host']) ? $parts['host'] : ''); + $parts['user'] = (isset($parts['user']) ? $parts['user'] : ''); + $parts['pass'] = (isset($parts['pass']) ? $parts['pass'] : ''); + $parts['path'] = (isset($parts['path']) ? $parts['path'] : ''); + $parts['query'] = (isset($parts['query']) ? $parts['query'] : ''); + return $parts; + } + + public function IsValidURL($url, $allowUserPass=false) { + if ($url == '') { + return false; + } + if ($allowUserPass !== true) { + if (strstr($url, '@')) { + // in the format http://user:pass@example.com or http://user@example.com + // but could easily be somebody incorrectly entering an email address in place of a URL + return false; + } + } + if ($parts = $this->safe_parse_url($url)) { + if (($parts['scheme'] != 'http') && ($parts['scheme'] != 'https') && ($parts['scheme'] != 'ftp') && ($parts['scheme'] != 'gopher')) { + return false; + } elseif (!preg_match('#^[[:alnum:]]([-.]?[0-9a-z])*\\.[a-z]{2,3}$#i', $parts['host'], $regs) && !preg_match('#^[0-9]{1,3}(\\.[0-9]{1,3}){3}$#', $parts['host'])) { + return false; + } elseif (!preg_match('#^([[:alnum:]-]|[\\_])*$#i', $parts['user'], $regs)) { + return false; + } elseif (!preg_match('#^([[:alnum:]-]|[\\_])*$#i', $parts['pass'], $regs)) { + return false; + } elseif (!preg_match('#^[[:alnum:]/_\\.@~-]*$#i', $parts['path'], $regs)) { + return false; + } elseif (!empty($parts['query']) && !preg_match('#^[[:alnum:]?&=+:;_()%\\#/,\\.-]*$#i', $parts['query'], $regs)) { + return false; + } else { + return true; + } + } + return false; + } + + public static function ID3v2ShortFrameNameLookup($majorversion, $long_description) { + $long_description = str_replace(' ', '_', strtolower(trim($long_description))); + static $ID3v2ShortFrameNameLookup = array(); + if (empty($ID3v2ShortFrameNameLookup)) { + + // The following are unique to ID3v2.2 + $ID3v2ShortFrameNameLookup[2]['comment'] = 'COM'; + $ID3v2ShortFrameNameLookup[2]['album'] = 'TAL'; + $ID3v2ShortFrameNameLookup[2]['beats_per_minute'] = 'TBP'; + $ID3v2ShortFrameNameLookup[2]['composer'] = 'TCM'; + $ID3v2ShortFrameNameLookup[2]['genre'] = 'TCO'; + $ID3v2ShortFrameNameLookup[2]['itunescompilation'] = 'TCP'; + $ID3v2ShortFrameNameLookup[2]['copyright'] = 'TCR'; + $ID3v2ShortFrameNameLookup[2]['encoded_by'] = 'TEN'; + $ID3v2ShortFrameNameLookup[2]['language'] = 'TLA'; + $ID3v2ShortFrameNameLookup[2]['length'] = 'TLE'; + $ID3v2ShortFrameNameLookup[2]['original_artist'] = 'TOA'; + $ID3v2ShortFrameNameLookup[2]['original_filename'] = 'TOF'; + $ID3v2ShortFrameNameLookup[2]['original_lyricist'] = 'TOL'; + $ID3v2ShortFrameNameLookup[2]['original_album_title'] = 'TOT'; + $ID3v2ShortFrameNameLookup[2]['artist'] = 'TP1'; + $ID3v2ShortFrameNameLookup[2]['band'] = 'TP2'; + $ID3v2ShortFrameNameLookup[2]['conductor'] = 'TP3'; + $ID3v2ShortFrameNameLookup[2]['remixer'] = 'TP4'; + $ID3v2ShortFrameNameLookup[2]['publisher'] = 'TPB'; + $ID3v2ShortFrameNameLookup[2]['isrc'] = 'TRC'; + $ID3v2ShortFrameNameLookup[2]['tracknumber'] = 'TRK'; + $ID3v2ShortFrameNameLookup[2]['size'] = 'TSI'; + $ID3v2ShortFrameNameLookup[2]['encoder_settings'] = 'TSS'; + $ID3v2ShortFrameNameLookup[2]['description'] = 'TT1'; + $ID3v2ShortFrameNameLookup[2]['title'] = 'TT2'; + $ID3v2ShortFrameNameLookup[2]['subtitle'] = 'TT3'; + $ID3v2ShortFrameNameLookup[2]['lyricist'] = 'TXT'; + $ID3v2ShortFrameNameLookup[2]['user_text'] = 'TXX'; + $ID3v2ShortFrameNameLookup[2]['year'] = 'TYE'; + $ID3v2ShortFrameNameLookup[2]['unique_file_identifier'] = 'UFI'; + $ID3v2ShortFrameNameLookup[2]['unsynchronised_lyrics'] = 'ULT'; + $ID3v2ShortFrameNameLookup[2]['url_file'] = 'WAF'; + $ID3v2ShortFrameNameLookup[2]['url_artist'] = 'WAR'; + $ID3v2ShortFrameNameLookup[2]['url_source'] = 'WAS'; + $ID3v2ShortFrameNameLookup[2]['copyright_information'] = 'WCP'; + $ID3v2ShortFrameNameLookup[2]['url_publisher'] = 'WPB'; + $ID3v2ShortFrameNameLookup[2]['url_user'] = 'WXX'; + + // The following are common to ID3v2.3 and ID3v2.4 + $ID3v2ShortFrameNameLookup[3]['audio_encryption'] = 'AENC'; + $ID3v2ShortFrameNameLookup[3]['attached_picture'] = 'APIC'; + $ID3v2ShortFrameNameLookup[3]['comment'] = 'COMM'; + $ID3v2ShortFrameNameLookup[3]['commercial'] = 'COMR'; + $ID3v2ShortFrameNameLookup[3]['encryption_method_registration'] = 'ENCR'; + $ID3v2ShortFrameNameLookup[3]['event_timing_codes'] = 'ETCO'; + $ID3v2ShortFrameNameLookup[3]['general_encapsulated_object'] = 'GEOB'; + $ID3v2ShortFrameNameLookup[3]['group_identification_registration'] = 'GRID'; + $ID3v2ShortFrameNameLookup[3]['linked_information'] = 'LINK'; + $ID3v2ShortFrameNameLookup[3]['music_cd_identifier'] = 'MCDI'; + $ID3v2ShortFrameNameLookup[3]['mpeg_location_lookup_table'] = 'MLLT'; + $ID3v2ShortFrameNameLookup[3]['ownership'] = 'OWNE'; + $ID3v2ShortFrameNameLookup[3]['play_counter'] = 'PCNT'; + $ID3v2ShortFrameNameLookup[3]['popularimeter'] = 'POPM'; + $ID3v2ShortFrameNameLookup[3]['position_synchronisation'] = 'POSS'; + $ID3v2ShortFrameNameLookup[3]['private'] = 'PRIV'; + $ID3v2ShortFrameNameLookup[3]['recommended_buffer_size'] = 'RBUF'; + $ID3v2ShortFrameNameLookup[3]['reverb'] = 'RVRB'; + $ID3v2ShortFrameNameLookup[3]['synchronised_lyrics'] = 'SYLT'; + $ID3v2ShortFrameNameLookup[3]['synchronised_tempo_codes'] = 'SYTC'; + $ID3v2ShortFrameNameLookup[3]['album'] = 'TALB'; + $ID3v2ShortFrameNameLookup[3]['beats_per_minute'] = 'TBPM'; + $ID3v2ShortFrameNameLookup[3]['itunescompilation'] = 'TCMP'; + $ID3v2ShortFrameNameLookup[3]['composer'] = 'TCOM'; + $ID3v2ShortFrameNameLookup[3]['genre'] = 'TCON'; + $ID3v2ShortFrameNameLookup[3]['copyright'] = 'TCOP'; + $ID3v2ShortFrameNameLookup[3]['playlist_delay'] = 'TDLY'; + $ID3v2ShortFrameNameLookup[3]['encoded_by'] = 'TENC'; + $ID3v2ShortFrameNameLookup[3]['lyricist'] = 'TEXT'; + $ID3v2ShortFrameNameLookup[3]['file_type'] = 'TFLT'; + $ID3v2ShortFrameNameLookup[3]['content_group_description'] = 'TIT1'; + $ID3v2ShortFrameNameLookup[3]['title'] = 'TIT2'; + $ID3v2ShortFrameNameLookup[3]['subtitle'] = 'TIT3'; + $ID3v2ShortFrameNameLookup[3]['initial_key'] = 'TKEY'; + $ID3v2ShortFrameNameLookup[3]['language'] = 'TLAN'; + $ID3v2ShortFrameNameLookup[3]['length'] = 'TLEN'; + $ID3v2ShortFrameNameLookup[3]['media_type'] = 'TMED'; + $ID3v2ShortFrameNameLookup[3]['original_album_title'] = 'TOAL'; + $ID3v2ShortFrameNameLookup[3]['original_filename'] = 'TOFN'; + $ID3v2ShortFrameNameLookup[3]['original_lyricist'] = 'TOLY'; + $ID3v2ShortFrameNameLookup[3]['original_artist'] = 'TOPE'; + $ID3v2ShortFrameNameLookup[3]['file_owner'] = 'TOWN'; + $ID3v2ShortFrameNameLookup[3]['artist'] = 'TPE1'; + $ID3v2ShortFrameNameLookup[3]['band'] = 'TPE2'; + $ID3v2ShortFrameNameLookup[3]['conductor'] = 'TPE3'; + $ID3v2ShortFrameNameLookup[3]['remixer'] = 'TPE4'; + $ID3v2ShortFrameNameLookup[3]['part_of_a_set'] = 'TPOS'; + $ID3v2ShortFrameNameLookup[3]['publisher'] = 'TPUB'; + $ID3v2ShortFrameNameLookup[3]['tracknumber'] = 'TRCK'; + $ID3v2ShortFrameNameLookup[3]['internet_radio_station_name'] = 'TRSN'; + $ID3v2ShortFrameNameLookup[3]['internet_radio_station_owner'] = 'TRSO'; + $ID3v2ShortFrameNameLookup[3]['isrc'] = 'TSRC'; + $ID3v2ShortFrameNameLookup[3]['encoder_settings'] = 'TSSE'; + $ID3v2ShortFrameNameLookup[3]['user_text'] = 'TXXX'; + $ID3v2ShortFrameNameLookup[3]['unique_file_identifier'] = 'UFID'; + $ID3v2ShortFrameNameLookup[3]['terms_of_use'] = 'USER'; + $ID3v2ShortFrameNameLookup[3]['unsynchronised_lyrics'] = 'USLT'; + $ID3v2ShortFrameNameLookup[3]['commercial'] = 'WCOM'; + $ID3v2ShortFrameNameLookup[3]['copyright_information'] = 'WCOP'; + $ID3v2ShortFrameNameLookup[3]['url_file'] = 'WOAF'; + $ID3v2ShortFrameNameLookup[3]['url_artist'] = 'WOAR'; + $ID3v2ShortFrameNameLookup[3]['url_source'] = 'WOAS'; + $ID3v2ShortFrameNameLookup[3]['url_station'] = 'WORS'; + $ID3v2ShortFrameNameLookup[3]['payment'] = 'WPAY'; + $ID3v2ShortFrameNameLookup[3]['url_publisher'] = 'WPUB'; + $ID3v2ShortFrameNameLookup[3]['url_user'] = 'WXXX'; + + // The above are common to ID3v2.3 and ID3v2.4 + // so copy them to ID3v2.4 before adding specifics for 2.3 and 2.4 + $ID3v2ShortFrameNameLookup[4] = $ID3v2ShortFrameNameLookup[3]; + + // The following are unique to ID3v2.3 + $ID3v2ShortFrameNameLookup[3]['equalisation'] = 'EQUA'; + $ID3v2ShortFrameNameLookup[3]['involved_people_list'] = 'IPLS'; + $ID3v2ShortFrameNameLookup[3]['relative_volume_adjustment'] = 'RVAD'; + $ID3v2ShortFrameNameLookup[3]['date'] = 'TDAT'; + $ID3v2ShortFrameNameLookup[3]['time'] = 'TIME'; + $ID3v2ShortFrameNameLookup[3]['original_release_year'] = 'TORY'; + $ID3v2ShortFrameNameLookup[3]['recording_dates'] = 'TRDA'; + $ID3v2ShortFrameNameLookup[3]['size'] = 'TSIZ'; + $ID3v2ShortFrameNameLookup[3]['year'] = 'TYER'; + + + // The following are unique to ID3v2.4 + $ID3v2ShortFrameNameLookup[4]['audio_seek_point_index'] = 'ASPI'; + $ID3v2ShortFrameNameLookup[4]['equalisation'] = 'EQU2'; + $ID3v2ShortFrameNameLookup[4]['relative_volume_adjustment'] = 'RVA2'; + $ID3v2ShortFrameNameLookup[4]['seek'] = 'SEEK'; + $ID3v2ShortFrameNameLookup[4]['signature'] = 'SIGN'; + $ID3v2ShortFrameNameLookup[4]['encoding_time'] = 'TDEN'; + $ID3v2ShortFrameNameLookup[4]['original_release_time'] = 'TDOR'; + $ID3v2ShortFrameNameLookup[4]['recording_time'] = 'TDRC'; + $ID3v2ShortFrameNameLookup[4]['release_time'] = 'TDRL'; + $ID3v2ShortFrameNameLookup[4]['tagging_time'] = 'TDTG'; + $ID3v2ShortFrameNameLookup[4]['involved_people_list'] = 'TIPL'; + $ID3v2ShortFrameNameLookup[4]['musician_credits_list'] = 'TMCL'; + $ID3v2ShortFrameNameLookup[4]['mood'] = 'TMOO'; + $ID3v2ShortFrameNameLookup[4]['produced_notice'] = 'TPRO'; + $ID3v2ShortFrameNameLookup[4]['album_sort_order'] = 'TSOA'; + $ID3v2ShortFrameNameLookup[4]['performer_sort_order'] = 'TSOP'; + $ID3v2ShortFrameNameLookup[4]['title_sort_order'] = 'TSOT'; + $ID3v2ShortFrameNameLookup[4]['set_subtitle'] = 'TSST'; + } + return (isset($ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)]) ? $ID3v2ShortFrameNameLookup[$majorversion][strtolower($long_description)] : ''); + + } + +} + diff --git a/app/libs/vendor/getid3/write.lyrics3.php b/app/libs/vendor/getid3/write.lyrics3.php index 223c1f99..1f85ebd0 100644 --- a/app/libs/vendor/getid3/write.lyrics3.php +++ b/app/libs/vendor/getid3/write.lyrics3.php @@ -1,71 +1,71 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.lyrics3.php // -// module for writing Lyrics3 tags // -// dependencies: module.tag.lyrics3.php // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_write_lyrics3 -{ - public $filename; - public $tag_data; - //public $lyrics3_version = 2; // 1 or 2 - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_lyrics3() { - return true; - } - - public function WriteLyrics3() { - $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3'; - return false; - } - public function DeleteLyrics3() { - // Initialize getID3 engine - $getID3 = new getID3; - $ThisFileInfo = $getID3->analyze($this->filename); - if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { - if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { - - flock($fp, LOCK_EX); - $oldignoreuserabort = ignore_user_abort(true); - - fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end'], SEEK_SET); - $DataAfterLyrics3 = ''; - if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) { - $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']); - } - - ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); - - if (!empty($DataAfterLyrics3)) { - fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start'], SEEK_SET); - fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3)); - } - - flock($fp, LOCK_UN); - fclose($fp); - ignore_user_abort($oldignoreuserabort); - - return true; - - } else { - $this->errors[] = 'Cannot fopen('.$this->filename.', "a+b")'; - return false; - } - } - // no Lyrics3 present - return true; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.lyrics3.php // +// module for writing Lyrics3 tags // +// dependencies: module.tag.lyrics3.php // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_lyrics3 +{ + public $filename; + public $tag_data; + //public $lyrics3_version = 2; // 1 or 2 + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_lyrics3() { + return true; + } + + public function WriteLyrics3() { + $this->errors[] = 'WriteLyrics3() not yet functional - cannot write Lyrics3'; + return false; + } + public function DeleteLyrics3() { + // Initialize getID3 engine + $getID3 = new getID3; + $ThisFileInfo = $getID3->analyze($this->filename); + if (isset($ThisFileInfo['lyrics3']['tag_offset_start']) && isset($ThisFileInfo['lyrics3']['tag_offset_end'])) { + if (is_readable($this->filename) && is_writable($this->filename) && is_file($this->filename) && ($fp = fopen($this->filename, 'a+b'))) { + + flock($fp, LOCK_EX); + $oldignoreuserabort = ignore_user_abort(true); + + fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_end'], SEEK_SET); + $DataAfterLyrics3 = ''; + if ($ThisFileInfo['filesize'] > $ThisFileInfo['lyrics3']['tag_offset_end']) { + $DataAfterLyrics3 = fread($fp, $ThisFileInfo['filesize'] - $ThisFileInfo['lyrics3']['tag_offset_end']); + } + + ftruncate($fp, $ThisFileInfo['lyrics3']['tag_offset_start']); + + if (!empty($DataAfterLyrics3)) { + fseek($fp, $ThisFileInfo['lyrics3']['tag_offset_start'], SEEK_SET); + fwrite($fp, $DataAfterLyrics3, strlen($DataAfterLyrics3)); + } + + flock($fp, LOCK_UN); + fclose($fp); + ignore_user_abort($oldignoreuserabort); + + return true; + + } else { + $this->errors[] = 'Cannot fopen('.$this->filename.', "a+b")'; + return false; + } + } + // no Lyrics3 present + return true; + } + +} diff --git a/app/libs/vendor/getid3/write.metaflac.php b/app/libs/vendor/getid3/write.metaflac.php index 26039a84..f3ce505f 100644 --- a/app/libs/vendor/getid3/write.metaflac.php +++ b/app/libs/vendor/getid3/write.metaflac.php @@ -1,161 +1,161 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.metaflac.php // -// module for writing metaflac tags // -// dependencies: /helperapps/metaflac.exe // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_write_metaflac -{ - - public $filename; - public $tag_data; - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_metaflac() { - return true; - } - - public function WriteMetaFLAC() { - - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written'; - return false; - } - - // Create file with new comments - $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); - if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { - foreach ($this->tag_data as $key => $value) { - foreach ($value as $commentdata) { - fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n"); - } - } - fclose($fpcomments); - - } else { - $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$tempcommentsfilename.'", "wb")'; - return false; - } - - $oldignoreuserabort = ignore_user_abort(true); - if (GETID3_OS_ISWINDOWS) { - - if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { - //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; - // metaflac works fine if you copy-paste the above commandline into a command prompt, - // but refuses to work with `backtick` if there are "doublequotes" present around BOTH - // the metaflac pathname and the target filename. For whatever reason...?? - // The solution is simply ensure that the metaflac pathname has no spaces, - // and therefore does not need to be quoted - - // On top of that, if error messages are not always captured properly under Windows - // To at least see if there was a problem, compare file modification timestamps before and after writing - clearstatcache(); - $timestampbeforewriting = filemtime($this->filename); - - $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1'; - $metaflacError = `$commandline`; - - if (empty($metaflacError)) { - clearstatcache(); - if ($timestampbeforewriting == filemtime($this->filename)) { - $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; - } - } - } else { - $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; - } - - } else { - - // It's simpler on *nix - $commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1'; - $metaflacError = `$commandline`; - - } - - // Remove temporary comments file - unlink($tempcommentsfilename); - ignore_user_abort($oldignoreuserabort); - - if (!empty($metaflacError)) { - - $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; - return false; - - } - - return true; - } - - - public function DeleteMetaFLAC() { - - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted'; - return false; - } - - $oldignoreuserabort = ignore_user_abort(true); - if (GETID3_OS_ISWINDOWS) { - - if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { - // To at least see if there was a problem, compare file modification timestamps before and after writing - clearstatcache(); - $timestampbeforewriting = filemtime($this->filename); - - $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1'; - $metaflacError = `$commandline`; - - if (empty($metaflacError)) { - clearstatcache(); - if ($timestampbeforewriting == filemtime($this->filename)) { - $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted'; - } - } - } else { - $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; - } - - } else { - - // It's simpler on *nix - $commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1'; - $metaflacError = `$commandline`; - - } - - ignore_user_abort($oldignoreuserabort); - - if (!empty($metaflacError)) { - $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; - return false; - } - return true; - } - - - public function CleanmetaflacName($originalcommentname) { - // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. - // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through - // 0x7A inclusive (a-z). - - // replace invalid chars with a space, return uppercase text - // Thanks Chris Bolt for improving this function - // note: *reg_replace() replaces nulls with empty string (not space) - return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.metaflac.php // +// module for writing metaflac tags // +// dependencies: /helperapps/metaflac.exe // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_metaflac +{ + + public $filename; + public $tag_data; + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_metaflac() { + return true; + } + + public function WriteMetaFLAC() { + + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not written'; + return false; + } + + // Create file with new comments + $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); + if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { + foreach ($this->tag_data as $key => $value) { + foreach ($value as $commentdata) { + fwrite($fpcomments, $this->CleanmetaflacName($key).'='.$commentdata."\n"); + } + } + fclose($fpcomments); + + } else { + $this->errors[] = 'failed to open temporary tags file, tags not written - fopen("'.$tempcommentsfilename.'", "wb")'; + return false; + } + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { + //$commandline = '"'.GETID3_HELPERAPPSDIR.'metaflac.exe" --no-utf8-convert --remove-all-tags --import-tags-from="'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; + // metaflac works fine if you copy-paste the above commandline into a command prompt, + // but refuses to work with `backtick` if there are "doublequotes" present around BOTH + // the metaflac pathname and the target filename. For whatever reason...?? + // The solution is simply ensure that the metaflac pathname has no spaces, + // and therefore does not need to be quoted + + // On top of that, if error messages are not always captured properly under Windows + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1'; + $metaflacError = `$commandline`; + + if (empty($metaflacError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not written'; + } + } + } else { + $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + // It's simpler on *nix + $commandline = 'metaflac --no-utf8-convert --remove-all-tags --import-tags-from='.escapeshellarg($tempcommentsfilename).' '.escapeshellarg($this->filename).' 2>&1'; + $metaflacError = `$commandline`; + + } + + // Remove temporary comments file + unlink($tempcommentsfilename); + ignore_user_abort($oldignoreuserabort); + + if (!empty($metaflacError)) { + + $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; + return false; + + } + + return true; + } + + + public function DeleteMetaFLAC() { + + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call metaflac, tags not deleted'; + return false; + } + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'metaflac.exe')) { + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'metaflac.exe --remove-all-tags "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + if (empty($metaflacError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $metaflacError = 'File modification timestamp has not changed - it looks like the tags were not deleted'; + } + } + } else { + $metaflacError = 'metaflac.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + // It's simpler on *nix + $commandline = 'metaflac --remove-all-tags "'.$this->filename.'" 2>&1'; + $metaflacError = `$commandline`; + + } + + ignore_user_abort($oldignoreuserabort); + + if (!empty($metaflacError)) { + $this->errors[] = 'System call to metaflac failed with this message returned: '."\n\n".$metaflacError; + return false; + } + return true; + } + + + public function CleanmetaflacName($originalcommentname) { + // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through + // 0x7A inclusive (a-z). + + // replace invalid chars with a space, return uppercase text + // Thanks Chris Bolt for improving this function + // note: *reg_replace() replaces nulls with empty string (not space) + return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); + + } + +} diff --git a/app/libs/vendor/getid3/write.php b/app/libs/vendor/getid3/write.php index 3f1270e4..3a7f1974 100644 --- a/app/libs/vendor/getid3/write.php +++ b/app/libs/vendor/getid3/write.php @@ -1,613 +1,613 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -/// // -// write.php // -// module for writing tags (APEv2, ID3v1, ID3v2) // -// dependencies: getid3.lib.php // -// write.apetag.php (optional) // -// write.id3v1.php (optional) // -// write.id3v2.php (optional) // -// write.vorbiscomment.php (optional) // -// write.metaflac.php (optional) // -// write.lyrics3.php (optional) // -// /// -///////////////////////////////////////////////////////////////// - -if (!defined('GETID3_INCLUDEPATH')) { - throw new Exception('getid3.php MUST be included before calling getid3_writetags'); -} -if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { - throw new Exception('write.php depends on getid3.lib.php, which is missing.'); -} - - -// NOTES: -// -// You should pass data here with standard field names as follows: -// * TITLE -// * ARTIST -// * ALBUM -// * TRACKNUMBER -// * COMMENT -// * GENRE -// * YEAR -// * ATTACHED_PICTURE (ID3v2 only) -// -// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html -// The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead -// Pass data here as "TRACKNUMBER" for compatability with all formats - - -class getid3_writetags -{ - // public - public $filename; // absolute filename of file to write tags to - public $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real') - public $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis') - public $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', ) - public $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data - public $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats - - public $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html) - public $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter) - - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - // private - private $ThisFileInfo; // analysis of file before writing - - public function getid3_writetags() { - return true; - } - - - public function WriteTags() { - - if (empty($this->filename)) { - $this->errors[] = 'filename is undefined in getid3_writetags'; - return false; - } elseif (!file_exists($this->filename)) { - $this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags'; - return false; - } - - if (!is_array($this->tagformats)) { - $this->errors[] = 'tagformats must be an array in getid3_writetags'; - return false; - } - - $TagFormatsToRemove = array(); - if (filesize($this->filename) == 0) { - - // empty file special case - allow any tag format, don't check existing format - // could be useful if you want to generate tag data for a non-existant file - $this->ThisFileInfo = array('fileformat'=>''); - $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); - - } else { - - $getID3 = new getID3; - $getID3->encoding = $this->tag_encoding; - $this->ThisFileInfo = $getID3->analyze($this->filename); - - // check for what file types are allowed on this fileformat - switch (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '') { - case 'mp3': - case 'mp2': - case 'mp1': - case 'riff': // maybe not officially, but people do it anyway - $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); - break; - - case 'mpc': - $AllowedTagFormats = array('ape'); - break; - - case 'flac': - $AllowedTagFormats = array('metaflac'); - break; - - case 'real': - $AllowedTagFormats = array('real'); - break; - - case 'ogg': - switch (isset($this->ThisFileInfo['audio']['dataformat']) ? $this->ThisFileInfo['audio']['dataformat'] : '') { - case 'flac': - //$AllowedTagFormats = array('metaflac'); - $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files'; - return false; - break; - case 'vorbis': - $AllowedTagFormats = array('vorbiscomment'); - break; - default: - $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis'; - return false; - break; - } - break; - - default: - $AllowedTagFormats = array(); - break; - } - foreach ($this->tagformats as $requested_tag_format) { - if (!in_array($requested_tag_format, $AllowedTagFormats)) { - $errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.(isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : ''); - $errormessage .= (isset($this->ThisFileInfo['audio']['dataformat']) ? '.'.$this->ThisFileInfo['audio']['dataformat'] : ''); - $errormessage .= '" files'; - $this->errors[] = $errormessage; - return false; - } - } - - // List of other tag formats, removed if requested - if ($this->remove_other_tags) { - foreach ($AllowedTagFormats as $AllowedTagFormat) { - switch ($AllowedTagFormat) { - case 'id3v2.2': - case 'id3v2.3': - case 'id3v2.4': - if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) { - $TagFormatsToRemove[] = 'id3v2'; - } - break; - - default: - if (!in_array($AllowedTagFormat, $this->tagformats)) { - $TagFormatsToRemove[] = $AllowedTagFormat; - } - break; - } - } - } - } - - $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove); - - // Check for required include files and include them - foreach ($WritingFilesToInclude as $tagformat) { - switch ($tagformat) { - case 'ape': - $GETID3_ERRORARRAY = &$this->errors; - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, false)) { - return false; - } - break; - - case 'id3v1': - case 'lyrics3': - case 'vorbiscomment': - case 'metaflac': - case 'real': - $GETID3_ERRORARRAY = &$this->errors; - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, false)) { - return false; - } - break; - - case 'id3v2.2': - case 'id3v2.3': - case 'id3v2.4': - case 'id3v2': - $GETID3_ERRORARRAY = &$this->errors; - if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, false)) { - return false; - } - break; - - default: - $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()'; - return false; - break; - } - - } - - // Validation of supplied data - if (!is_array($this->tag_data)) { - $this->errors[] = '$this->tag_data is not an array in WriteTags()'; - return false; - } - // convert supplied data array keys to upper case, if they're not already - foreach ($this->tag_data as $tag_key => $tag_array) { - if (strtoupper($tag_key) !== $tag_key) { - $this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key]; - unset($this->tag_data[$tag_key]); - } - } - // convert source data array keys to upper case, if they're not already - if (!empty($this->ThisFileInfo['tags'])) { - foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) { - foreach ($tag_data_array as $tag_key => $tag_array) { - if (strtoupper($tag_key) !== $tag_key) { - $this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key]; - unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]); - } - } - } - } - - // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats - if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) { - $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK']; - unset($this->tag_data['TRACK']); - } - - // Remove all other tag formats, if requested - if ($this->remove_other_tags) { - $this->DeleteTags($TagFormatsToRemove); - } - - // Write data for each tag format - foreach ($this->tagformats as $tagformat) { - $success = false; // overridden if tag writing is successful - switch ($tagformat) { - case 'ape': - $ape_writer = new getid3_write_apetag; - if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) { - $ape_writer->filename = $this->filename; - if (($success = $ape_writer->WriteAPEtag()) === false) { - $this->errors[] = 'WriteAPEtag() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $ape_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForAPE() failed'; - } - break; - - case 'id3v1': - $id3v1_writer = new getid3_write_id3v1; - if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) { - $id3v1_writer->filename = $this->filename; - if (($success = $id3v1_writer->WriteID3v1()) === false) { - $this->errors[] = 'WriteID3v1() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $id3v1_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForID3v1() failed'; - } - break; - - case 'id3v2.2': - case 'id3v2.3': - case 'id3v2.4': - $id3v2_writer = new getid3_write_id3v2; - $id3v2_writer->majorversion = intval(substr($tagformat, -1)); - $id3v2_writer->paddedlength = $this->id3v2_paddedlength; - if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) { - $id3v2_writer->filename = $this->filename; - if (($success = $id3v2_writer->WriteID3v2()) === false) { - $this->errors[] = 'WriteID3v2() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $id3v2_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForID3v2() failed'; - } - break; - - case 'vorbiscomment': - $vorbiscomment_writer = new getid3_write_vorbiscomment; - if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) { - $vorbiscomment_writer->filename = $this->filename; - if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) { - $this->errors[] = 'WriteVorbisComment() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $vorbiscomment_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForVorbisComment() failed'; - } - break; - - case 'metaflac': - $metaflac_writer = new getid3_write_metaflac; - if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) { - $metaflac_writer->filename = $this->filename; - if (($success = $metaflac_writer->WriteMetaFLAC()) === false) { - $this->errors[] = 'WriteMetaFLAC() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $metaflac_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForMetaFLAC() failed'; - } - break; - - case 'real': - $real_writer = new getid3_write_real; - if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) { - $real_writer->filename = $this->filename; - if (($success = $real_writer->WriteReal()) === false) { - $this->errors[] = 'WriteReal() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $real_writer->errors)))).'
    '; - } - } else { - $this->errors[] = 'FormatDataForReal() failed'; - } - break; - - default: - $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"'; - return false; - break; - } - if (!$success) { - return false; - } - } - return true; - - } - - - public function DeleteTags($TagFormatsToDelete) { - foreach ($TagFormatsToDelete as $DeleteTagFormat) { - $success = false; // overridden if tag deletion is successful - switch ($DeleteTagFormat) { - case 'id3v1': - $id3v1_writer = new getid3_write_id3v1; - $id3v1_writer->filename = $this->filename; - if (($success = $id3v1_writer->RemoveID3v1()) === false) { - $this->errors[] = 'RemoveID3v1() failed with message(s):
    • '.trim(implode('
    • ', $id3v1_writer->errors)).'
    '; - } - break; - - case 'id3v2': - $id3v2_writer = new getid3_write_id3v2; - $id3v2_writer->filename = $this->filename; - if (($success = $id3v2_writer->RemoveID3v2()) === false) { - $this->errors[] = 'RemoveID3v2() failed with message(s):
    • '.trim(implode('
    • ', $id3v2_writer->errors)).'
    '; - } - break; - - case 'ape': - $ape_writer = new getid3_write_apetag; - $ape_writer->filename = $this->filename; - if (($success = $ape_writer->DeleteAPEtag()) === false) { - $this->errors[] = 'DeleteAPEtag() failed with message(s):
    • '.trim(implode('
    • ', $ape_writer->errors)).'
    '; - } - break; - - case 'vorbiscomment': - $vorbiscomment_writer = new getid3_write_vorbiscomment; - $vorbiscomment_writer->filename = $this->filename; - if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) { - $this->errors[] = 'DeleteVorbisComment() failed with message(s):
    • '.trim(implode('
    • ', $vorbiscomment_writer->errors)).'
    '; - } - break; - - case 'metaflac': - $metaflac_writer = new getid3_write_metaflac; - $metaflac_writer->filename = $this->filename; - if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) { - $this->errors[] = 'DeleteMetaFLAC() failed with message(s):
    • '.trim(implode('
    • ', $metaflac_writer->errors)).'
    '; - } - break; - - case 'lyrics3': - $lyrics3_writer = new getid3_write_lyrics3; - $lyrics3_writer->filename = $this->filename; - if (($success = $lyrics3_writer->DeleteLyrics3()) === false) { - $this->errors[] = 'DeleteLyrics3() failed with message(s):
    • '.trim(implode('
    • ', $lyrics3_writer->errors)).'
    '; - } - break; - - case 'real': - $real_writer = new getid3_write_real; - $real_writer->filename = $this->filename; - if (($success = $real_writer->RemoveReal()) === false) { - $this->errors[] = 'RemoveReal() failed with message(s):
    • '.trim(implode('
    • ', $real_writer->errors)).'
    '; - } - break; - - default: - $this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"'; - return false; - break; - } - if (!$success) { - return false; - } - } - return true; - } - - - public function MergeExistingTagData($TagFormat, &$tag_data) { - // Merge supplied data with existing data, if requested - if ($this->overwrite_tags) { - // do nothing - ignore previous data - } else { -throw new Exception('$this->overwrite_tags=false is known to be buggy in this version of getID3. Will be fixed in the near future, check www.getid3.org for a newer version.'); - if (!isset($this->ThisFileInfo['tags'][$TagFormat])) { - return false; - } - $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]); - } - return true; - } - - public function FormatDataForAPE() { - $ape_tag_data = array(); - foreach ($this->tag_data as $tag_key => $valuearray) { - switch ($tag_key) { - case 'ATTACHED_PICTURE': - // ATTACHED_PICTURE is ID3v2 only - ignore - $this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag'; - break; - - default: - foreach ($valuearray as $key => $value) { - if (is_string($value) || is_numeric($value)) { - $ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); - } else { - $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag'; - unset($ape_tag_data[$tag_key]); - break; - } - } - break; - } - } - $this->MergeExistingTagData('ape', $ape_tag_data); - return $ape_tag_data; - } - - - public function FormatDataForID3v1() { - $tag_data_id3v1['genreid'] = 255; - if (!empty($this->tag_data['GENRE'])) { - foreach ($this->tag_data['GENRE'] as $key => $value) { - if (getid3_id3v1::LookupGenreID($value) !== false) { - $tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value); - break; - } - } - } - $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array()))); - $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array()))); - $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM'] ) ? $this->tag_data['ALBUM'] : array()))); - $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR'] ) ? $this->tag_data['YEAR'] : array()))); - $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array()))); - $tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACKNUMBER']) ? $this->tag_data['TRACKNUMBER'] : array())))); - if ($tag_data_id3v1['track'] <= 0) { - $tag_data_id3v1['track'] = ''; - } - - $this->MergeExistingTagData('id3v1', $tag_data_id3v1); - return $tag_data_id3v1; - } - - public function FormatDataForID3v2($id3v2_majorversion) { - $tag_data_id3v2 = array(); - - $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1); - $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1); - $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3); - foreach ($this->tag_data as $tag_key => $valuearray) { - $ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key); - switch ($ID3v2_framename) { - case 'APIC': - foreach ($valuearray as $key => $apic_data_array) { - if (isset($apic_data_array['data']) && - isset($apic_data_array['picturetypeid']) && - isset($apic_data_array['description']) && - isset($apic_data_array['mime'])) { - $tag_data_id3v2['APIC'][] = $apic_data_array; - } else { - $this->errors[] = 'ID3v2 APIC data is not properly structured'; - return false; - } - } - break; - - case '': - $this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type'; - // some other data type, don't know how to handle it, ignore it - break; - - default: - // most other (text) frames can be copied over as-is - foreach ($valuearray as $key => $value) { - if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) { - // source encoding is valid in ID3v2 - use it with no conversion - $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding]; - $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; - } else { - // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first - if ($id3v2_majorversion < 4) { - // convert data from other encoding to UTF-16 (with BOM) - // note: some software, notably Windows Media Player and iTunes are broken and treat files tagged with UTF-16BE (with BOM) as corrupt - // therefore we force data to UTF-16LE and manually prepend the BOM - $ID3v2_tag_data_converted = false; - if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'ISO-8859-1')) { - // great, leave data as-is for minimum compatability problems - $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; - $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; - $ID3v2_tag_data_converted = true; - } - if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'UTF-8')) { - do { - // if UTF-8 string does not include any characters above chr(127) then it is identical to ISO-8859-1 - for ($i = 0; $i < strlen($value); $i++) { - if (ord($value{$i}) > 127) { - break 2; - } - } - $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; - $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; - $ID3v2_tag_data_converted = true; - } while (false); - } - if (!$ID3v2_tag_data_converted) { - $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1; - //$tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value); // output is UTF-16LE+BOM or UTF-16BE+BOM depending on system architecture - $tag_data_id3v2[$ID3v2_framename][$key]['data'] = "\xFF\xFE".getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16LE', $value); // force LittleEndian order version of UTF-16 - $ID3v2_tag_data_converted = true; - } - - } else { - // convert data from other encoding to UTF-8 - $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3; - $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); - } - } - - // These values are not needed for all frame types, but if they're not used no matter - $tag_data_id3v2[$ID3v2_framename][$key]['description'] = ''; - $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language; - } - break; - } - } - $this->MergeExistingTagData('id3v2', $tag_data_id3v2); - return $tag_data_id3v2; - } - - public function FormatDataForVorbisComment() { - $tag_data_vorbiscomment = $this->tag_data; - - // check for multi-line comment values - split out to multiple comments if neccesary - // and convert data to UTF-8 strings - foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) { - foreach ($valuearray as $key => $value) { - str_replace("\r", "\n", $value); - if (strstr($value, "\n")) { - unset($tag_data_vorbiscomment[$tag_key][$key]); - $multilineexploded = explode("\n", $value); - foreach ($multilineexploded as $newcomment) { - if (strlen(trim($newcomment)) > 0) { - $tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment); - } - } - } elseif (is_string($value) || is_numeric($value)) { - $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); - } else { - $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag'; - unset($tag_data_vorbiscomment[$tag_key]); - break; - } - } - } - $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment); - return $tag_data_vorbiscomment; - } - - public function FormatDataForMetaFLAC() { - // FLAC & OggFLAC use VorbisComments same as OggVorbis - // but require metaflac to do the writing rather than vorbiscomment - return $this->FormatDataForVorbisComment(); - } - - public function FormatDataForReal() { - $tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array()))); - $tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array()))); - $tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COPYRIGHT']) ? $this->tag_data['COPYRIGHT'] : array()))); - $tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array()))); - - $this->MergeExistingTagData('real', $tag_data_real); - return $tag_data_real; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +/// // +// write.php // +// module for writing tags (APEv2, ID3v1, ID3v2) // +// dependencies: getid3.lib.php // +// write.apetag.php (optional) // +// write.id3v1.php (optional) // +// write.id3v2.php (optional) // +// write.vorbiscomment.php (optional) // +// write.metaflac.php (optional) // +// write.lyrics3.php (optional) // +// /// +///////////////////////////////////////////////////////////////// + +if (!defined('GETID3_INCLUDEPATH')) { + throw new Exception('getid3.php MUST be included before calling getid3_writetags'); +} +if (!include_once(GETID3_INCLUDEPATH.'getid3.lib.php')) { + throw new Exception('write.php depends on getid3.lib.php, which is missing.'); +} + + +// NOTES: +// +// You should pass data here with standard field names as follows: +// * TITLE +// * ARTIST +// * ALBUM +// * TRACKNUMBER +// * COMMENT +// * GENRE +// * YEAR +// * ATTACHED_PICTURE (ID3v2 only) +// +// http://www.personal.uni-jena.de/~pfk/mpp/sv8/apekey.html +// The APEv2 Tag Items Keys definition says "TRACK" is correct but foobar2000 uses "TRACKNUMBER" instead +// Pass data here as "TRACKNUMBER" for compatability with all formats + + +class getid3_writetags +{ + // public + public $filename; // absolute filename of file to write tags to + public $tagformats = array(); // array of tag formats to write ('id3v1', 'id3v2.2', 'id2v2.3', 'id3v2.4', 'ape', 'vorbiscomment', 'metaflac', 'real') + public $tag_data = array(array()); // 2-dimensional array of tag data (ex: $data['ARTIST'][0] = 'Elvis') + public $tag_encoding = 'ISO-8859-1'; // text encoding used for tag data ('ISO-8859-1', 'UTF-8', 'UTF-16', 'UTF-16LE', 'UTF-16BE', ) + public $overwrite_tags = true; // if true will erase existing tag data and write only passed data; if false will merge passed data with existing tag data + public $remove_other_tags = false; // if true will erase remove all existing tags and only write those passed in $tagformats; if false will ignore any tags not mentioned in $tagformats + + public $id3v2_tag_language = 'eng'; // ISO-639-2 3-character language code needed for some ID3v2 frames (http://www.id3.org/iso639-2.html) + public $id3v2_paddedlength = 4096; // minimum length of ID3v2 tags (will be padded to this length if tag data is shorter) + + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + // private + private $ThisFileInfo; // analysis of file before writing + + public function getid3_writetags() { + return true; + } + + + public function WriteTags() { + + if (empty($this->filename)) { + $this->errors[] = 'filename is undefined in getid3_writetags'; + return false; + } elseif (!file_exists($this->filename)) { + $this->errors[] = 'filename set to non-existant file "'.$this->filename.'" in getid3_writetags'; + return false; + } + + if (!is_array($this->tagformats)) { + $this->errors[] = 'tagformats must be an array in getid3_writetags'; + return false; + } + + $TagFormatsToRemove = array(); + if (filesize($this->filename) == 0) { + + // empty file special case - allow any tag format, don't check existing format + // could be useful if you want to generate tag data for a non-existant file + $this->ThisFileInfo = array('fileformat'=>''); + $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); + + } else { + + $getID3 = new getID3; + $getID3->encoding = $this->tag_encoding; + $this->ThisFileInfo = $getID3->analyze($this->filename); + + // check for what file types are allowed on this fileformat + switch (isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : '') { + case 'mp3': + case 'mp2': + case 'mp1': + case 'riff': // maybe not officially, but people do it anyway + $AllowedTagFormats = array('id3v1', 'id3v2.2', 'id3v2.3', 'id3v2.4', 'ape', 'lyrics3'); + break; + + case 'mpc': + $AllowedTagFormats = array('ape'); + break; + + case 'flac': + $AllowedTagFormats = array('metaflac'); + break; + + case 'real': + $AllowedTagFormats = array('real'); + break; + + case 'ogg': + switch (isset($this->ThisFileInfo['audio']['dataformat']) ? $this->ThisFileInfo['audio']['dataformat'] : '') { + case 'flac': + //$AllowedTagFormats = array('metaflac'); + $this->errors[] = 'metaflac is not (yet) compatible with OggFLAC files'; + return false; + break; + case 'vorbis': + $AllowedTagFormats = array('vorbiscomment'); + break; + default: + $this->errors[] = 'metaflac is not (yet) compatible with Ogg files other than OggVorbis'; + return false; + break; + } + break; + + default: + $AllowedTagFormats = array(); + break; + } + foreach ($this->tagformats as $requested_tag_format) { + if (!in_array($requested_tag_format, $AllowedTagFormats)) { + $errormessage = 'Tag format "'.$requested_tag_format.'" is not allowed on "'.(isset($this->ThisFileInfo['fileformat']) ? $this->ThisFileInfo['fileformat'] : ''); + $errormessage .= (isset($this->ThisFileInfo['audio']['dataformat']) ? '.'.$this->ThisFileInfo['audio']['dataformat'] : ''); + $errormessage .= '" files'; + $this->errors[] = $errormessage; + return false; + } + } + + // List of other tag formats, removed if requested + if ($this->remove_other_tags) { + foreach ($AllowedTagFormats as $AllowedTagFormat) { + switch ($AllowedTagFormat) { + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + if (!in_array('id3v2', $TagFormatsToRemove) && !in_array('id3v2.2', $this->tagformats) && !in_array('id3v2.3', $this->tagformats) && !in_array('id3v2.4', $this->tagformats)) { + $TagFormatsToRemove[] = 'id3v2'; + } + break; + + default: + if (!in_array($AllowedTagFormat, $this->tagformats)) { + $TagFormatsToRemove[] = $AllowedTagFormat; + } + break; + } + } + } + } + + $WritingFilesToInclude = array_merge($this->tagformats, $TagFormatsToRemove); + + // Check for required include files and include them + foreach ($WritingFilesToInclude as $tagformat) { + switch ($tagformat) { + case 'ape': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.apetag.php', __FILE__, false)) { + return false; + } + break; + + case 'id3v1': + case 'lyrics3': + case 'vorbiscomment': + case 'metaflac': + case 'real': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.'.$tagformat.'.php', __FILE__, false)) { + return false; + } + break; + + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + case 'id3v2': + $GETID3_ERRORARRAY = &$this->errors; + if (!getid3_lib::IncludeDependency(GETID3_INCLUDEPATH.'write.id3v2.php', __FILE__, false)) { + return false; + } + break; + + default: + $this->errors[] = 'unknown tag format "'.$tagformat.'" in $tagformats in WriteTags()'; + return false; + break; + } + + } + + // Validation of supplied data + if (!is_array($this->tag_data)) { + $this->errors[] = '$this->tag_data is not an array in WriteTags()'; + return false; + } + // convert supplied data array keys to upper case, if they're not already + foreach ($this->tag_data as $tag_key => $tag_array) { + if (strtoupper($tag_key) !== $tag_key) { + $this->tag_data[strtoupper($tag_key)] = $this->tag_data[$tag_key]; + unset($this->tag_data[$tag_key]); + } + } + // convert source data array keys to upper case, if they're not already + if (!empty($this->ThisFileInfo['tags'])) { + foreach ($this->ThisFileInfo['tags'] as $tag_format => $tag_data_array) { + foreach ($tag_data_array as $tag_key => $tag_array) { + if (strtoupper($tag_key) !== $tag_key) { + $this->ThisFileInfo['tags'][$tag_format][strtoupper($tag_key)] = $this->ThisFileInfo['tags'][$tag_format][$tag_key]; + unset($this->ThisFileInfo['tags'][$tag_format][$tag_key]); + } + } + } + } + + // Convert "TRACK" to "TRACKNUMBER" (if needed) for compatability with all formats + if (isset($this->tag_data['TRACK']) && !isset($this->tag_data['TRACKNUMBER'])) { + $this->tag_data['TRACKNUMBER'] = $this->tag_data['TRACK']; + unset($this->tag_data['TRACK']); + } + + // Remove all other tag formats, if requested + if ($this->remove_other_tags) { + $this->DeleteTags($TagFormatsToRemove); + } + + // Write data for each tag format + foreach ($this->tagformats as $tagformat) { + $success = false; // overridden if tag writing is successful + switch ($tagformat) { + case 'ape': + $ape_writer = new getid3_write_apetag; + if (($ape_writer->tag_data = $this->FormatDataForAPE()) !== false) { + $ape_writer->filename = $this->filename; + if (($success = $ape_writer->WriteAPEtag()) === false) { + $this->errors[] = 'WriteAPEtag() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $ape_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForAPE() failed'; + } + break; + + case 'id3v1': + $id3v1_writer = new getid3_write_id3v1; + if (($id3v1_writer->tag_data = $this->FormatDataForID3v1()) !== false) { + $id3v1_writer->filename = $this->filename; + if (($success = $id3v1_writer->WriteID3v1()) === false) { + $this->errors[] = 'WriteID3v1() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $id3v1_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForID3v1() failed'; + } + break; + + case 'id3v2.2': + case 'id3v2.3': + case 'id3v2.4': + $id3v2_writer = new getid3_write_id3v2; + $id3v2_writer->majorversion = intval(substr($tagformat, -1)); + $id3v2_writer->paddedlength = $this->id3v2_paddedlength; + if (($id3v2_writer->tag_data = $this->FormatDataForID3v2($id3v2_writer->majorversion)) !== false) { + $id3v2_writer->filename = $this->filename; + if (($success = $id3v2_writer->WriteID3v2()) === false) { + $this->errors[] = 'WriteID3v2() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $id3v2_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForID3v2() failed'; + } + break; + + case 'vorbiscomment': + $vorbiscomment_writer = new getid3_write_vorbiscomment; + if (($vorbiscomment_writer->tag_data = $this->FormatDataForVorbisComment()) !== false) { + $vorbiscomment_writer->filename = $this->filename; + if (($success = $vorbiscomment_writer->WriteVorbisComment()) === false) { + $this->errors[] = 'WriteVorbisComment() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $vorbiscomment_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForVorbisComment() failed'; + } + break; + + case 'metaflac': + $metaflac_writer = new getid3_write_metaflac; + if (($metaflac_writer->tag_data = $this->FormatDataForMetaFLAC()) !== false) { + $metaflac_writer->filename = $this->filename; + if (($success = $metaflac_writer->WriteMetaFLAC()) === false) { + $this->errors[] = 'WriteMetaFLAC() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $metaflac_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForMetaFLAC() failed'; + } + break; + + case 'real': + $real_writer = new getid3_write_real; + if (($real_writer->tag_data = $this->FormatDataForReal()) !== false) { + $real_writer->filename = $this->filename; + if (($success = $real_writer->WriteReal()) === false) { + $this->errors[] = 'WriteReal() failed with message(s):
    • '.str_replace("\n", '
    • ', htmlentities(trim(implode("\n", $real_writer->errors)))).'
    '; + } + } else { + $this->errors[] = 'FormatDataForReal() failed'; + } + break; + + default: + $this->errors[] = 'Invalid tag format to write: "'.$tagformat.'"'; + return false; + break; + } + if (!$success) { + return false; + } + } + return true; + + } + + + public function DeleteTags($TagFormatsToDelete) { + foreach ($TagFormatsToDelete as $DeleteTagFormat) { + $success = false; // overridden if tag deletion is successful + switch ($DeleteTagFormat) { + case 'id3v1': + $id3v1_writer = new getid3_write_id3v1; + $id3v1_writer->filename = $this->filename; + if (($success = $id3v1_writer->RemoveID3v1()) === false) { + $this->errors[] = 'RemoveID3v1() failed with message(s):
    • '.trim(implode('
    • ', $id3v1_writer->errors)).'
    '; + } + break; + + case 'id3v2': + $id3v2_writer = new getid3_write_id3v2; + $id3v2_writer->filename = $this->filename; + if (($success = $id3v2_writer->RemoveID3v2()) === false) { + $this->errors[] = 'RemoveID3v2() failed with message(s):
    • '.trim(implode('
    • ', $id3v2_writer->errors)).'
    '; + } + break; + + case 'ape': + $ape_writer = new getid3_write_apetag; + $ape_writer->filename = $this->filename; + if (($success = $ape_writer->DeleteAPEtag()) === false) { + $this->errors[] = 'DeleteAPEtag() failed with message(s):
    • '.trim(implode('
    • ', $ape_writer->errors)).'
    '; + } + break; + + case 'vorbiscomment': + $vorbiscomment_writer = new getid3_write_vorbiscomment; + $vorbiscomment_writer->filename = $this->filename; + if (($success = $vorbiscomment_writer->DeleteVorbisComment()) === false) { + $this->errors[] = 'DeleteVorbisComment() failed with message(s):
    • '.trim(implode('
    • ', $vorbiscomment_writer->errors)).'
    '; + } + break; + + case 'metaflac': + $metaflac_writer = new getid3_write_metaflac; + $metaflac_writer->filename = $this->filename; + if (($success = $metaflac_writer->DeleteMetaFLAC()) === false) { + $this->errors[] = 'DeleteMetaFLAC() failed with message(s):
    • '.trim(implode('
    • ', $metaflac_writer->errors)).'
    '; + } + break; + + case 'lyrics3': + $lyrics3_writer = new getid3_write_lyrics3; + $lyrics3_writer->filename = $this->filename; + if (($success = $lyrics3_writer->DeleteLyrics3()) === false) { + $this->errors[] = 'DeleteLyrics3() failed with message(s):
    • '.trim(implode('
    • ', $lyrics3_writer->errors)).'
    '; + } + break; + + case 'real': + $real_writer = new getid3_write_real; + $real_writer->filename = $this->filename; + if (($success = $real_writer->RemoveReal()) === false) { + $this->errors[] = 'RemoveReal() failed with message(s):
    • '.trim(implode('
    • ', $real_writer->errors)).'
    '; + } + break; + + default: + $this->errors[] = 'Invalid tag format to delete: "'.$tagformat.'"'; + return false; + break; + } + if (!$success) { + return false; + } + } + return true; + } + + + public function MergeExistingTagData($TagFormat, &$tag_data) { + // Merge supplied data with existing data, if requested + if ($this->overwrite_tags) { + // do nothing - ignore previous data + } else { +throw new Exception('$this->overwrite_tags=false is known to be buggy in this version of getID3. Will be fixed in the near future, check www.getid3.org for a newer version.'); + if (!isset($this->ThisFileInfo['tags'][$TagFormat])) { + return false; + } + $tag_data = array_merge_recursive($tag_data, $this->ThisFileInfo['tags'][$TagFormat]); + } + return true; + } + + public function FormatDataForAPE() { + $ape_tag_data = array(); + foreach ($this->tag_data as $tag_key => $valuearray) { + switch ($tag_key) { + case 'ATTACHED_PICTURE': + // ATTACHED_PICTURE is ID3v2 only - ignore + $this->warnings[] = '$data['.$tag_key.'] is assumed to be ID3v2 APIC data - NOT written to APE tag'; + break; + + default: + foreach ($valuearray as $key => $value) { + if (is_string($value) || is_numeric($value)) { + $ape_tag_data[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } else { + $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to APE tag'; + unset($ape_tag_data[$tag_key]); + break; + } + } + break; + } + } + $this->MergeExistingTagData('ape', $ape_tag_data); + return $ape_tag_data; + } + + + public function FormatDataForID3v1() { + $tag_data_id3v1['genreid'] = 255; + if (!empty($this->tag_data['GENRE'])) { + foreach ($this->tag_data['GENRE'] as $key => $value) { + if (getid3_id3v1::LookupGenreID($value) !== false) { + $tag_data_id3v1['genreid'] = getid3_id3v1::LookupGenreID($value); + break; + } + } + } + $tag_data_id3v1['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array()))); + $tag_data_id3v1['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array()))); + $tag_data_id3v1['album'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ALBUM'] ) ? $this->tag_data['ALBUM'] : array()))); + $tag_data_id3v1['year'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['YEAR'] ) ? $this->tag_data['YEAR'] : array()))); + $tag_data_id3v1['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array()))); + $tag_data_id3v1['track'] = intval(getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TRACKNUMBER']) ? $this->tag_data['TRACKNUMBER'] : array())))); + if ($tag_data_id3v1['track'] <= 0) { + $tag_data_id3v1['track'] = ''; + } + + $this->MergeExistingTagData('id3v1', $tag_data_id3v1); + return $tag_data_id3v1; + } + + public function FormatDataForID3v2($id3v2_majorversion) { + $tag_data_id3v2 = array(); + + $ID3v2_text_encoding_lookup[2] = array('ISO-8859-1'=>0, 'UTF-16'=>1); + $ID3v2_text_encoding_lookup[3] = array('ISO-8859-1'=>0, 'UTF-16'=>1); + $ID3v2_text_encoding_lookup[4] = array('ISO-8859-1'=>0, 'UTF-16'=>1, 'UTF-16BE'=>2, 'UTF-8'=>3); + foreach ($this->tag_data as $tag_key => $valuearray) { + $ID3v2_framename = getid3_write_id3v2::ID3v2ShortFrameNameLookup($id3v2_majorversion, $tag_key); + switch ($ID3v2_framename) { + case 'APIC': + foreach ($valuearray as $key => $apic_data_array) { + if (isset($apic_data_array['data']) && + isset($apic_data_array['picturetypeid']) && + isset($apic_data_array['description']) && + isset($apic_data_array['mime'])) { + $tag_data_id3v2['APIC'][] = $apic_data_array; + } else { + $this->errors[] = 'ID3v2 APIC data is not properly structured'; + return false; + } + } + break; + + case '': + $this->errors[] = 'ID3v2: Skipping "'.$tag_key.'" because cannot match it to a known ID3v2 frame type'; + // some other data type, don't know how to handle it, ignore it + break; + + default: + // most other (text) frames can be copied over as-is + foreach ($valuearray as $key => $value) { + if (isset($ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding])) { + // source encoding is valid in ID3v2 - use it with no conversion + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = $ID3v2_text_encoding_lookup[$id3v2_majorversion][$this->tag_encoding]; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; + } else { + // source encoding is NOT valid in ID3v2 - convert it to an ID3v2-valid encoding first + if ($id3v2_majorversion < 4) { + // convert data from other encoding to UTF-16 (with BOM) + // note: some software, notably Windows Media Player and iTunes are broken and treat files tagged with UTF-16BE (with BOM) as corrupt + // therefore we force data to UTF-16LE and manually prepend the BOM + $ID3v2_tag_data_converted = false; + if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'ISO-8859-1')) { + // great, leave data as-is for minimum compatability problems + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; + $ID3v2_tag_data_converted = true; + } + if (!$ID3v2_tag_data_converted && ($this->tag_encoding == 'UTF-8')) { + do { + // if UTF-8 string does not include any characters above chr(127) then it is identical to ISO-8859-1 + for ($i = 0; $i < strlen($value); $i++) { + if (ord($value{$i}) > 127) { + break 2; + } + } + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 0; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = $value; + $ID3v2_tag_data_converted = true; + } while (false); + } + if (!$ID3v2_tag_data_converted) { + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 1; + //$tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16', $value); // output is UTF-16LE+BOM or UTF-16BE+BOM depending on system architecture + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = "\xFF\xFE".getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-16LE', $value); // force LittleEndian order version of UTF-16 + $ID3v2_tag_data_converted = true; + } + + } else { + // convert data from other encoding to UTF-8 + $tag_data_id3v2[$ID3v2_framename][$key]['encodingid'] = 3; + $tag_data_id3v2[$ID3v2_framename][$key]['data'] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } + } + + // These values are not needed for all frame types, but if they're not used no matter + $tag_data_id3v2[$ID3v2_framename][$key]['description'] = ''; + $tag_data_id3v2[$ID3v2_framename][$key]['language'] = $this->id3v2_tag_language; + } + break; + } + } + $this->MergeExistingTagData('id3v2', $tag_data_id3v2); + return $tag_data_id3v2; + } + + public function FormatDataForVorbisComment() { + $tag_data_vorbiscomment = $this->tag_data; + + // check for multi-line comment values - split out to multiple comments if neccesary + // and convert data to UTF-8 strings + foreach ($tag_data_vorbiscomment as $tag_key => $valuearray) { + foreach ($valuearray as $key => $value) { + str_replace("\r", "\n", $value); + if (strstr($value, "\n")) { + unset($tag_data_vorbiscomment[$tag_key][$key]); + $multilineexploded = explode("\n", $value); + foreach ($multilineexploded as $newcomment) { + if (strlen(trim($newcomment)) > 0) { + $tag_data_vorbiscomment[$tag_key][] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $newcomment); + } + } + } elseif (is_string($value) || is_numeric($value)) { + $tag_data_vorbiscomment[$tag_key][$key] = getid3_lib::iconv_fallback($this->tag_encoding, 'UTF-8', $value); + } else { + $this->warnings[] = '$data['.$tag_key.']['.$key.'] is not a string value - all of $data['.$tag_key.'] NOT written to VorbisComment tag'; + unset($tag_data_vorbiscomment[$tag_key]); + break; + } + } + } + $this->MergeExistingTagData('vorbiscomment', $tag_data_vorbiscomment); + return $tag_data_vorbiscomment; + } + + public function FormatDataForMetaFLAC() { + // FLAC & OggFLAC use VorbisComments same as OggVorbis + // but require metaflac to do the writing rather than vorbiscomment + return $this->FormatDataForVorbisComment(); + } + + public function FormatDataForReal() { + $tag_data_real['title'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['TITLE'] ) ? $this->tag_data['TITLE'] : array()))); + $tag_data_real['artist'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['ARTIST'] ) ? $this->tag_data['ARTIST'] : array()))); + $tag_data_real['copyright'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COPYRIGHT']) ? $this->tag_data['COPYRIGHT'] : array()))); + $tag_data_real['comment'] = getid3_lib::iconv_fallback($this->tag_encoding, 'ISO-8859-1', implode(' ', (isset($this->tag_data['COMMENT'] ) ? $this->tag_data['COMMENT'] : array()))); + + $this->MergeExistingTagData('real', $tag_data_real); + return $tag_data_real; + } + +} diff --git a/app/libs/vendor/getid3/write.real.php b/app/libs/vendor/getid3/write.real.php index 26c0ab47..02b91652 100644 --- a/app/libs/vendor/getid3/write.real.php +++ b/app/libs/vendor/getid3/write.real.php @@ -1,273 +1,273 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.real.php // -// module for writing RealAudio/RealVideo tags // -// dependencies: module.tag.real.php // -// /// -///////////////////////////////////////////////////////////////// - -class getid3_write_real -{ - public $filename; - public $tag_data = array(); - public $fread_buffer_size = 32768; // read buffer size in bytes - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - public $paddedlength = 512; // minimum length of CONT tag in bytes - - public function getid3_write_real() { - return true; - } - - public function WriteReal() { - // File MUST be writeable - CHMOD(646) at least - if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) { - - // Initialize getID3 engine - $getID3 = new getID3; - $OldThisFileInfo = $getID3->analyze($this->filename); - if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { - $this->errors[] = 'Cannot write Real tags on old-style file format'; - fclose($fp_source); - return false; - } - - if (empty($OldThisFileInfo['real']['chunks'])) { - $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file'; - fclose($fp_source); - return false; - } - foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { - $oldChunkInfo[$chunkarray['name']] = $chunkarray; - } - if (!empty($oldChunkInfo['CONT']['length'])) { - $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength); - } - - $new_CONT_tag_data = $this->GenerateCONTchunk(); - $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data); - $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']); - - if (isset($oldChunkInfo['.RMF']['length']) && ($oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data))) { - fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET); - fwrite($fp_source, $new__RMF_tag_data); - } else { - $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)'; - fclose($fp_source); - return false; - } - - if (isset($oldChunkInfo['PROP']['length']) && ($oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data))) { - fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET); - fwrite($fp_source, $new_PROP_tag_data); - } else { - $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)'; - fclose($fp_source); - return false; - } - - if (isset($oldChunkInfo['CONT']['length']) && ($oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data))) { - - // new data length is same as old data length - just overwrite - fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET); - fwrite($fp_source, $new_CONT_tag_data); - fclose($fp_source); - return true; - - } else { - - if (empty($oldChunkInfo['CONT'])) { - // no existing CONT chunk - $BeforeOffset = $oldChunkInfo['DATA']['offset']; - $AfterOffset = $oldChunkInfo['DATA']['offset']; - } else { - // new data is longer than old data - $BeforeOffset = $oldChunkInfo['CONT']['offset']; - $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; - } - if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { - if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { - - rewind($fp_source); - fwrite($fp_temp, fread($fp_source, $BeforeOffset)); - fwrite($fp_temp, $new_CONT_tag_data); - fseek($fp_source, $AfterOffset, SEEK_SET); - while ($buffer = fread($fp_source, $this->fread_buffer_size)) { - fwrite($fp_temp, $buffer, strlen($buffer)); - } - fclose($fp_temp); - - if (copy($tempfilename, $this->filename)) { - unlink($tempfilename); - fclose($fp_source); - return true; - } - unlink($tempfilename); - $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')'; - - } else { - $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; - } - } - fclose($fp_source); - return false; - - } - - } - $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; - return false; - } - - public function GenerateRMFchunk(&$chunks) { - $oldCONTexists = false; - foreach ($chunks as $key => $chunk) { - $chunkNameKeys[$chunk['name']] = $key; - if ($chunk['name'] == 'CONT') { - $oldCONTexists = true; - } - } - $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1); - - $RMFchunk = "\x00\x00"; // object version - $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4); - $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4); - - $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length - return $RMFchunk; - } - - public function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) { - $old_CONT_length = 0; - $old_DATA_offset = 0; - $old_INDX_offset = 0; - foreach ($chunks as $key => $chunk) { - $chunkNameKeys[$chunk['name']] = $key; - if ($chunk['name'] == 'CONT') { - $old_CONT_length = $chunk['length']; - } elseif ($chunk['name'] == 'DATA') { - if (!$old_DATA_offset) { - $old_DATA_offset = $chunk['offset']; - } - } elseif ($chunk['name'] == 'INDX') { - if (!$old_INDX_offset) { - $old_INDX_offset = $chunk['offset']; - } - } - } - $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length; - - $PROPchunk = "\x00\x00"; // object version - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4); - $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4); - $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2); - $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2); - - $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length - return $PROPchunk; - } - - public function GenerateCONTchunk() { - foreach ($this->tag_data as $key => $value) { - // limit each value to 0xFFFF bytes - $this->tag_data[$key] = substr($value, 0, 65535); - } - - $CONTchunk = "\x00\x00"; // object version - - $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0), 2); - $CONTchunk .= (!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : ''); - - $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0), 2); - $CONTchunk .= (!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : ''); - - $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0), 2); - $CONTchunk .= (!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : ''); - - $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0), 2); - $CONTchunk .= (!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : ''); - - if ($this->paddedlength > (strlen($CONTchunk) + 8)) { - $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8); - } - - $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length - - return $CONTchunk; - } - - public function RemoveReal() { - // File MUST be writeable - CHMOD(646) at least - if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) { - - // Initialize getID3 engine - $getID3 = new getID3; - $OldThisFileInfo = $getID3->analyze($this->filename); - if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { - $this->errors[] = 'Cannot remove Real tags from old-style file format'; - fclose($fp_source); - return false; - } - - if (empty($OldThisFileInfo['real']['chunks'])) { - $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file'; - fclose($fp_source); - return false; - } - foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { - $oldChunkInfo[$chunkarray['name']] = $chunkarray; - } - - if (empty($oldChunkInfo['CONT'])) { - // no existing CONT chunk - fclose($fp_source); - return true; - } - - $BeforeOffset = $oldChunkInfo['CONT']['offset']; - $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; - if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { - if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { - - rewind($fp_source); - fwrite($fp_temp, fread($fp_source, $BeforeOffset)); - fseek($fp_source, $AfterOffset, SEEK_SET); - while ($buffer = fread($fp_source, $this->fread_buffer_size)) { - fwrite($fp_temp, $buffer, strlen($buffer)); - } - fclose($fp_temp); - - if (copy($tempfilename, $this->filename)) { - unlink($tempfilename); - fclose($fp_source); - return true; - } - unlink($tempfilename); - $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')'; - - } else { - $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; - } - } - fclose($fp_source); - return false; - } - $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; - return false; - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.real.php // +// module for writing RealAudio/RealVideo tags // +// dependencies: module.tag.real.php // +// /// +///////////////////////////////////////////////////////////////// + +class getid3_write_real +{ + public $filename; + public $tag_data = array(); + public $fread_buffer_size = 32768; // read buffer size in bytes + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + public $paddedlength = 512; // minimum length of CONT tag in bytes + + public function getid3_write_real() { + return true; + } + + public function WriteReal() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { + $this->errors[] = 'Cannot write Real tags on old-style file format'; + fclose($fp_source); + return false; + } + + if (empty($OldThisFileInfo['real']['chunks'])) { + $this->errors[] = 'Cannot write Real tags because cannot find DATA chunk in file'; + fclose($fp_source); + return false; + } + foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { + $oldChunkInfo[$chunkarray['name']] = $chunkarray; + } + if (!empty($oldChunkInfo['CONT']['length'])) { + $this->paddedlength = max($oldChunkInfo['CONT']['length'], $this->paddedlength); + } + + $new_CONT_tag_data = $this->GenerateCONTchunk(); + $new_PROP_tag_data = $this->GeneratePROPchunk($OldThisFileInfo['real']['chunks'], $new_CONT_tag_data); + $new__RMF_tag_data = $this->GenerateRMFchunk($OldThisFileInfo['real']['chunks']); + + if (isset($oldChunkInfo['.RMF']['length']) && ($oldChunkInfo['.RMF']['length'] == strlen($new__RMF_tag_data))) { + fseek($fp_source, $oldChunkInfo['.RMF']['offset'], SEEK_SET); + fwrite($fp_source, $new__RMF_tag_data); + } else { + $this->errors[] = 'new .RMF tag ('.strlen($new__RMF_tag_data).' bytes) different length than old .RMF tag ('.$oldChunkInfo['.RMF']['length'].' bytes)'; + fclose($fp_source); + return false; + } + + if (isset($oldChunkInfo['PROP']['length']) && ($oldChunkInfo['PROP']['length'] == strlen($new_PROP_tag_data))) { + fseek($fp_source, $oldChunkInfo['PROP']['offset'], SEEK_SET); + fwrite($fp_source, $new_PROP_tag_data); + } else { + $this->errors[] = 'new PROP tag ('.strlen($new_PROP_tag_data).' bytes) different length than old PROP tag ('.$oldChunkInfo['PROP']['length'].' bytes)'; + fclose($fp_source); + return false; + } + + if (isset($oldChunkInfo['CONT']['length']) && ($oldChunkInfo['CONT']['length'] == strlen($new_CONT_tag_data))) { + + // new data length is same as old data length - just overwrite + fseek($fp_source, $oldChunkInfo['CONT']['offset'], SEEK_SET); + fwrite($fp_source, $new_CONT_tag_data); + fclose($fp_source); + return true; + + } else { + + if (empty($oldChunkInfo['CONT'])) { + // no existing CONT chunk + $BeforeOffset = $oldChunkInfo['DATA']['offset']; + $AfterOffset = $oldChunkInfo['DATA']['offset']; + } else { + // new data is longer than old data + $BeforeOffset = $oldChunkInfo['CONT']['offset']; + $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; + } + if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { + if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { + + rewind($fp_source); + fwrite($fp_temp, fread($fp_source, $BeforeOffset)); + fwrite($fp_temp, $new_CONT_tag_data); + fseek($fp_source, $AfterOffset, SEEK_SET); + while ($buffer = fread($fp_source, $this->fread_buffer_size)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + + if (copy($tempfilename, $this->filename)) { + unlink($tempfilename); + fclose($fp_source); + return true; + } + unlink($tempfilename); + $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')'; + + } else { + $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; + } + } + fclose($fp_source); + return false; + + } + + } + $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; + return false; + } + + public function GenerateRMFchunk(&$chunks) { + $oldCONTexists = false; + foreach ($chunks as $key => $chunk) { + $chunkNameKeys[$chunk['name']] = $key; + if ($chunk['name'] == 'CONT') { + $oldCONTexists = true; + } + } + $newHeadersCount = $chunks[$chunkNameKeys['.RMF']]['headers_count'] + ($oldCONTexists ? 0 : 1); + + $RMFchunk = "\x00\x00"; // object version + $RMFchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['.RMF']]['file_version'], 4); + $RMFchunk .= getid3_lib::BigEndian2String($newHeadersCount, 4); + + $RMFchunk = '.RMF'.getid3_lib::BigEndian2String(strlen($RMFchunk) + 8, 4).$RMFchunk; // .RMF chunk identifier + chunk length + return $RMFchunk; + } + + public function GeneratePROPchunk(&$chunks, &$new_CONT_tag_data) { + $old_CONT_length = 0; + $old_DATA_offset = 0; + $old_INDX_offset = 0; + foreach ($chunks as $key => $chunk) { + $chunkNameKeys[$chunk['name']] = $key; + if ($chunk['name'] == 'CONT') { + $old_CONT_length = $chunk['length']; + } elseif ($chunk['name'] == 'DATA') { + if (!$old_DATA_offset) { + $old_DATA_offset = $chunk['offset']; + } + } elseif ($chunk['name'] == 'INDX') { + if (!$old_INDX_offset) { + $old_INDX_offset = $chunk['offset']; + } + } + } + $CONTdelta = strlen($new_CONT_tag_data) - $old_CONT_length; + + $PROPchunk = "\x00\x00"; // object version + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_bit_rate'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_bit_rate'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['max_packet_size'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['avg_packet_size'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_packets'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['duration'], 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['preroll'], 4); + $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_INDX_offset + $CONTdelta), 4); + $PROPchunk .= getid3_lib::BigEndian2String(max(0, $old_DATA_offset + $CONTdelta), 4); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['num_streams'], 2); + $PROPchunk .= getid3_lib::BigEndian2String($chunks[$chunkNameKeys['PROP']]['flags_raw'], 2); + + $PROPchunk = 'PROP'.getid3_lib::BigEndian2String(strlen($PROPchunk) + 8, 4).$PROPchunk; // PROP chunk identifier + chunk length + return $PROPchunk; + } + + public function GenerateCONTchunk() { + foreach ($this->tag_data as $key => $value) { + // limit each value to 0xFFFF bytes + $this->tag_data[$key] = substr($value, 0, 65535); + } + + $CONTchunk = "\x00\x00"; // object version + + $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : 0), 2); + $CONTchunk .= (!empty($this->tag_data['title']) ? strlen($this->tag_data['title']) : ''); + + $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : 0), 2); + $CONTchunk .= (!empty($this->tag_data['artist']) ? strlen($this->tag_data['artist']) : ''); + + $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : 0), 2); + $CONTchunk .= (!empty($this->tag_data['copyright']) ? strlen($this->tag_data['copyright']) : ''); + + $CONTchunk .= getid3_lib::BigEndian2String((!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : 0), 2); + $CONTchunk .= (!empty($this->tag_data['comment']) ? strlen($this->tag_data['comment']) : ''); + + if ($this->paddedlength > (strlen($CONTchunk) + 8)) { + $CONTchunk .= str_repeat("\x00", $this->paddedlength - strlen($CONTchunk) - 8); + } + + $CONTchunk = 'CONT'.getid3_lib::BigEndian2String(strlen($CONTchunk) + 8, 4).$CONTchunk; // CONT chunk identifier + chunk length + + return $CONTchunk; + } + + public function RemoveReal() { + // File MUST be writeable - CHMOD(646) at least + if (is_writeable($this->filename) && is_file($this->filename) && ($fp_source = fopen($this->filename, 'r+b'))) { + + // Initialize getID3 engine + $getID3 = new getID3; + $OldThisFileInfo = $getID3->analyze($this->filename); + if (empty($OldThisFileInfo['real']['chunks']) && !empty($OldThisFileInfo['real']['old_ra_header'])) { + $this->errors[] = 'Cannot remove Real tags from old-style file format'; + fclose($fp_source); + return false; + } + + if (empty($OldThisFileInfo['real']['chunks'])) { + $this->errors[] = 'Cannot remove Real tags because cannot find DATA chunk in file'; + fclose($fp_source); + return false; + } + foreach ($OldThisFileInfo['real']['chunks'] as $chunknumber => $chunkarray) { + $oldChunkInfo[$chunkarray['name']] = $chunkarray; + } + + if (empty($oldChunkInfo['CONT'])) { + // no existing CONT chunk + fclose($fp_source); + return true; + } + + $BeforeOffset = $oldChunkInfo['CONT']['offset']; + $AfterOffset = $oldChunkInfo['CONT']['offset'] + $oldChunkInfo['CONT']['length']; + if ($tempfilename = tempnam(GETID3_TEMP_DIR, 'getID3')) { + if (is_writable($tempfilename) && is_file($tempfilename) && ($fp_temp = fopen($tempfilename, 'wb'))) { + + rewind($fp_source); + fwrite($fp_temp, fread($fp_source, $BeforeOffset)); + fseek($fp_source, $AfterOffset, SEEK_SET); + while ($buffer = fread($fp_source, $this->fread_buffer_size)) { + fwrite($fp_temp, $buffer, strlen($buffer)); + } + fclose($fp_temp); + + if (copy($tempfilename, $this->filename)) { + unlink($tempfilename); + fclose($fp_source); + return true; + } + unlink($tempfilename); + $this->errors[] = 'FAILED: copy('.$tempfilename.', '.$this->filename.')'; + + } else { + $this->errors[] = 'Could not fopen("'.$tempfilename.'", "wb")'; + } + } + fclose($fp_source); + return false; + } + $this->errors[] = 'Could not fopen("'.$this->filename.'", "r+b")'; + return false; + } + +} diff --git a/app/libs/vendor/getid3/write.vorbiscomment.php b/app/libs/vendor/getid3/write.vorbiscomment.php index de5ac87d..30b51ffb 100644 --- a/app/libs/vendor/getid3/write.vorbiscomment.php +++ b/app/libs/vendor/getid3/write.vorbiscomment.php @@ -1,119 +1,119 @@ - // -// available at http://getid3.sourceforge.net // -// or http://www.getid3.org // -///////////////////////////////////////////////////////////////// -// See readme.txt for more details // -///////////////////////////////////////////////////////////////// -// // -// write.vorbiscomment.php // -// module for writing VorbisComment tags // -// dependencies: /helperapps/vorbiscomment.exe // -// /// -///////////////////////////////////////////////////////////////// - - -class getid3_write_vorbiscomment -{ - - public $filename; - public $tag_data; - public $warnings = array(); // any non-critical errors will be stored here - public $errors = array(); // any critical errors will be stored here - - public function getid3_write_vorbiscomment() { - return true; - } - - public function WriteVorbisComment() { - - if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { - $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written'; - return false; - } - - // Create file with new comments - $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); - if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { - - foreach ($this->tag_data as $key => $value) { - foreach ($value as $commentdata) { - fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n"); - } - } - fclose($fpcomments); - - } else { - $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written'; - return false; - } - - $oldignoreuserabort = ignore_user_abort(true); - if (GETID3_OS_ISWINDOWS) { - - if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { - //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; - // vorbiscomment works fine if you copy-paste the above commandline into a command prompt, - // but refuses to work with `backtick` if there are "doublequotes" present around BOTH - // the metaflac pathname and the target filename. For whatever reason...?? - // The solution is simply ensure that the metaflac pathname has no spaces, - // and therefore does not need to be quoted - - // On top of that, if error messages are not always captured properly under Windows - // To at least see if there was a problem, compare file modification timestamps before and after writing - clearstatcache(); - $timestampbeforewriting = filemtime($this->filename); - - $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; - $VorbiscommentError = `$commandline`; - - if (empty($VorbiscommentError)) { - clearstatcache(); - if ($timestampbeforewriting == filemtime($this->filename)) { - $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written'; - } - } - } else { - $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; - } - - } else { - - $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; - $VorbiscommentError = `$commandline`; - - } - - // Remove temporary comments file - unlink($tempcommentsfilename); - ignore_user_abort($oldignoreuserabort); - - if (!empty($VorbiscommentError)) { - - $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError; - return false; - - } - - return true; - } - - public function DeleteVorbisComment() { - $this->tag_data = array(array()); - return $this->WriteVorbisComment(); - } - - public function CleanVorbisCommentName($originalcommentname) { - // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. - // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through - // 0x7A inclusive (a-z). - - // replace invalid chars with a space, return uppercase text - // Thanks Chris Bolt for improving this function - // note: *reg_replace() replaces nulls with empty string (not space) - return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); - - } - -} + // +// available at http://getid3.sourceforge.net // +// or http://www.getid3.org // +///////////////////////////////////////////////////////////////// +// See readme.txt for more details // +///////////////////////////////////////////////////////////////// +// // +// write.vorbiscomment.php // +// module for writing VorbisComment tags // +// dependencies: /helperapps/vorbiscomment.exe // +// /// +///////////////////////////////////////////////////////////////// + + +class getid3_write_vorbiscomment +{ + + public $filename; + public $tag_data; + public $warnings = array(); // any non-critical errors will be stored here + public $errors = array(); // any critical errors will be stored here + + public function getid3_write_vorbiscomment() { + return true; + } + + public function WriteVorbisComment() { + + if (preg_match('#(1|ON)#i', ini_get('safe_mode'))) { + $this->errors[] = 'PHP running in Safe Mode (backtick operator not available) - cannot call vorbiscomment, tags not written'; + return false; + } + + // Create file with new comments + $tempcommentsfilename = tempnam(GETID3_TEMP_DIR, 'getID3'); + if (is_writable($tempcommentsfilename) && is_file($tempcommentsfilename) && ($fpcomments = fopen($tempcommentsfilename, 'wb'))) { + + foreach ($this->tag_data as $key => $value) { + foreach ($value as $commentdata) { + fwrite($fpcomments, $this->CleanVorbisCommentName($key).'='.$commentdata."\n"); + } + } + fclose($fpcomments); + + } else { + $this->errors[] = 'failed to open temporary tags file "'.$tempcommentsfilename.'", tags not written'; + return false; + } + + $oldignoreuserabort = ignore_user_abort(true); + if (GETID3_OS_ISWINDOWS) { + + if (file_exists(GETID3_HELPERAPPSDIR.'vorbiscomment.exe')) { + //$commandline = '"'.GETID3_HELPERAPPSDIR.'vorbiscomment.exe" -w --raw -c "'.$tempcommentsfilename.'" "'.str_replace('/', '\\', $this->filename).'"'; + // vorbiscomment works fine if you copy-paste the above commandline into a command prompt, + // but refuses to work with `backtick` if there are "doublequotes" present around BOTH + // the metaflac pathname and the target filename. For whatever reason...?? + // The solution is simply ensure that the metaflac pathname has no spaces, + // and therefore does not need to be quoted + + // On top of that, if error messages are not always captured properly under Windows + // To at least see if there was a problem, compare file modification timestamps before and after writing + clearstatcache(); + $timestampbeforewriting = filemtime($this->filename); + + $commandline = GETID3_HELPERAPPSDIR.'vorbiscomment.exe -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; + $VorbiscommentError = `$commandline`; + + if (empty($VorbiscommentError)) { + clearstatcache(); + if ($timestampbeforewriting == filemtime($this->filename)) { + $VorbiscommentError = 'File modification timestamp has not changed - it looks like the tags were not written'; + } + } + } else { + $VorbiscommentError = 'vorbiscomment.exe not found in '.GETID3_HELPERAPPSDIR; + } + + } else { + + $commandline = 'vorbiscomment -w --raw -c "'.$tempcommentsfilename.'" "'.$this->filename.'" 2>&1'; + $VorbiscommentError = `$commandline`; + + } + + // Remove temporary comments file + unlink($tempcommentsfilename); + ignore_user_abort($oldignoreuserabort); + + if (!empty($VorbiscommentError)) { + + $this->errors[] = 'system call to vorbiscomment failed with message: '."\n\n".$VorbiscommentError; + return false; + + } + + return true; + } + + public function DeleteVorbisComment() { + $this->tag_data = array(array()); + return $this->WriteVorbisComment(); + } + + public function CleanVorbisCommentName($originalcommentname) { + // A case-insensitive field name that may consist of ASCII 0x20 through 0x7D, 0x3D ('=') excluded. + // ASCII 0x41 through 0x5A inclusive (A-Z) is to be considered equivalent to ASCII 0x61 through + // 0x7A inclusive (a-z). + + // replace invalid chars with a space, return uppercase text + // Thanks Chris Bolt for improving this function + // note: *reg_replace() replaces nulls with empty string (not space) + return strtoupper(preg_replace('#[^ -<>-}]#', ' ', str_replace("\x00", ' ', $originalcommentname))); + + } + +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php index 351249a7..8e825f9b 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php @@ -1,86 +1,86 @@ - 'Domain', - 'path' => 'Path', - 'max_age' => 'Max-Age', - 'expires' => 'Expires', - 'version' => 'Version', - 'secure' => 'Secure', - 'port' => 'Port', - 'discard' => 'Discard', - 'comment' => 'Comment', - 'comment_url' => 'Comment-Url', - 'http_only' => 'HttpOnly' - ); - - public function parseCookie($cookie, $host = null, $path = null, $decode = false) - { - // Explode the cookie string using a series of semicolons - $pieces = array_filter(array_map('trim', explode(';', $cookie))); - - // The name of the cookie (first kvp) must include an equal sign. - if (empty($pieces) || !strpos($pieces[0], '=')) { - return false; - } - - // Create the default return array - $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( - 'cookies' => array(), - 'data' => array(), - 'path' => $path ?: '/', - 'http_only' => false, - 'discard' => false, - 'domain' => $host - )); - $foundNonCookies = 0; - - // Add the cookie pieces into the parsed data array - foreach ($pieces as $part) { - - $cookieParts = explode('=', $part, 2); - $key = trim($cookieParts[0]); - - if (count($cookieParts) == 1) { - // Can be a single value (e.g. secure, httpOnly) - $value = true; - } else { - // Be sure to strip wrapping quotes - $value = trim($cookieParts[1], " \n\r\t\0\x0B\""); - if ($decode) { - $value = urldecode($value); - } - } - - // Only check for non-cookies when cookies have been found - if (!empty($data['cookies'])) { - foreach (self::$cookieParts as $mapValue => $search) { - if (!strcasecmp($search, $key)) { - $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; - $foundNonCookies++; - continue 2; - } - } - } - - // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a - // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. - $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; - } - - // Calculate the expires date - if (!$data['expires'] && $data['max_age']) { - $data['expires'] = time() + (int) $data['max_age']; - } - - return $data; - } -} + 'Domain', + 'path' => 'Path', + 'max_age' => 'Max-Age', + 'expires' => 'Expires', + 'version' => 'Version', + 'secure' => 'Secure', + 'port' => 'Port', + 'discard' => 'Discard', + 'comment' => 'Comment', + 'comment_url' => 'Comment-Url', + 'http_only' => 'HttpOnly' + ); + + public function parseCookie($cookie, $host = null, $path = null, $decode = false) + { + // Explode the cookie string using a series of semicolons + $pieces = array_filter(array_map('trim', explode(';', $cookie))); + + // The name of the cookie (first kvp) must include an equal sign. + if (empty($pieces) || !strpos($pieces[0], '=')) { + return false; + } + + // Create the default return array + $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( + 'cookies' => array(), + 'data' => array(), + 'path' => $path ?: '/', + 'http_only' => false, + 'discard' => false, + 'domain' => $host + )); + $foundNonCookies = 0; + + // Add the cookie pieces into the parsed data array + foreach ($pieces as $part) { + + $cookieParts = explode('=', $part, 2); + $key = trim($cookieParts[0]); + + if (count($cookieParts) == 1) { + // Can be a single value (e.g. secure, httpOnly) + $value = true; + } else { + // Be sure to strip wrapping quotes + $value = trim($cookieParts[1], " \n\r\t\0\x0B\""); + if ($decode) { + $value = urldecode($value); + } + } + + // Only check for non-cookies when cookies have been found + if (!empty($data['cookies'])) { + foreach (self::$cookieParts as $mapValue => $search) { + if (!strcasecmp($search, $key)) { + $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; + $foundNonCookies++; + continue 2; + } + } + } + + // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a + // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. + $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; + } + + // Calculate the expires date + if (!$data['expires'] && $data['max_age']) { + $data['expires'] = time() + (int) $data['max_age']; + } + + return $data; + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php index 66a61ea3..d21ffe21 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php @@ -1,33 +1,33 @@ - $requestUrl, - 'scheme' => 'http' - ); - - // Check for the Host header - if (isset($parts['headers']['Host'])) { - $urlParts['host'] = $parts['headers']['Host']; - } elseif (isset($parts['headers']['host'])) { - $urlParts['host'] = $parts['headers']['host']; - } else { - $urlParts['host'] = null; - } - - if (false === strpos($urlParts['host'], ':')) { - $urlParts['port'] = ''; - } else { - $hostParts = explode(':', $urlParts['host']); - $urlParts['host'] = trim($hostParts[0]); - $urlParts['port'] = (int) trim($hostParts[1]); - if ($urlParts['port'] == 443) { - $urlParts['scheme'] = 'https'; - } - } - - // Check if a query is present - $path = $urlParts['path']; - $qpos = strpos($path, '?'); - if ($qpos) { - $urlParts['query'] = substr($path, $qpos + 1); - $urlParts['path'] = substr($path, 0, $qpos); - } else { - $urlParts['query'] = ''; - } - - return $urlParts; - } -} + $requestUrl, + 'scheme' => 'http' + ); + + // Check for the Host header + if (isset($parts['headers']['Host'])) { + $urlParts['host'] = $parts['headers']['Host']; + } elseif (isset($parts['headers']['host'])) { + $urlParts['host'] = $parts['headers']['host']; + } else { + $urlParts['host'] = null; + } + + if (false === strpos($urlParts['host'], ':')) { + $urlParts['port'] = ''; + } else { + $hostParts = explode(':', $urlParts['host']); + $urlParts['host'] = trim($hostParts[0]); + $urlParts['port'] = (int) trim($hostParts[1]); + if ($urlParts['port'] == 443) { + $urlParts['scheme'] = 'https'; + } + } + + // Check if a query is present + $path = $urlParts['path']; + $qpos = strpos($path, '?'); + if ($qpos) { + $urlParts['query'] = substr($path, $qpos + 1); + $urlParts['path'] = substr($path, 0, $qpos); + } else { + $urlParts['query'] = ''; + } + + return $urlParts; + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php index 7a50ceae..10474006 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php @@ -1,110 +1,110 @@ -parseMessage($message); - - // Parse the protocol and protocol version - if (isset($parts['start_line'][2])) { - $startParts = explode('/', $parts['start_line'][2]); - $protocol = strtoupper($startParts[0]); - $version = isset($startParts[1]) ? $startParts[1] : '1.1'; - } else { - $protocol = 'HTTP'; - $version = '1.1'; - } - - $parsed = array( - 'method' => strtoupper($parts['start_line'][0]), - 'protocol' => $protocol, - 'version' => $version, - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ); - - $parsed['request_url'] = $this->getUrlPartsFromMessage($parts['start_line'][1], $parsed); - - return $parsed; - } - - public function parseResponse($message) - { - if (!$message) { - return false; - } - - $parts = $this->parseMessage($message); - list($protocol, $version) = explode('/', trim($parts['start_line'][0])); - - return array( - 'protocol' => $protocol, - 'version' => $version, - 'code' => $parts['start_line'][1], - 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ); - } - - /** - * Parse a message into parts - * - * @param string $message Message to parse - * - * @return array - */ - protected function parseMessage($message) - { - $startLine = null; - $headers = array(); - $body = ''; - - // Iterate over each line in the message, accounting for line endings - $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { - - $line = $lines[$i]; - - // If two line breaks were encountered, then this is the end of body - if (empty($line)) { - if ($i < $totalLines - 1) { - $body = implode('', array_slice($lines, $i + 2)); - } - break; - } - - // Parse message headers - if (!$startLine) { - $startLine = explode(' ', $line, 3); - } elseif (strpos($line, ':')) { - $parts = explode(':', $line, 2); - $key = trim($parts[0]); - $value = isset($parts[1]) ? trim($parts[1]) : ''; - if (!isset($headers[$key])) { - $headers[$key] = $value; - } elseif (!is_array($headers[$key])) { - $headers[$key] = array($headers[$key], $value); - } else { - $headers[$key][] = $value; - } - } - } - - return array( - 'start_line' => $startLine, - 'headers' => $headers, - 'body' => $body - ); - } -} +parseMessage($message); + + // Parse the protocol and protocol version + if (isset($parts['start_line'][2])) { + $startParts = explode('/', $parts['start_line'][2]); + $protocol = strtoupper($startParts[0]); + $version = isset($startParts[1]) ? $startParts[1] : '1.1'; + } else { + $protocol = 'HTTP'; + $version = '1.1'; + } + + $parsed = array( + 'method' => strtoupper($parts['start_line'][0]), + 'protocol' => $protocol, + 'version' => $version, + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts['start_line'][1], $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = $this->parseMessage($message); + list($protocol, $version) = explode('/', trim($parts['start_line'][0])); + + return array( + 'protocol' => $protocol, + 'version' => $version, + 'code' => $parts['start_line'][1], + 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ); + } + + /** + * Parse a message into parts + * + * @param string $message Message to parse + * + * @return array + */ + protected function parseMessage($message) + { + $startLine = null; + $headers = array(); + $body = ''; + + // Iterate over each line in the message, accounting for line endings + $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { + + $line = $lines[$i]; + + // If two line breaks were encountered, then this is the end of body + if (empty($line)) { + if ($i < $totalLines - 1) { + $body = implode('', array_slice($lines, $i + 2)); + } + break; + } + + // Parse message headers + if (!$startLine) { + $startLine = explode(' ', $line, 3); + } elseif (strpos($line, ':')) { + $parts = explode(':', $line, 2); + $key = trim($parts[0]); + $value = isset($parts[1]) ? trim($parts[1]) : ''; + if (!isset($headers[$key])) { + $headers[$key] = $value; + } elseif (!is_array($headers[$key])) { + $headers[$key] = array($headers[$key], $value); + } else { + $headers[$key][] = $value; + } + } + } + + return array( + 'start_line' => $startLine, + 'headers' => $headers, + 'body' => $body + ); + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php index ef7d4121..cc448088 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php @@ -1,27 +1,27 @@ - $parts->requestMethod, - 'protocol' => 'HTTP', - 'version' => number_format($parts->httpVersion, 1), - 'headers' => $parts->headers, - 'body' => $parts->body - ); - - $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed); - - return $parsed; - } - - public function parseResponse($message) - { - if (!$message) { - return false; - } - - $parts = http_parse_message($message); - - return array( - 'protocol' => 'HTTP', - 'version' => number_format($parts->httpVersion, 1), - 'code' => $parts->responseCode, - 'reason_phrase' => $parts->responseStatus, - 'headers' => $parts->headers, - 'body' => $parts->body - ); - } -} + $parts->requestMethod, + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'headers' => $parts->headers, + 'body' => $parts->body + ); + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed); + + return $parsed; + } + + public function parseResponse($message) + { + if (!$message) { + return false; + } + + $parts = http_parse_message($message); + + return array( + 'protocol' => 'HTTP', + 'version' => number_format($parts->httpVersion, 1), + 'code' => $parts->responseCode, + 'reason_phrase' => $parts->responseStatus, + 'headers' => $parts->headers, + 'body' => $parts->body + ); + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php index 2b25572c..f8386831 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php @@ -1,75 +1,75 @@ - 'Guzzle\\Parser\\Message\\MessageParser', - 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', - 'url' => 'Guzzle\\Parser\\Url\\UrlParser', - 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate', - ); - - /** - * @return self - * @codeCoverageIgnore - */ - public static function getInstance() - { - if (!self::$instance) { - self::$instance = new static; - } - - return self::$instance; - } - - public function __construct() - { - // Use the PECL URI template parser if available - if (extension_loaded('uri_template')) { - $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate'; - } - } - - /** - * Get a parser by name from an instance - * - * @param string $name Name of the parser to retrieve - * - * @return mixed|null - */ - public function getParser($name) - { - if (!isset($this->instances[$name])) { - if (!isset($this->mapping[$name])) { - return null; - } - $class = $this->mapping[$name]; - $this->instances[$name] = new $class(); - } - - return $this->instances[$name]; - } - - /** - * Register a custom parser by name with the register - * - * @param string $name Name or handle of the parser to register - * @param mixed $parser Instantiated parser to register - */ - public function registerParser($name, $parser) - { - $this->instances[$name] = $parser; - } -} + 'Guzzle\\Parser\\Message\\MessageParser', + 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', + 'url' => 'Guzzle\\Parser\\Url\\UrlParser', + 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate', + ); + + /** + * @return self + * @codeCoverageIgnore + */ + public static function getInstance() + { + if (!self::$instance) { + self::$instance = new static; + } + + return self::$instance; + } + + public function __construct() + { + // Use the PECL URI template parser if available + if (extension_loaded('uri_template')) { + $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate'; + } + } + + /** + * Get a parser by name from an instance + * + * @param string $name Name of the parser to retrieve + * + * @return mixed|null + */ + public function getParser($name) + { + if (!isset($this->instances[$name])) { + if (!isset($this->mapping[$name])) { + return null; + } + $class = $this->mapping[$name]; + $this->instances[$name] = new $class(); + } + + return $this->instances[$name]; + } + + /** + * Register a custom parser by name with the register + * + * @param string $name Name or handle of the parser to register + * @param mixed $parser Instantiated parser to register + */ + public function registerParser($name, $parser) + { + $this->instances[$name] = $parser; + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php index 8adffc08..b0764e83 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php @@ -1,26 +1,26 @@ - true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true - ); - - /** @var array Delimiters */ - private static $delims = array( - ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' - ); - - /** @var array Percent encoded delimiters */ - private static $delimsPct = array( - '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', - '%3B', '%3D' - ); - - public function expand($template, array $variables) - { - if ($this->regex == self::DEFAULT_PATTERN && false === strpos($template, '{')) { - return $template; - } - - $this->template = $template; - $this->variables = $variables; - - return preg_replace_callback($this->regex, array($this, 'expandMatch'), $this->template); - } - - /** - * Set the regex patten used to expand URI templates - * - * @param string $regexPattern - */ - public function setRegex($regexPattern) - { - $this->regex = $regexPattern; - } - - /** - * Parse an expression into parts - * - * @param string $expression Expression to parse - * - * @return array Returns an associative array of parts - */ - private function parseExpression($expression) - { - // Check for URI operators - $operator = ''; - - if (isset(self::$operatorHash[$expression[0]])) { - $operator = $expression[0]; - $expression = substr($expression, 1); - } - - $values = explode(',', $expression); - foreach ($values as &$value) { - $value = trim($value); - $varspec = array(); - $substrPos = strpos($value, ':'); - if ($substrPos) { - $varspec['value'] = substr($value, 0, $substrPos); - $varspec['modifier'] = ':'; - $varspec['position'] = (int) substr($value, $substrPos + 1); - } elseif (substr($value, -1) == '*') { - $varspec['modifier'] = '*'; - $varspec['value'] = substr($value, 0, -1); - } else { - $varspec['value'] = (string) $value; - $varspec['modifier'] = ''; - } - $value = $varspec; - } - - return array( - 'operator' => $operator, - 'values' => $values - ); - } - - /** - * Process an expansion - * - * @param array $matches Matches met in the preg_replace_callback - * - * @return string Returns the replacement string - */ - private function expandMatch(array $matches) - { - static $rfc1738to3986 = array( - '+' => '%20', - '%7e' => '~' - ); - - $parsed = self::parseExpression($matches[1]); - $replacements = array(); - - $prefix = $parsed['operator']; - $joiner = $parsed['operator']; - $useQueryString = false; - if ($parsed['operator'] == '?') { - $joiner = '&'; - $useQueryString = true; - } elseif ($parsed['operator'] == '&') { - $useQueryString = true; - } elseif ($parsed['operator'] == '#') { - $joiner = ','; - } elseif ($parsed['operator'] == ';') { - $useQueryString = true; - } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') { - $joiner = ','; - $prefix = ''; - } - - foreach ($parsed['values'] as $value) { - - if (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) { - continue; - } - - $variable = $this->variables[$value['value']]; - $actuallyUseQueryString = $useQueryString; - $expanded = ''; - - if (is_array($variable)) { - - $isAssoc = $this->isAssoc($variable); - $kvp = array(); - foreach ($variable as $key => $var) { - - if ($isAssoc) { - $key = rawurlencode($key); - $isNestedArray = is_array($var); - } else { - $isNestedArray = false; - } - - if (!$isNestedArray) { - $var = rawurlencode($var); - if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { - $var = $this->decodeReserved($var); - } - } - - if ($value['modifier'] == '*') { - if ($isAssoc) { - if ($isNestedArray) { - // Nested arrays must allow for deeply nested structures - $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986); - } else { - $var = $key . '=' . $var; - } - } elseif ($key > 0 && $actuallyUseQueryString) { - $var = $value['value'] . '=' . $var; - } - } - - $kvp[$key] = $var; - } - - if (empty($variable)) { - $actuallyUseQueryString = false; - } elseif ($value['modifier'] == '*') { - $expanded = implode($joiner, $kvp); - if ($isAssoc) { - // Don't prepend the value name when using the explode modifier with an associative array - $actuallyUseQueryString = false; - } - } else { - if ($isAssoc) { - // When an associative array is encountered and the explode modifier is not set, then the - // result must be a comma separated list of keys followed by their respective values. - foreach ($kvp as $k => &$v) { - $v = $k . ',' . $v; - } - } - $expanded = implode(',', $kvp); - } - - } else { - if ($value['modifier'] == ':') { - $variable = substr($variable, 0, $value['position']); - } - $expanded = rawurlencode($variable); - if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { - $expanded = $this->decodeReserved($expanded); - } - } - - if ($actuallyUseQueryString) { - if (!$expanded && $joiner != '&') { - $expanded = $value['value']; - } else { - $expanded = $value['value'] . '=' . $expanded; - } - } - - $replacements[] = $expanded; - } - - $ret = implode($joiner, $replacements); - if ($ret && $prefix) { - return $prefix . $ret; - } - - return $ret; - } - - /** - * Determines if an array is associative - * - * @param array $array Array to check - * - * @return bool - */ - private function isAssoc(array $array) - { - return (bool) count(array_filter(array_keys($array), 'is_string')); - } - - /** - * Removes percent encoding on reserved characters (used with + and # modifiers) - * - * @param string $string String to fix - * - * @return string - */ - private function decodeReserved($string) - { - return str_replace(self::$delimsPct, self::$delims, $string); - } -} + true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true + ); + + /** @var array Delimiters */ + private static $delims = array( + ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' + ); + + /** @var array Percent encoded delimiters */ + private static $delimsPct = array( + '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', + '%3B', '%3D' + ); + + public function expand($template, array $variables) + { + if ($this->regex == self::DEFAULT_PATTERN && false === strpos($template, '{')) { + return $template; + } + + $this->template = $template; + $this->variables = $variables; + + return preg_replace_callback($this->regex, array($this, 'expandMatch'), $this->template); + } + + /** + * Set the regex patten used to expand URI templates + * + * @param string $regexPattern + */ + public function setRegex($regexPattern) + { + $this->regex = $regexPattern; + } + + /** + * Parse an expression into parts + * + * @param string $expression Expression to parse + * + * @return array Returns an associative array of parts + */ + private function parseExpression($expression) + { + // Check for URI operators + $operator = ''; + + if (isset(self::$operatorHash[$expression[0]])) { + $operator = $expression[0]; + $expression = substr($expression, 1); + } + + $values = explode(',', $expression); + foreach ($values as &$value) { + $value = trim($value); + $varspec = array(); + $substrPos = strpos($value, ':'); + if ($substrPos) { + $varspec['value'] = substr($value, 0, $substrPos); + $varspec['modifier'] = ':'; + $varspec['position'] = (int) substr($value, $substrPos + 1); + } elseif (substr($value, -1) == '*') { + $varspec['modifier'] = '*'; + $varspec['value'] = substr($value, 0, -1); + } else { + $varspec['value'] = (string) $value; + $varspec['modifier'] = ''; + } + $value = $varspec; + } + + return array( + 'operator' => $operator, + 'values' => $values + ); + } + + /** + * Process an expansion + * + * @param array $matches Matches met in the preg_replace_callback + * + * @return string Returns the replacement string + */ + private function expandMatch(array $matches) + { + static $rfc1738to3986 = array( + '+' => '%20', + '%7e' => '~' + ); + + $parsed = self::parseExpression($matches[1]); + $replacements = array(); + + $prefix = $parsed['operator']; + $joiner = $parsed['operator']; + $useQueryString = false; + if ($parsed['operator'] == '?') { + $joiner = '&'; + $useQueryString = true; + } elseif ($parsed['operator'] == '&') { + $useQueryString = true; + } elseif ($parsed['operator'] == '#') { + $joiner = ','; + } elseif ($parsed['operator'] == ';') { + $useQueryString = true; + } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') { + $joiner = ','; + $prefix = ''; + } + + foreach ($parsed['values'] as $value) { + + if (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) { + continue; + } + + $variable = $this->variables[$value['value']]; + $actuallyUseQueryString = $useQueryString; + $expanded = ''; + + if (is_array($variable)) { + + $isAssoc = $this->isAssoc($variable); + $kvp = array(); + foreach ($variable as $key => $var) { + + if ($isAssoc) { + $key = rawurlencode($key); + $isNestedArray = is_array($var); + } else { + $isNestedArray = false; + } + + if (!$isNestedArray) { + $var = rawurlencode($var); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $var = $this->decodeReserved($var); + } + } + + if ($value['modifier'] == '*') { + if ($isAssoc) { + if ($isNestedArray) { + // Nested arrays must allow for deeply nested structures + $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986); + } else { + $var = $key . '=' . $var; + } + } elseif ($key > 0 && $actuallyUseQueryString) { + $var = $value['value'] . '=' . $var; + } + } + + $kvp[$key] = $var; + } + + if (empty($variable)) { + $actuallyUseQueryString = false; + } elseif ($value['modifier'] == '*') { + $expanded = implode($joiner, $kvp); + if ($isAssoc) { + // Don't prepend the value name when using the explode modifier with an associative array + $actuallyUseQueryString = false; + } + } else { + if ($isAssoc) { + // When an associative array is encountered and the explode modifier is not set, then the + // result must be a comma separated list of keys followed by their respective values. + foreach ($kvp as $k => &$v) { + $v = $k . ',' . $v; + } + } + $expanded = implode(',', $kvp); + } + + } else { + if ($value['modifier'] == ':') { + $variable = substr($variable, 0, $value['position']); + } + $expanded = rawurlencode($variable); + if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + $expanded = $this->decodeReserved($expanded); + } + } + + if ($actuallyUseQueryString) { + if (!$expanded && $joiner != '&') { + $expanded = $value['value']; + } else { + $expanded = $value['value'] . '=' . $expanded; + } + } + + $replacements[] = $expanded; + } + + $ret = implode($joiner, $replacements); + if ($ret && $prefix) { + return $prefix . $ret; + } + + return $ret; + } + + /** + * Determines if an array is associative + * + * @param array $array Array to check + * + * @return bool + */ + private function isAssoc(array $array) + { + return (bool) count(array_filter(array_keys($array), 'is_string')); + } + + /** + * Removes percent encoding on reserved characters (used with + and # modifiers) + * + * @param string $string String to fix + * + * @return string + */ + private function decodeReserved($string) + { + return str_replace(self::$delimsPct, self::$delims, $string); + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php index 4aa889f2..c81d5154 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/UriTemplateInterface.php @@ -1,21 +1,21 @@ -utf8 = $utf8; - } - - public function parseUrl($url) - { - Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); - - static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, - 'user' => null, 'pass' => null, 'fragment' => null); - - $parts = parse_url($url); - - // Need to handle query parsing specially for UTF-8 requirements - if ($this->utf8 && isset($parts['query'])) { - $queryPos = strpos($url, '?'); - if (isset($parts['fragment'])) { - $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1); - } else { - $parts['query'] = substr($url, $queryPos + 1); - } - } - - return $parts + $defaults; - } -} +utf8 = $utf8; + } + + public function parseUrl($url) + { + Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); + + static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + 'user' => null, 'pass' => null, 'fragment' => null); + + $parts = parse_url($url); + + // Need to handle query parsing specially for UTF-8 requirements + if ($this->utf8 && isset($parts['query'])) { + $queryPos = strpos($url, '?'); + if (isset($parts['fragment'])) { + $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1); + } else { + $parts['query'] = substr($url, $queryPos + 1); + } + } + + return $parts + $defaults; + } +} diff --git a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php index 2a05735d..89ac4b30 100644 --- a/app/libs/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php +++ b/app/libs/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php @@ -1,19 +1,19 @@ -=5.3.2" - }, - "autoload": { - "psr-0": { "Guzzle\\Parser": "" } - }, - "target-dir": "Guzzle/Parser", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - } -} +{ + "name": "guzzle/parser", + "homepage": "http://guzzlephp.org/", + "description": "Interchangeable parsers used by Guzzle", + "keywords": ["HTTP", "message", "cookie", "URL", "URI Template"], + "license": "MIT", + "require": { + "php": ">=5.3.2" + }, + "autoload": { + "psr-0": { "Guzzle\\Parser": "" } + }, + "target-dir": "Guzzle/Parser", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + } +} diff --git a/app/libs/vendor/league/plates/.gitignore b/app/libs/vendor/league/plates/.gitignore index c7679272..88e99d50 100644 --- a/app/libs/vendor/league/plates/.gitignore +++ b/app/libs/vendor/league/plates/.gitignore @@ -1,2 +1,2 @@ -vendor +vendor composer.lock \ No newline at end of file diff --git a/app/libs/vendor/league/plates/.travis.yml b/app/libs/vendor/league/plates/.travis.yml index fa3a85bf..63d894de 100644 --- a/app/libs/vendor/league/plates/.travis.yml +++ b/app/libs/vendor/league/plates/.travis.yml @@ -1,16 +1,16 @@ -language: php - -php: - - 5.3 - - 5.4 - - 5.5 - -before_script: - - composer self-update - - composer install - - pyrus install pear/PHP_CodeSniffer - - phpenv rehash - -script: - - phpcs -n --standard=psr2 src/ +language: php + +php: + - 5.3 + - 5.4 + - 5.5 + +before_script: + - composer self-update + - composer install + - pyrus install pear/PHP_CodeSniffer + - phpenv rehash + +script: + - phpcs -n --standard=psr2 src/ - phpunit --coverage-text \ No newline at end of file diff --git a/app/libs/vendor/league/plates/CONTRIBUTING.md b/app/libs/vendor/league/plates/CONTRIBUTING.md index d5044c41..9eebab6e 100644 --- a/app/libs/vendor/league/plates/CONTRIBUTING.md +++ b/app/libs/vendor/league/plates/CONTRIBUTING.md @@ -1,22 +1,22 @@ -# Contributing - -Contributions are **welcome** and will be fully **credited**. - -We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/plates). - -## Pull Requests - -- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). -- **Add tests!** - Your patch won't be accepted if it doesn't have tests. -- **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. -- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. -- **Create topic branches** - Don't ask us to pull from your master branch. -- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. -- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. - -## Running Tests - -``` bash -$ phpunit -``` +# Contributing + +Contributions are **welcome** and will be fully **credited**. + +We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/plates). + +## Pull Requests + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. +- **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date. +- **Consider our release cycle** - We try to follow semver. Randomly breaking public APIs is not an option. +- **Create topic branches** - Don't ask us to pull from your master branch. +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. + +## Running Tests + +``` bash +$ phpunit +``` **Happy coding**! \ No newline at end of file diff --git a/app/libs/vendor/league/plates/README.md b/app/libs/vendor/league/plates/README.md index 9f27ec60..23d8de69 100644 --- a/app/libs/vendor/league/plates/README.md +++ b/app/libs/vendor/league/plates/README.md @@ -1,55 +1,55 @@ -Plates -====== - -[![Build Status](https://travis-ci.org/thephpleague/plates.png?branch=master)](https://travis-ci.org/thephpleague/plates) -[![Total Downloads](https://poser.pugx.org/league/plates/downloads.png)](https://packagist.org/packages/league/plates) -[![Latest Stable Version](https://poser.pugx.org/league/plates/v/stable.png)](https://packagist.org/packages/league/plates) - -Plates is a native PHP template system that’s fast, easy to use and easy to extend. It’s inspired by the excellent [Twig](http://twig.sensiolabs.org/) template engine and tries to bring modern template language functionality to native PHP templates. Plates is designed for developers who prefer to use native PHP templates over compiled templates, such as Twig or Smarty. - -### Highlights - -- Native PHP templates, no new syntax to learn -- Plates is a template system, not a template language -- Plates encourages the use of existing PHP functions -- Template layouts and inheritance -- Template folders for grouping templates into namespaces -- Easy to extend using extensions -- Framework-agnostic, will work with any project -- Decoupled design makes templates easy to test -- Composer ready and PSR-2 compliant - -## Installation - -Plates is available via Composer: - -```json -{ - "require": { - "league/plates": "1.1.*" - } -} -``` - -## Documentation - -Full documentation can be found at [platesphp.com](http://platesphp.com/). - -## Testing - -```bash -$ phpunit -``` - -## Contributing - -Please see [CONTRIBUTING](https://github.com/thephpleague/plates/blob/master/CONTRIBUTING.md) for details. - -## Credits - -- [Jonathan Reinink](https://github.com/reinink) -- [All Contributors](https://github.com/thephpleague/plates/contributors) - -## License - +Plates +====== + +[![Build Status](https://travis-ci.org/thephpleague/plates.png?branch=master)](https://travis-ci.org/thephpleague/plates) +[![Total Downloads](https://poser.pugx.org/league/plates/downloads.png)](https://packagist.org/packages/league/plates) +[![Latest Stable Version](https://poser.pugx.org/league/plates/v/stable.png)](https://packagist.org/packages/league/plates) + +Plates is a native PHP template system that’s fast, easy to use and easy to extend. It’s inspired by the excellent [Twig](http://twig.sensiolabs.org/) template engine and tries to bring modern template language functionality to native PHP templates. Plates is designed for developers who prefer to use native PHP templates over compiled templates, such as Twig or Smarty. + +### Highlights + +- Native PHP templates, no new syntax to learn +- Plates is a template system, not a template language +- Plates encourages the use of existing PHP functions +- Template layouts and inheritance +- Template folders for grouping templates into namespaces +- Easy to extend using extensions +- Framework-agnostic, will work with any project +- Decoupled design makes templates easy to test +- Composer ready and PSR-2 compliant + +## Installation + +Plates is available via Composer: + +```json +{ + "require": { + "league/plates": "1.1.*" + } +} +``` + +## Documentation + +Full documentation can be found at [platesphp.com](http://platesphp.com/). + +## Testing + +```bash +$ phpunit +``` + +## Contributing + +Please see [CONTRIBUTING](https://github.com/thephpleague/plates/blob/master/CONTRIBUTING.md) for details. + +## Credits + +- [Jonathan Reinink](https://github.com/reinink) +- [All Contributors](https://github.com/thephpleague/plates/contributors) + +## License + The MIT License (MIT). Please see [License File](https://github.com/thephpleague/plates/blob/master/LICENSE) for more information. \ No newline at end of file diff --git a/app/libs/vendor/league/plates/composer.json b/app/libs/vendor/league/plates/composer.json index 08cb6ee6..54719c97 100644 --- a/app/libs/vendor/league/plates/composer.json +++ b/app/libs/vendor/league/plates/composer.json @@ -1,29 +1,29 @@ -{ - "name": "league/plates", - "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", - "keywords": [ - "league", - "package", - "templating" - ], - "homepage": "http://platesphp.com", - "license": "MIT", - "authors" : [ - { - "name": "Jonathan Reinink", - "email": "jonathan@reinink.ca", - "role": "Developer" - } - ], - "require-dev": { - "phpunit/phpunit": "3.7.*", - "mikey179/vfsStream": "v1.2.0", - "mockery/mockery": "dev-master@dev" - }, - "autoload": - { - "psr-4": { - "League\\Plates\\": "src" - } - } -} +{ + "name": "league/plates", + "description": "Plates, the native PHP template system that’s fast, easy to use and easy to extend.", + "keywords": [ + "league", + "package", + "templating" + ], + "homepage": "http://platesphp.com", + "license": "MIT", + "authors" : [ + { + "name": "Jonathan Reinink", + "email": "jonathan@reinink.ca", + "role": "Developer" + } + ], + "require-dev": { + "phpunit/phpunit": "3.7.*", + "mikey179/vfsStream": "v1.2.0", + "mockery/mockery": "dev-master@dev" + }, + "autoload": + { + "psr-4": { + "League\\Plates\\": "src" + } + } +} diff --git a/app/libs/vendor/league/plates/phpunit.xml b/app/libs/vendor/league/plates/phpunit.xml index 1b022b27..1b7d59b3 100644 --- a/app/libs/vendor/league/plates/phpunit.xml +++ b/app/libs/vendor/league/plates/phpunit.xml @@ -1,16 +1,16 @@ - - - - - tests/League - - - - - vendor - - - src - - + + + + + tests/League + + + + + vendor + + + src + + \ No newline at end of file diff --git a/app/libs/vendor/league/plates/src/Engine.php b/app/libs/vendor/league/plates/src/Engine.php index db5c6c70..131006c0 100644 --- a/app/libs/vendor/league/plates/src/Engine.php +++ b/app/libs/vendor/league/plates/src/Engine.php @@ -1,236 +1,236 @@ -setDirectory($directory); - $this->setFileExtension($fileExtension); - $this->loadExtension(new Extension\Escape); - $this->loadExtension(new Extension\Batch); - } - - /** - * Set path to templates directory. - * @param string|null $directory Pass null to disable the default directory. - * @return Engine - */ - public function setDirectory($directory) - { - if (!is_null($directory) and !is_string($directory)) { - throw new \LogicException('The directory must be a string or null, ' . gettype($directory) . ' given.'); - } - - if (is_string($directory) and !is_dir($directory)) { - throw new \LogicException('The specified directory "' . $directory . '" does not exist.'); - } - - $this->directory = $directory; - - return $this; - } - - /** - * Set the file extension used by templates. - * @param string|null $fileExtension Pass null to manually set it each time. - * @return Engine - */ - public function setFileExtension($fileExtension) - { - if (!is_string($fileExtension) and !is_null($fileExtension)) { - throw new \LogicException('The file extension must be a string or null, ' . gettype($fileExtension) . ' given.'); - } - - $this->fileExtension = $fileExtension; - - return $this; - } - - /** - * Add a new template folder for grouping templates under different namespaces. - * @param string $namespace - * @param string $directory - * @return Engine - */ - public function addFolder($namespace, $directory) - { - if (!is_string($namespace)) { - throw new \LogicException('The namespace must be a string, ' . gettype($namespace) . ' given.'); - } - - if (!is_string($directory)) { - throw new \LogicException('The directory must be a string, ' . gettype($directory) . ' given.'); - } - - if (!is_dir($directory)) { - throw new \LogicException('The specified directory "' . $directory . '" does not exist.'); - } - - if (isset($this->folders[$namespace])) { - throw new \LogicException('Folder conflict detected. The namespace "' . $namespace . '" is already being used.'); - } - - $this->folders[$namespace] = $directory; - - return $this; - } - - /** - * Load an extension and make additional functions available within templates. - * @param ExtensionExtensionInterface $extension - * @return Engine - */ - public function loadExtension(Extension\ExtensionInterface $extension) - { - if (!is_array($extension->getFunctions())) { - throw new \LogicException('The "' . get_class($extension) . '" getFunctions method must return an array, ' . gettype($extension->getFunctions()) . ' given.'); - } - - if (count($extension->getFunctions()) === 0) { - throw new \LogicException('The extension "' . get_class($extension) . '" has no functions defined.'); - } - - $extension->engine = $this; - - foreach ($extension->getFunctions() as $function => $method) { - - if (!is_string($function) or empty($function) or !is_callable($function, true)) { - throw new \LogicException('The function "' . $function . '" is not a valid function name in the "' . get_class($extension) . '" extension.'); - } - - if (!is_string($method) or empty($method) or !is_callable($method, true)) { - throw new \LogicException('The method "' . $method . '" is not a valid method name in the "' . get_class($extension) . '" extension.'); - } - - if (isset($this->functions[$function]) or in_array($function, array('layout', 'data', 'start', 'end', 'child', 'insert', 'render'))) { - throw new \LogicException('The function "' . $function . '" already exists and cannot be used by the "' . get_class($extension) . '" extension.'); - } - - if (!is_callable(array($extension, $method))) { - throw new \LogicException('The method "' . $method . '" is not callable in the "' . get_class($extension) . '" extension.'); - } - - $this->functions[$function] = array($extension, $method); - } - - return $this; - } - - /** - * Get a loaded extension and method by function name. - * @param string $function - * @return array - */ - public function getFunction($function) - { - if (!is_string($function) or empty($function) or !is_callable($function, true)) { - throw new \LogicException('Not a valid extension function name.'); - } - - if (!$this->functionExists($function)) { - throw new \LogicException('No extensions with the function "' . $function . '" were found.'); - } - - return $this->functions[$function]; - } - - /** - * Check if an extension function exists. - * @param string $method - * @return boolean - */ - public function functionExists($method) - { - return isset($this->functions[$method]); - } - - /** - * Determine the file path of a template. - * @param string $name - * @return string - */ - public function resolvePath($name) - { - if (!is_string($name)) { - throw new \LogicException('The template name must be a string, ' . gettype($name) . ' given.'); - } - - $parts = explode('::', $name); - - if (count($parts) === 1) { - - if (is_null($this->directory)) { - throw new \LogicException('The default directory has not been defined.'); - } - - if ($parts[0] === '') { - throw new \LogicException('The template name cannot be an empty.'); - } - - $filePath = $this->directory . DIRECTORY_SEPARATOR . $parts[0]; - - } else if (count($parts) === 2) { - - if ($parts[0] === '') { - throw new \LogicException('The template name "' . $name . '" is not valid.'); - } - - if ($parts[1] === '') { - throw new \LogicException('The template name "' . $name . '" is not valid.'); - } - - if (!isset($this->folders[$parts[0]])) { - throw new \LogicException('The folder "' . $parts[0] . '" does not exist.'); - } - - $filePath = $this->folders[$parts[0]] . DIRECTORY_SEPARATOR . $parts[1]; - - } else { - throw new \LogicException('The template name "' . $name . '" is not valid.'); - } - - if (!is_null($this->fileExtension)) { - $filePath .= '.' . $this->fileExtension; - } - - if (!is_file($filePath)) { - throw new \LogicException('The specified template "' . $name . '" could not be found at "' . $filePath . '".'); - } - - return $filePath; - } -} +setDirectory($directory); + $this->setFileExtension($fileExtension); + $this->loadExtension(new Extension\Escape); + $this->loadExtension(new Extension\Batch); + } + + /** + * Set path to templates directory. + * @param string|null $directory Pass null to disable the default directory. + * @return Engine + */ + public function setDirectory($directory) + { + if (!is_null($directory) and !is_string($directory)) { + throw new \LogicException('The directory must be a string or null, ' . gettype($directory) . ' given.'); + } + + if (is_string($directory) and !is_dir($directory)) { + throw new \LogicException('The specified directory "' . $directory . '" does not exist.'); + } + + $this->directory = $directory; + + return $this; + } + + /** + * Set the file extension used by templates. + * @param string|null $fileExtension Pass null to manually set it each time. + * @return Engine + */ + public function setFileExtension($fileExtension) + { + if (!is_string($fileExtension) and !is_null($fileExtension)) { + throw new \LogicException('The file extension must be a string or null, ' . gettype($fileExtension) . ' given.'); + } + + $this->fileExtension = $fileExtension; + + return $this; + } + + /** + * Add a new template folder for grouping templates under different namespaces. + * @param string $namespace + * @param string $directory + * @return Engine + */ + public function addFolder($namespace, $directory) + { + if (!is_string($namespace)) { + throw new \LogicException('The namespace must be a string, ' . gettype($namespace) . ' given.'); + } + + if (!is_string($directory)) { + throw new \LogicException('The directory must be a string, ' . gettype($directory) . ' given.'); + } + + if (!is_dir($directory)) { + throw new \LogicException('The specified directory "' . $directory . '" does not exist.'); + } + + if (isset($this->folders[$namespace])) { + throw new \LogicException('Folder conflict detected. The namespace "' . $namespace . '" is already being used.'); + } + + $this->folders[$namespace] = $directory; + + return $this; + } + + /** + * Load an extension and make additional functions available within templates. + * @param ExtensionExtensionInterface $extension + * @return Engine + */ + public function loadExtension(Extension\ExtensionInterface $extension) + { + if (!is_array($extension->getFunctions())) { + throw new \LogicException('The "' . get_class($extension) . '" getFunctions method must return an array, ' . gettype($extension->getFunctions()) . ' given.'); + } + + if (count($extension->getFunctions()) === 0) { + throw new \LogicException('The extension "' . get_class($extension) . '" has no functions defined.'); + } + + $extension->engine = $this; + + foreach ($extension->getFunctions() as $function => $method) { + + if (!is_string($function) or empty($function) or !is_callable($function, true)) { + throw new \LogicException('The function "' . $function . '" is not a valid function name in the "' . get_class($extension) . '" extension.'); + } + + if (!is_string($method) or empty($method) or !is_callable($method, true)) { + throw new \LogicException('The method "' . $method . '" is not a valid method name in the "' . get_class($extension) . '" extension.'); + } + + if (isset($this->functions[$function]) or in_array($function, array('layout', 'data', 'start', 'end', 'child', 'insert', 'render'))) { + throw new \LogicException('The function "' . $function . '" already exists and cannot be used by the "' . get_class($extension) . '" extension.'); + } + + if (!is_callable(array($extension, $method))) { + throw new \LogicException('The method "' . $method . '" is not callable in the "' . get_class($extension) . '" extension.'); + } + + $this->functions[$function] = array($extension, $method); + } + + return $this; + } + + /** + * Get a loaded extension and method by function name. + * @param string $function + * @return array + */ + public function getFunction($function) + { + if (!is_string($function) or empty($function) or !is_callable($function, true)) { + throw new \LogicException('Not a valid extension function name.'); + } + + if (!$this->functionExists($function)) { + throw new \LogicException('No extensions with the function "' . $function . '" were found.'); + } + + return $this->functions[$function]; + } + + /** + * Check if an extension function exists. + * @param string $method + * @return boolean + */ + public function functionExists($method) + { + return isset($this->functions[$method]); + } + + /** + * Determine the file path of a template. + * @param string $name + * @return string + */ + public function resolvePath($name) + { + if (!is_string($name)) { + throw new \LogicException('The template name must be a string, ' . gettype($name) . ' given.'); + } + + $parts = explode('::', $name); + + if (count($parts) === 1) { + + if (is_null($this->directory)) { + throw new \LogicException('The default directory has not been defined.'); + } + + if ($parts[0] === '') { + throw new \LogicException('The template name cannot be an empty.'); + } + + $filePath = $this->directory . DIRECTORY_SEPARATOR . $parts[0]; + + } else if (count($parts) === 2) { + + if ($parts[0] === '') { + throw new \LogicException('The template name "' . $name . '" is not valid.'); + } + + if ($parts[1] === '') { + throw new \LogicException('The template name "' . $name . '" is not valid.'); + } + + if (!isset($this->folders[$parts[0]])) { + throw new \LogicException('The folder "' . $parts[0] . '" does not exist.'); + } + + $filePath = $this->folders[$parts[0]] . DIRECTORY_SEPARATOR . $parts[1]; + + } else { + throw new \LogicException('The template name "' . $name . '" is not valid.'); + } + + if (!is_null($this->fileExtension)) { + $filePath .= '.' . $this->fileExtension; + } + + if (!is_file($filePath)) { + throw new \LogicException('The specified template "' . $name . '" could not be found at "' . $filePath . '".'); + } + + return $filePath; + } +} diff --git a/app/libs/vendor/league/plates/src/Extension/Asset.php b/app/libs/vendor/league/plates/src/Extension/Asset.php index bf4a2ffa..22fd0053 100644 --- a/app/libs/vendor/league/plates/src/Extension/Asset.php +++ b/app/libs/vendor/league/plates/src/Extension/Asset.php @@ -1,50 +1,50 @@ -path = rtrim($path, '/'); - $this->filenameMethod = $filenameMethod; - } - - public function getFunctions() - { - return array( - 'asset' => 'cachedAssetUrl' - ); - } - - public function cachedAssetUrl($url) - { - $filePath = $this->path . '/' . ltrim($url, '/'); - - if (!file_exists($filePath)) { - throw new \LogicException('Unable to locate the asset "' . $url . '" in the "' . $this->path . '" directory.'); - } - - $lastUpdated = filemtime($filePath); - $pathInfo = pathinfo($url); - - if ($pathInfo['dirname'] === '.') { - $directory = ''; - } elseif ($pathInfo['dirname'] === '/') { - $directory = '/'; - } else { - $directory = $pathInfo['dirname'] . '/'; - } - - if ($this->filenameMethod) { - return $directory . $pathInfo['filename'] . '.' . $lastUpdated . '.' . $pathInfo['extension']; - } else { - return $directory . $pathInfo['filename'] . '.' . $pathInfo['extension'] . '?v=' . $lastUpdated; - } - } -} +path = rtrim($path, '/'); + $this->filenameMethod = $filenameMethod; + } + + public function getFunctions() + { + return array( + 'asset' => 'cachedAssetUrl' + ); + } + + public function cachedAssetUrl($url) + { + $filePath = $this->path . '/' . ltrim($url, '/'); + + if (!file_exists($filePath)) { + throw new \LogicException('Unable to locate the asset "' . $url . '" in the "' . $this->path . '" directory.'); + } + + $lastUpdated = filemtime($filePath); + $pathInfo = pathinfo($url); + + if ($pathInfo['dirname'] === '.') { + $directory = ''; + } elseif ($pathInfo['dirname'] === '/') { + $directory = '/'; + } else { + $directory = $pathInfo['dirname'] . '/'; + } + + if ($this->filenameMethod) { + return $directory . $pathInfo['filename'] . '.' . $lastUpdated . '.' . $pathInfo['extension']; + } else { + return $directory . $pathInfo['filename'] . '.' . $pathInfo['extension'] . '?v=' . $lastUpdated; + } + } +} diff --git a/app/libs/vendor/league/plates/src/Extension/Batch.php b/app/libs/vendor/league/plates/src/Extension/Batch.php index 0b718566..2c0413aa 100644 --- a/app/libs/vendor/league/plates/src/Extension/Batch.php +++ b/app/libs/vendor/league/plates/src/Extension/Batch.php @@ -1,31 +1,31 @@ - 'runBatch' - ); - } - - public function runBatch($var, $methods) - { - foreach (explode('|', $methods) as $method) { - if ($this->engine->functionExists($method)) { - $var = $this->template->$method($var); - } else if (is_callable($method)) { - $var = call_user_func($method, $var); - } else { - throw new \LogicException('The batch method was unable to find the supplied "' . $method . '" function.'); - } - } - - return $var; - } -} + 'runBatch' + ); + } + + public function runBatch($var, $methods) + { + foreach (explode('|', $methods) as $method) { + if ($this->engine->functionExists($method)) { + $var = $this->template->$method($var); + } else if (is_callable($method)) { + $var = call_user_func($method, $var); + } else { + throw new \LogicException('The batch method was unable to find the supplied "' . $method . '" function.'); + } + } + + return $var; + } +} diff --git a/app/libs/vendor/league/plates/src/Extension/Escape.php b/app/libs/vendor/league/plates/src/Extension/Escape.php index 3fe36baf..7df957f8 100644 --- a/app/libs/vendor/league/plates/src/Extension/Escape.php +++ b/app/libs/vendor/league/plates/src/Extension/Escape.php @@ -1,26 +1,26 @@ - 'escapeString', - 'e' => 'escapeString' - ); - } - - public function escapeString($string) - { - return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); - } -} - -if (!defined('ENT_SUBSTITUTE')) { - define('ENT_SUBSTITUTE', 8); -} + 'escapeString', + 'e' => 'escapeString' + ); + } + + public function escapeString($string) + { + return htmlspecialchars($string, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); + } +} + +if (!defined('ENT_SUBSTITUTE')) { + define('ENT_SUBSTITUTE', 8); +} diff --git a/app/libs/vendor/league/plates/src/Extension/ExtensionInterface.php b/app/libs/vendor/league/plates/src/Extension/ExtensionInterface.php index 56b60a3a..283a7833 100644 --- a/app/libs/vendor/league/plates/src/Extension/ExtensionInterface.php +++ b/app/libs/vendor/league/plates/src/Extension/ExtensionInterface.php @@ -1,8 +1,8 @@ -uri = $uri; - $this->parts = explode('/', $this->uri); - } - - public function getFunctions() - { - return array( - 'uri' => 'runUri' - ); - } - - public function runUri($var1 = null, $var2 = null, $var3 = null, $var4 = null) - { - if (is_null($var1)) { - return $this->uri; - } - - if (is_numeric($var1) and is_null($var2) and is_null($var3) and is_null($var4)) { - return $this->parts[$var1]; - } - - if (is_numeric($var1) and is_string($var2) and is_null($var3) and is_null($var4)) { - return $this->parts[$var1] === $var2; - } - - if (is_numeric($var1) and is_string($var2) and is_string($var3) and is_null($var4)) { - if ($this->parts[$var1] === $var2) { - return $var3; - } else { - return false; - } - } - - if (is_numeric($var1) and is_string($var2) and is_string($var3) and is_string($var4)) { - if ($this->parts[$var1] === $var2) { - return $var3; - } else { - return $var4; - } - } - - if (is_string($var1) and is_null($var2) and is_null($var3) and is_null($var4)) { - return preg_match('#^' . $var1 . '$#', $this->uri) === 1; - } - - if (is_string($var1) and is_string($var2) and is_null($var3) and is_null($var4)) { - if (preg_match('#^' . $var1 . '$#', $this->uri) === 1) { - return $var2; - } else { - return false; - } - } - - if (is_string($var1) and is_string($var2) and is_string($var3) and is_null($var4)) { - if (preg_match('#^' . $var1 . '$#', $this->uri) === 1) { - return $var2; - } else { - return $var3; - } - } - - throw new \LogicException('Invalid use of the uri() method.'); - } -} +uri = $uri; + $this->parts = explode('/', $this->uri); + } + + public function getFunctions() + { + return array( + 'uri' => 'runUri' + ); + } + + public function runUri($var1 = null, $var2 = null, $var3 = null, $var4 = null) + { + if (is_null($var1)) { + return $this->uri; + } + + if (is_numeric($var1) and is_null($var2) and is_null($var3) and is_null($var4)) { + return $this->parts[$var1]; + } + + if (is_numeric($var1) and is_string($var2) and is_null($var3) and is_null($var4)) { + return $this->parts[$var1] === $var2; + } + + if (is_numeric($var1) and is_string($var2) and is_string($var3) and is_null($var4)) { + if ($this->parts[$var1] === $var2) { + return $var3; + } else { + return false; + } + } + + if (is_numeric($var1) and is_string($var2) and is_string($var3) and is_string($var4)) { + if ($this->parts[$var1] === $var2) { + return $var3; + } else { + return $var4; + } + } + + if (is_string($var1) and is_null($var2) and is_null($var3) and is_null($var4)) { + return preg_match('#^' . $var1 . '$#', $this->uri) === 1; + } + + if (is_string($var1) and is_string($var2) and is_null($var3) and is_null($var4)) { + if (preg_match('#^' . $var1 . '$#', $this->uri) === 1) { + return $var2; + } else { + return false; + } + } + + if (is_string($var1) and is_string($var2) and is_string($var3) and is_null($var4)) { + if (preg_match('#^' . $var1 . '$#', $this->uri) === 1) { + return $var2; + } else { + return $var3; + } + } + + throw new \LogicException('Invalid use of the uri() method.'); + } +} diff --git a/app/libs/vendor/league/plates/src/Template.php b/app/libs/vendor/league/plates/src/Template.php index 590b709f..c867e8e1 100644 --- a/app/libs/vendor/league/plates/src/Template.php +++ b/app/libs/vendor/league/plates/src/Template.php @@ -1,87 +1,87 @@ -_internal['engine'] = $engine; - } - - public function __call($name, $arguments) - { - $function = $this->_internal['engine']->getFunction($name); - $function[0]->template = $this; - - return call_user_func_array($function, $arguments); - } - - public function data(Array $data = null) - { - if (!is_null($data)) { - foreach ($data as $name => $value) { - $this->$name = $value; - } - } - } - - public function layout($name, Array $data = null) - { - $this->data($data); - - $this->_internal['layout'] = $name; - } - - public function start($name) - { - $this->_internal['sections'][] = $name; - - ob_start(); - } - - public function end() - { - if (!isset($this->_internal['sections']) or !count($this->_internal['sections'])) { - throw new \LogicException('You must start a section before you can end it.'); - } - - $this->{end($this->_internal['sections'])} = ob_get_clean(); - - array_pop($this->_internal['sections']); - } - - public function child() - { - return $this->_internal['child']; - } - - public function insert($name, Array $data = null) - { - $this->data($data); - - include $this->_internal['engine']->resolvePath($name); - } - - public function render($name, Array $data = null) - { - $this->data($data); - - ob_start(); - - include($this->_internal['engine']->resolvePath($name)); - - if (isset($this->_internal['layout'])) { - - $this->_internal['child'] = ob_get_contents(); - - ob_clean(); - - include($this->_internal['engine']->resolvePath($this->_internal['layout'])); - } - - return ob_get_clean(); - } -} +_internal['engine'] = $engine; + } + + public function __call($name, $arguments) + { + $function = $this->_internal['engine']->getFunction($name); + $function[0]->template = $this; + + return call_user_func_array($function, $arguments); + } + + public function data(Array $data = null) + { + if (!is_null($data)) { + foreach ($data as $name => $value) { + $this->$name = $value; + } + } + } + + public function layout($name, Array $data = null) + { + $this->data($data); + + $this->_internal['layout'] = $name; + } + + public function start($name) + { + $this->_internal['sections'][] = $name; + + ob_start(); + } + + public function end() + { + if (!isset($this->_internal['sections']) or !count($this->_internal['sections'])) { + throw new \LogicException('You must start a section before you can end it.'); + } + + $this->{end($this->_internal['sections'])} = ob_get_clean(); + + array_pop($this->_internal['sections']); + } + + public function child() + { + return $this->_internal['child']; + } + + public function insert($name, Array $data = null) + { + $this->data($data); + + include $this->_internal['engine']->resolvePath($name); + } + + public function render($name, Array $data = null) + { + $this->data($data); + + ob_start(); + + include($this->_internal['engine']->resolvePath($name)); + + if (isset($this->_internal['layout'])) { + + $this->_internal['child'] = ob_get_contents(); + + ob_clean(); + + include($this->_internal['engine']->resolvePath($this->_internal['layout'])); + } + + return ob_get_clean(); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/EngineTest.php b/app/libs/vendor/league/plates/tests/League/Plates/EngineTest.php index d9dc5fa1..99a3b788 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/EngineTest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/EngineTest.php @@ -1,230 +1,230 @@ -engine = new Engine; - - vfsStream::setup('templates'); - vfsStream::create( - array( - 'home.php' => '', - 'emails' => array( - 'welcome.php' => '' - ) - ) - ); - } - - public function testCanCreateEngine() - { - $this->assertInstanceOf('League\Plates\Engine', $this->engine); - } - - public function testSetValidDirectory() - { - $this->assertInstanceOf('League\Plates\Engine', $this->engine->setDirectory(null)); - $this->assertInstanceOf('League\Plates\Engine', $this->engine->setDirectory(vfsStream::url('templates'))); - } - - public function testSetInvalidDirectory() - { - $this->setExpectedException('LogicException'); - $this->engine->setDirectory(vfsStream::url('does/not/exist')); - } - - public function testSetInvalidDirectoryFileType() - { - $this->setExpectedException('LogicException'); - $this->engine->setDirectory(array()); - } - - public function testSetValidFileExtension() - { - $this->assertInstanceOf('League\Plates\Engine', $this->engine->setFileExtension('tpl')); - $this->assertInstanceOf('League\Plates\Engine', $this->engine->setFileExtension(null)); - } - - public function testSetInvalidFileExtension() - { - $this->setExpectedException('LogicException'); - $this->engine->setFileExtension(array()); - } - - public function testAddValidFolder() - { - $this->assertInstanceOf('League\Plates\Engine', $this->engine->addFolder('emails', vfsStream::url('templates/emails'))); - } - - public function testAddFolderWithInvalidNamespace() - { - $this->setExpectedException('LogicException'); - $this->engine->addFolder(array(), vfsStream::url('templates')); - } - - public function testAddFolderWithInvalidDirectory() - { - $this->setExpectedException('LogicException'); - $this->engine->addFolder('namespace', vfsStream::url('does/not/exist')); - } - - public function testAddFolderWithInvalidDirectoryFileType() - { - $this->setExpectedException('LogicException'); - $this->engine->addFolder('namespace', array()); - } - - public function testAddFolderDirectoryWithNamespaceConflict() - { - $this->setExpectedException('LogicException'); - $this->engine->addFolder('namespace', vfsStream::url('templates')); - $this->engine->addFolder('namespace', vfsStream::url('templates')); - } - - public function testLoadValidExtension() - { - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array('function' => 'method')) - ->mock(); - $this->assertInstanceOf('League\Plates\Engine', $this->engine->loadExtension($extension)); - } - - public function testLoadExtensionWithInvalidFunctionsFileType() - { - $this->setExpectedException('LogicException'); - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(null) - ->mock(); - $this->engine->loadExtension($extension); - } - - public function testLoadExtensionWithEmptyFunctionsArray() - { - $this->setExpectedException('LogicException'); - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array()) - ->mock(); - $this->engine->loadExtension($extension); - } - - public function testLoadExtensionWithInvalidFunctionName() - { - $this->setExpectedException('LogicException'); - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array(null => 'method')) - ->mock(); - $this->engine->loadExtension($extension); - } - - public function testLoadExtensionWithInvalidMethodName() - { - $this->setExpectedException('LogicException'); - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array('function' => null)) - ->mock(); - $this->engine->loadExtension($extension); - } - - public function testLoadExtensionsWithFunctionNameConflicts() - { - $this->setExpectedException('LogicException'); - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array('function' => 'method')) - ->mock(); - $this->engine->loadExtension($extension); - $this->engine->loadExtension($extension); - } - - public function testGetFunctionWithInvalidFunction() - { - $this->setExpectedException('LogicException'); - $this->engine->getFunction(null); - } - - public function testGetExtensionWithMissingFunction() - { - $this->setExpectedException('LogicException'); - $this->engine->getFunction('function'); - } - - public function testGetFunctionWithValidFunction() - { - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array('function' => 'method')) - ->mock(); - $this->engine->loadExtension($extension); - $this->assertInternalType('array', $this->engine->getFunction('function')); - } - - public function testFunctionExistsReturnsTrue() - { - $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') - ->shouldReceive('getFunctions') - ->andReturn(array('function' => 'method')) - ->mock(); - $this->engine->loadExtension($extension); - $this->assertTrue($this->engine->functionExists('function')); - } - - public function testMethodExistsReturnsFalse() - { - $this->assertFalse($this->engine->functionExists('function')); - } - - public function testResolvePathWithInvalidPath() - { - foreach (array('', 'a::b::c', '::b', 'a::', array()) as $var) { - try { - $this->engine->resolvePath($var); - $this->fail('No exception thrown for invalid path "' . gettype($var) . '".'); - } catch (\LogicException $expected) { - // Test passed - } - } - } - - public function testResolvePathWithValidTemplate() - { - $this->engine->setDirectory(vfsStream::url('templates')); - $this->assertInternalType('string', $this->engine->resolvePath('home')); - } - - public function testResolvePathWithInvalidTemplate() - { - $this->setExpectedException('LogicException'); - $this->engine->resolvePath('template_that_does_not_exist'); - } - - public function testResolvePathWithValidFolderAndValidTemplate() - { - $this->engine->addFolder('emails', vfsStream::url('templates/emails')); - $this->assertInternalType('string', $this->engine->resolvePath('emails::welcome')); - } - - public function testResolvePathWithInvalidFolder() - { - $this->setExpectedException('LogicException'); - $this->engine->resolvePath('folder_that_does_not_exist::any_template'); - } - - public function testResolvePathWithInvalidFolderTemplate() - { - $this->setExpectedException('LogicException'); - $this->engine->addFolder('emails', vfsStream::url('templates/emails')); - $this->engine->resolvePath('emails::template_that_does_not_exist'); - } -} +engine = new Engine; + + vfsStream::setup('templates'); + vfsStream::create( + array( + 'home.php' => '', + 'emails' => array( + 'welcome.php' => '' + ) + ) + ); + } + + public function testCanCreateEngine() + { + $this->assertInstanceOf('League\Plates\Engine', $this->engine); + } + + public function testSetValidDirectory() + { + $this->assertInstanceOf('League\Plates\Engine', $this->engine->setDirectory(null)); + $this->assertInstanceOf('League\Plates\Engine', $this->engine->setDirectory(vfsStream::url('templates'))); + } + + public function testSetInvalidDirectory() + { + $this->setExpectedException('LogicException'); + $this->engine->setDirectory(vfsStream::url('does/not/exist')); + } + + public function testSetInvalidDirectoryFileType() + { + $this->setExpectedException('LogicException'); + $this->engine->setDirectory(array()); + } + + public function testSetValidFileExtension() + { + $this->assertInstanceOf('League\Plates\Engine', $this->engine->setFileExtension('tpl')); + $this->assertInstanceOf('League\Plates\Engine', $this->engine->setFileExtension(null)); + } + + public function testSetInvalidFileExtension() + { + $this->setExpectedException('LogicException'); + $this->engine->setFileExtension(array()); + } + + public function testAddValidFolder() + { + $this->assertInstanceOf('League\Plates\Engine', $this->engine->addFolder('emails', vfsStream::url('templates/emails'))); + } + + public function testAddFolderWithInvalidNamespace() + { + $this->setExpectedException('LogicException'); + $this->engine->addFolder(array(), vfsStream::url('templates')); + } + + public function testAddFolderWithInvalidDirectory() + { + $this->setExpectedException('LogicException'); + $this->engine->addFolder('namespace', vfsStream::url('does/not/exist')); + } + + public function testAddFolderWithInvalidDirectoryFileType() + { + $this->setExpectedException('LogicException'); + $this->engine->addFolder('namespace', array()); + } + + public function testAddFolderDirectoryWithNamespaceConflict() + { + $this->setExpectedException('LogicException'); + $this->engine->addFolder('namespace', vfsStream::url('templates')); + $this->engine->addFolder('namespace', vfsStream::url('templates')); + } + + public function testLoadValidExtension() + { + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array('function' => 'method')) + ->mock(); + $this->assertInstanceOf('League\Plates\Engine', $this->engine->loadExtension($extension)); + } + + public function testLoadExtensionWithInvalidFunctionsFileType() + { + $this->setExpectedException('LogicException'); + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(null) + ->mock(); + $this->engine->loadExtension($extension); + } + + public function testLoadExtensionWithEmptyFunctionsArray() + { + $this->setExpectedException('LogicException'); + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array()) + ->mock(); + $this->engine->loadExtension($extension); + } + + public function testLoadExtensionWithInvalidFunctionName() + { + $this->setExpectedException('LogicException'); + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array(null => 'method')) + ->mock(); + $this->engine->loadExtension($extension); + } + + public function testLoadExtensionWithInvalidMethodName() + { + $this->setExpectedException('LogicException'); + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array('function' => null)) + ->mock(); + $this->engine->loadExtension($extension); + } + + public function testLoadExtensionsWithFunctionNameConflicts() + { + $this->setExpectedException('LogicException'); + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array('function' => 'method')) + ->mock(); + $this->engine->loadExtension($extension); + $this->engine->loadExtension($extension); + } + + public function testGetFunctionWithInvalidFunction() + { + $this->setExpectedException('LogicException'); + $this->engine->getFunction(null); + } + + public function testGetExtensionWithMissingFunction() + { + $this->setExpectedException('LogicException'); + $this->engine->getFunction('function'); + } + + public function testGetFunctionWithValidFunction() + { + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array('function' => 'method')) + ->mock(); + $this->engine->loadExtension($extension); + $this->assertInternalType('array', $this->engine->getFunction('function')); + } + + public function testFunctionExistsReturnsTrue() + { + $extension = \Mockery::mock('League\Plates\Extension\ExtensionInterface') + ->shouldReceive('getFunctions') + ->andReturn(array('function' => 'method')) + ->mock(); + $this->engine->loadExtension($extension); + $this->assertTrue($this->engine->functionExists('function')); + } + + public function testMethodExistsReturnsFalse() + { + $this->assertFalse($this->engine->functionExists('function')); + } + + public function testResolvePathWithInvalidPath() + { + foreach (array('', 'a::b::c', '::b', 'a::', array()) as $var) { + try { + $this->engine->resolvePath($var); + $this->fail('No exception thrown for invalid path "' . gettype($var) . '".'); + } catch (\LogicException $expected) { + // Test passed + } + } + } + + public function testResolvePathWithValidTemplate() + { + $this->engine->setDirectory(vfsStream::url('templates')); + $this->assertInternalType('string', $this->engine->resolvePath('home')); + } + + public function testResolvePathWithInvalidTemplate() + { + $this->setExpectedException('LogicException'); + $this->engine->resolvePath('template_that_does_not_exist'); + } + + public function testResolvePathWithValidFolderAndValidTemplate() + { + $this->engine->addFolder('emails', vfsStream::url('templates/emails')); + $this->assertInternalType('string', $this->engine->resolvePath('emails::welcome')); + } + + public function testResolvePathWithInvalidFolder() + { + $this->setExpectedException('LogicException'); + $this->engine->resolvePath('folder_that_does_not_exist::any_template'); + } + + public function testResolvePathWithInvalidFolderTemplate() + { + $this->setExpectedException('LogicException'); + $this->engine->addFolder('emails', vfsStream::url('templates/emails')); + $this->engine->resolvePath('emails::template_that_does_not_exist'); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/Extension/AssetTest.php b/app/libs/vendor/league/plates/tests/League/Plates/Extension/AssetTest.php index 21035f23..21cf54b4 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/Extension/AssetTest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/Extension/AssetTest.php @@ -1,45 +1,45 @@ -extension = new Asset(realpath('tests/assets')); - } - - public function testCanCreateExtension() - { - $this->assertInstanceOf('League\Plates\Extension\Asset', $this->extension); - } - - public function testGetFunctionsReturnsAnArray() - { - $this->assertInternalType('array', $this->extension->getFunctions()); - } - - public function testGetFunctionsReturnsAtLeastOneRecord() - { - $this->assertTrue(count($this->extension->getFunctions()) > 0); - } - - public function testCachedAssetUrl() - { - $this->assertTrue($this->extension->cachedAssetUrl('styles.css') === 'styles.css?v=' . filemtime(realpath('tests/assets/styles.css'))); - } - - public function testCachedAssetUrlUsingFilenameMethod() - { - $this->extension = new Asset(realpath('tests/assets'), true); - $this->assertTrue($this->extension->cachedAssetUrl('styles.css') === 'styles.' . filemtime(realpath('tests/assets/styles.css')) . '.css'); - } - - public function testFileNotFoundException() - { - $this->setExpectedException('LogicException'); - $this->extension->cachedAssetUrl('404.css'); - } -} +extension = new Asset(realpath('tests/assets')); + } + + public function testCanCreateExtension() + { + $this->assertInstanceOf('League\Plates\Extension\Asset', $this->extension); + } + + public function testGetFunctionsReturnsAnArray() + { + $this->assertInternalType('array', $this->extension->getFunctions()); + } + + public function testGetFunctionsReturnsAtLeastOneRecord() + { + $this->assertTrue(count($this->extension->getFunctions()) > 0); + } + + public function testCachedAssetUrl() + { + $this->assertTrue($this->extension->cachedAssetUrl('styles.css') === 'styles.css?v=' . filemtime(realpath('tests/assets/styles.css'))); + } + + public function testCachedAssetUrlUsingFilenameMethod() + { + $this->extension = new Asset(realpath('tests/assets'), true); + $this->assertTrue($this->extension->cachedAssetUrl('styles.css') === 'styles.' . filemtime(realpath('tests/assets/styles.css')) . '.css'); + } + + public function testFileNotFoundException() + { + $this->setExpectedException('LogicException'); + $this->extension->cachedAssetUrl('404.css'); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/Extension/BatchTest.php b/app/libs/vendor/league/plates/tests/League/Plates/Extension/BatchTest.php index 18b30836..fd5818fa 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/Extension/BatchTest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/Extension/BatchTest.php @@ -1,43 +1,43 @@ -extension = new Batch; - $this->extension->engine = new \League\Plates\Engine(); - $this->extension->template = new \League\Plates\Template($this->extension->engine); - } - - public function testCanCreateExtension() - { - $this->assertInstanceOf('League\Plates\Extension\Batch', $this->extension); - } - - public function testGetFunctionsReturnsAnArray() - { - $this->assertInternalType('array', $this->extension->getFunctions()); - } - - public function testGetFunctionsReturnsAtLeastOneRecord() - { - $this->assertTrue(count($this->extension->getFunctions()) > 0); - } - - public function testRunBatch() - { - $this->assertTrue($this->extension->runBatch('Sweet ', 'trim') === 'Sweet'); - $this->assertTrue($this->extension->runBatch('Jonathan', 'strtoupper|strtolower') === 'jonathan'); - $this->assertTrue($this->extension->runBatch('Jonathan', 'e|strtolower') === 'jonathan'); - } - - public function testRunBatchException() - { - $this->setExpectedException('LogicException'); - $this->assertTrue($this->extension->runBatch('Jonathan', 'somefunctionthatwillneverexist')); - } -} +extension = new Batch; + $this->extension->engine = new \League\Plates\Engine(); + $this->extension->template = new \League\Plates\Template($this->extension->engine); + } + + public function testCanCreateExtension() + { + $this->assertInstanceOf('League\Plates\Extension\Batch', $this->extension); + } + + public function testGetFunctionsReturnsAnArray() + { + $this->assertInternalType('array', $this->extension->getFunctions()); + } + + public function testGetFunctionsReturnsAtLeastOneRecord() + { + $this->assertTrue(count($this->extension->getFunctions()) > 0); + } + + public function testRunBatch() + { + $this->assertTrue($this->extension->runBatch('Sweet ', 'trim') === 'Sweet'); + $this->assertTrue($this->extension->runBatch('Jonathan', 'strtoupper|strtolower') === 'jonathan'); + $this->assertTrue($this->extension->runBatch('Jonathan', 'e|strtolower') === 'jonathan'); + } + + public function testRunBatchException() + { + $this->setExpectedException('LogicException'); + $this->assertTrue($this->extension->runBatch('Jonathan', 'somefunctionthatwillneverexist')); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/Extension/EscapeTest.php b/app/libs/vendor/league/plates/tests/League/Plates/Extension/EscapeTest.php index 3b1a3829..4ef5c93c 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/Extension/EscapeTest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/Extension/EscapeTest.php @@ -1,35 +1,35 @@ -extension = new Escape; - } - - public function testCanCreateExtension() - { - $this->assertInstanceOf('League\Plates\Extension\Escape', $this->extension); - } - - public function testGetFunctionsReturnsAnArray() - { - $this->assertInternalType('array', $this->extension->getFunctions()); - } - - public function testGetFunctionsReturnsAtLeastOneRecord() - { - $this->assertTrue(count($this->extension->getFunctions()) > 0); - } - - public function testStringEscaping() - { - $this->assertTrue($this->extension->escapeString('') === ''); - $this->assertTrue($this->extension->escapeString('Test') === 'Test'); - $this->assertTrue($this->extension->escapeString('\'') === '''); - } -} +extension = new Escape; + } + + public function testCanCreateExtension() + { + $this->assertInstanceOf('League\Plates\Extension\Escape', $this->extension); + } + + public function testGetFunctionsReturnsAnArray() + { + $this->assertInternalType('array', $this->extension->getFunctions()); + } + + public function testGetFunctionsReturnsAtLeastOneRecord() + { + $this->assertTrue(count($this->extension->getFunctions()) > 0); + } + + public function testStringEscaping() + { + $this->assertTrue($this->extension->escapeString('') === ''); + $this->assertTrue($this->extension->escapeString('Test') === 'Test'); + $this->assertTrue($this->extension->escapeString('\'') === '''); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/Extension/URITest.php b/app/libs/vendor/league/plates/tests/League/Plates/Extension/URITest.php index 7728b695..6c30e7c7 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/Extension/URITest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/Extension/URITest.php @@ -1,71 +1,71 @@ -extension = new URI('/green/red/blue'); - } - - public function testCanCreateExtension() - { - $this->assertInstanceOf('League\Plates\Extension\URI', $this->extension); - } - - public function testGetFunctionsReturnsAnArray() - { - $this->assertInternalType('array', $this->extension->getFunctions()); - } - - public function testGetFunctionsReturnsAtLeastOneRecord() - { - $this->assertTrue(count($this->extension->getFunctions()) > 0); - } - - public function testGetUrl() - { - $this->assertTrue($this->extension->runUri() === '/green/red/blue'); - } - - public function testGetSpecifiedSegment() - { - $this->assertTrue($this->extension->runUri(1) === 'green'); - $this->assertTrue($this->extension->runUri(2) === 'red'); - $this->assertTrue($this->extension->runUri(3) === 'blue'); - } - - public function testSegmentMatch() - { - $this->assertTrue($this->extension->runUri(1, 'green')); - $this->assertFalse($this->extension->runUri(1, 'red')); - } - - public function testSegmentMatchSuccessResponse() - { - $this->assertTrue($this->extension->runUri(1, 'green', 'success') === 'success'); - } - - public function testSegmentMatchFailureResponse() - { - $this->assertTrue($this->extension->runUri(1, 'red', 'success', 'fail') === 'fail'); - } - - public function testRegexMatch() - { - $this->assertTrue($this->extension->runUri('/[a-z]+/red/blue')); - } - - public function testRegexMatchSuccessResponse() - { - $this->assertTrue($this->extension->runUri('/[a-z]+/red/blue', 'success') === 'success'); - } - - public function testRegexMatchFailureResponse() - { - $this->assertTrue($this->extension->runUri('/[0-9]+/red/blue', 'success', 'fail') === 'fail'); - } -} +extension = new URI('/green/red/blue'); + } + + public function testCanCreateExtension() + { + $this->assertInstanceOf('League\Plates\Extension\URI', $this->extension); + } + + public function testGetFunctionsReturnsAnArray() + { + $this->assertInternalType('array', $this->extension->getFunctions()); + } + + public function testGetFunctionsReturnsAtLeastOneRecord() + { + $this->assertTrue(count($this->extension->getFunctions()) > 0); + } + + public function testGetUrl() + { + $this->assertTrue($this->extension->runUri() === '/green/red/blue'); + } + + public function testGetSpecifiedSegment() + { + $this->assertTrue($this->extension->runUri(1) === 'green'); + $this->assertTrue($this->extension->runUri(2) === 'red'); + $this->assertTrue($this->extension->runUri(3) === 'blue'); + } + + public function testSegmentMatch() + { + $this->assertTrue($this->extension->runUri(1, 'green')); + $this->assertFalse($this->extension->runUri(1, 'red')); + } + + public function testSegmentMatchSuccessResponse() + { + $this->assertTrue($this->extension->runUri(1, 'green', 'success') === 'success'); + } + + public function testSegmentMatchFailureResponse() + { + $this->assertTrue($this->extension->runUri(1, 'red', 'success', 'fail') === 'fail'); + } + + public function testRegexMatch() + { + $this->assertTrue($this->extension->runUri('/[a-z]+/red/blue')); + } + + public function testRegexMatchSuccessResponse() + { + $this->assertTrue($this->extension->runUri('/[a-z]+/red/blue', 'success') === 'success'); + } + + public function testRegexMatchFailureResponse() + { + $this->assertTrue($this->extension->runUri('/[0-9]+/red/blue', 'success', 'fail') === 'fail'); + } +} diff --git a/app/libs/vendor/league/plates/tests/League/Plates/TemplateTest.php b/app/libs/vendor/league/plates/tests/League/Plates/TemplateTest.php index c425d060..c674d70a 100644 --- a/app/libs/vendor/league/plates/tests/League/Plates/TemplateTest.php +++ b/app/libs/vendor/league/plates/tests/League/Plates/TemplateTest.php @@ -1,81 +1,81 @@ -template = new Template(new Engine(realpath('tests/assets'), 'tpl')); - } - - public function testCanCreateTemplate() - { - $this->assertInstanceOf('League\Plates\Template', $this->template); - } - - public function testFunctionCall() - { - $this->assertTrue($this->template->batch('Jonathan ', 'trim') === 'Jonathan'); - } - - public function testSetLayout() - { - $this->assertNull($this->template->layout('test')); - } - - public function testSetLayoutWithData() - { - $this->template->layout('test', array('name' => 'Jonathan')); - $this->assertTrue($this->template->name === 'Jonathan'); - } - - public function testSetData() - { - $this->template->data(array('name' => 'Jonathan')); - $this->assertTrue(isset($this->template->name)); - } - - public function testSetVariable() - { - $this->template->name = 'Jonathan'; - $this->assertTrue($this->template->name === 'Jonathan'); - } - - public function testSection() - { - $this->template->start('name'); - echo 'Jonathan'; - $this->template->end(); - $this->assertTrue($this->template->name === 'Jonathan'); - } - - public function testInsert() - { - $this->expectOutputString('Jonathan'); - $this->template->insert('basic-template'); - } - - public function testInsertWithData() - { - $this->expectOutputString('Jonathan'); - $this->template->insert('template-with-data', array('name' => 'Jonathan')); - } - - public function testRender() - { - $this->assertTrue($this->template->render('basic-template') === 'Jonathan'); - } - - public function testRenderWithLayout() - { - $this->assertTrue($this->template->render('template-with-layout') === 'Hello, Jonathan'); - } - - public function testRenderWithData() - { - $this->assertTrue($this->template->render('template-with-data', array('name' => 'Jonathan')) === 'Jonathan'); - } -} +template = new Template(new Engine(realpath('tests/assets'), 'tpl')); + } + + public function testCanCreateTemplate() + { + $this->assertInstanceOf('League\Plates\Template', $this->template); + } + + public function testFunctionCall() + { + $this->assertTrue($this->template->batch('Jonathan ', 'trim') === 'Jonathan'); + } + + public function testSetLayout() + { + $this->assertNull($this->template->layout('test')); + } + + public function testSetLayoutWithData() + { + $this->template->layout('test', array('name' => 'Jonathan')); + $this->assertTrue($this->template->name === 'Jonathan'); + } + + public function testSetData() + { + $this->template->data(array('name' => 'Jonathan')); + $this->assertTrue(isset($this->template->name)); + } + + public function testSetVariable() + { + $this->template->name = 'Jonathan'; + $this->assertTrue($this->template->name === 'Jonathan'); + } + + public function testSection() + { + $this->template->start('name'); + echo 'Jonathan'; + $this->template->end(); + $this->assertTrue($this->template->name === 'Jonathan'); + } + + public function testInsert() + { + $this->expectOutputString('Jonathan'); + $this->template->insert('basic-template'); + } + + public function testInsertWithData() + { + $this->expectOutputString('Jonathan'); + $this->template->insert('template-with-data', array('name' => 'Jonathan')); + } + + public function testRender() + { + $this->assertTrue($this->template->render('basic-template') === 'Jonathan'); + } + + public function testRenderWithLayout() + { + $this->assertTrue($this->template->render('template-with-layout') === 'Hello, Jonathan'); + } + + public function testRenderWithData() + { + $this->assertTrue($this->template->render('template-with-data', array('name' => 'Jonathan')) === 'Jonathan'); + } +} diff --git a/app/libs/vendor/react/promise/.gitignore b/app/libs/vendor/react/promise/.gitignore index a8bba96f..c4bcb78f 100644 --- a/app/libs/vendor/react/promise/.gitignore +++ b/app/libs/vendor/react/promise/.gitignore @@ -1,4 +1,4 @@ -composer.lock -composer.phar -phpunit.xml -vendor/ +composer.lock +composer.phar +phpunit.xml +vendor/ diff --git a/app/libs/vendor/react/promise/.travis.yml b/app/libs/vendor/react/promise/.travis.yml index 2db781ce..b0b5c89e 100644 --- a/app/libs/vendor/react/promise/.travis.yml +++ b/app/libs/vendor/react/promise/.travis.yml @@ -1,10 +1,10 @@ -language: php - -php: - - 5.4 - - 5.5 - -before_script: - - composer install - -script: phpunit --coverage-text +language: php + +php: + - 5.4 + - 5.5 + +before_script: + - composer install + +script: phpunit --coverage-text diff --git a/app/libs/vendor/react/promise/CHANGELOG.md b/app/libs/vendor/react/promise/CHANGELOG.md index ec3f2d01..fe50904a 100644 --- a/app/libs/vendor/react/promise/CHANGELOG.md +++ b/app/libs/vendor/react/promise/CHANGELOG.md @@ -1,43 +1,43 @@ -CHANGELOG -========= - -* 2.0.0 (2013-12-10) - - New major release. The goal was to streamline the API and to make it more - compliant with other promise libraries and especially with the new upcoming - [ES6 promises specification](https://github.com/domenic/promises-unwrapping/). - - * Add standalone Promise class. - * Add new React\Promise\race() function. - * BC break: Bump minimum PHP version to PHP 5.4. - * BC break: Remove ResolverInterface and PromiseInterface from Deferred. - * BC break: Change signature of PromiseInterface. - * BC break: Remove When and Util classes and move static methods to functions. - * BC break: FulfilledPromise and RejectedPromise now throw an exception when - initialized with a promise instead of a value/reason. - * BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject() - no longer return a promise. - -* 1.0.4 (2013-04-03) - - * Trigger PHP errors when invalid callback is passed. - * Fully resolve rejection value before calling rejection handler. - * Add When::lazy() to create lazy promises which will be initialized once a - consumer calls the then() method. - -* 1.0.3 (2012-11-17) - - * Add `PromisorInterface` for objects that have a `promise()` method. - -* 1.0.2 (2012-11-14) - - * Fix bug in When::any() not correctly unwrapping to a single result value - * $promiseOrValue argument of When::resolve() and When::reject() is now optional - -* 1.0.1 (2012-11-13) - - * Prevent deep recursion which was reaching `xdebug.max_nesting_level` default of 100 - -* 1.0.0 (2012-11-07) - - * First tagged release +CHANGELOG +========= + +* 2.0.0 (2013-12-10) + + New major release. The goal was to streamline the API and to make it more + compliant with other promise libraries and especially with the new upcoming + [ES6 promises specification](https://github.com/domenic/promises-unwrapping/). + + * Add standalone Promise class. + * Add new React\Promise\race() function. + * BC break: Bump minimum PHP version to PHP 5.4. + * BC break: Remove ResolverInterface and PromiseInterface from Deferred. + * BC break: Change signature of PromiseInterface. + * BC break: Remove When and Util classes and move static methods to functions. + * BC break: FulfilledPromise and RejectedPromise now throw an exception when + initialized with a promise instead of a value/reason. + * BC break: React\Promise\Deferred::resolve() and React\Promise\Deferred::reject() + no longer return a promise. + +* 1.0.4 (2013-04-03) + + * Trigger PHP errors when invalid callback is passed. + * Fully resolve rejection value before calling rejection handler. + * Add When::lazy() to create lazy promises which will be initialized once a + consumer calls the then() method. + +* 1.0.3 (2012-11-17) + + * Add `PromisorInterface` for objects that have a `promise()` method. + +* 1.0.2 (2012-11-14) + + * Fix bug in When::any() not correctly unwrapping to a single result value + * $promiseOrValue argument of When::resolve() and When::reject() is now optional + +* 1.0.1 (2012-11-13) + + * Prevent deep recursion which was reaching `xdebug.max_nesting_level` default of 100 + +* 1.0.0 (2012-11-07) + + * First tagged release diff --git a/app/libs/vendor/react/promise/README.md b/app/libs/vendor/react/promise/README.md index df037971..820e6a83 100644 --- a/app/libs/vendor/react/promise/README.md +++ b/app/libs/vendor/react/promise/README.md @@ -1,574 +1,574 @@ -React/Promise -============= - -A lightweight implementation of -[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. - -[![Build Status](https://secure.travis-ci.org/reactphp/promise.png?branch=master)](http://travis-ci.org/reactphp/promise) - -Table of Contents ------------------ - -1. [Introduction](#introduction) -2. [Concepts](#concepts) - * [Deferred](#deferred) - * [Promise](#promise) -3. [API](#api) - * [Deferred](#deferred-1) - * [Deferred::promise()](#deferredpromise) - * [Deferred::resolve()](#deferredresolve) - * [Deferred::reject()](#deferredreject) - * [Deferred::progress()](#deferredprogress) - * [PromiseInterface](#promiseinterface) - * [PromiseInterface::then()](#promiseinterfacethen) - * [Promise](#promise-1) - * [FulfilledPromise](#fulfilledpromise) - * [RejectedPromise](#rejectedpromise) - * [LazyPromise](#lazypromise) - * [Functions](#functions) - * [resolve()](#resolve) - * [reject()](#reject) - * [all()](#all) - * [race()](#race) - * [any()](#any) - * [some()](#some) - * [map()](#map) - * [reduce()](#reduce) - * [PromisorInterface](#promisorinterface) -4. [Examples](#examples) - * [How to use Deferred](#how-to-use-deferred) - * [How promise forwarding works](#how-promise-forwarding-works) - * [Resolution forwarding](#resolution-forwarding) - * [Rejection forwarding](#rejection-forwarding) - * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding) - * [Progress event forwarding](#progress-event-forwarding) -5. [Credits](#credits) -6. [License](#license) - -Introduction ------------- - -React/Promise is a library implementing -[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. - -It also provides several other useful promise-related concepts, such as joining -multiple promises and mapping and reducing collections of promises. - -If you've never heard about promises before, -[read this first](https://gist.github.com/3889970). - -Concepts --------- - -### Deferred - -A **Deferred** represents a computation or unit of work that may not have -completed yet. Typically (but not always), that computation will be something -that executes asynchronously and completes at some point in the future. - -### Promise - -While a deferred represents the computation itself, a **Promise** represents -the result of that computation. Thus, each deferred has a promise that acts as -a placeholder for its actual result. - -API ---- - -### Deferred - -A deferred represents an operation whose resolution is pending. It has separate -promise and resolver parts. - -``` php -$deferred = new React\Promise\Deferred(); - -$promise = $deferred->promise(); - -$deferred->resolve(mixed $value = null); -$deferred->reject(mixed $reason = null); -$deferred->progress(mixed $update = null); -``` - -The `promise` method returns the promise of the deferred. - -The `resolve` and `reject` methods control the state of the deferred. - -The `progress` method is for progress notification. - -#### Deferred::promise() - -``` php -$promise = $deferred->promise(); -``` - -Returns the promise of the deferred, which you can hand out to others while -keeping the authority to modify its state to yourself. - -#### Deferred::resolve() - -``` php -$deferred->resolve(mixed $value = null); -``` - -Resolves the promise returned by `promise()`. All consumers are notified by -having `$onFulfilled` (which they registered via `$promise->then()`) called with -`$value`. - -If `$value` itself is a promise, the promise will transition to the state of -this promise once it is resolved. - -#### Deferred::reject() - -``` php -$resolver->reject(mixed $reason = null); -``` - -Rejects the promise returned by `promise()`, signalling that the deferred's -computation failed. -All consumers are notified by having `$onRejected` (which they registered via -`$promise->then()`) called with `$reason`. - -If `$reason` itself is a promise, the promise will be rejected with the outcome -of this promise regardless whether it fulfills or rejects. - -#### Deferred::progress() - -``` php -$resolver->progress(mixed $update = null); -``` - -Triggers progress notifications, to indicate to consumers that the computation -is making progress toward its result. - -All consumers are notified by having `$onProgress` (which they registered via -`$promise->then()`) called with `$update`. - -### PromiseInterface - -The promise interface provides the common interface for all promise -implementations. - -A promise represents an eventual outcome, which is either fulfillment (success) -and an associated value, or rejection (failure) and an associated reason. - -Once in the fulfilled or rejected state, a promise becomes immutable. -Neither its state nor its result (or error) can be modified. - -#### PromiseInterface::then() - -``` php -$newPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); -``` - -The `then()` method registers new fulfilled, rejection and progress handlers -with this promise (all parameters are optional): - - * `$onFulfilled` will be invoked once the promise is fulfilled and passed - the result as the first argument. - * `$onRejected` will be invoked once the promise is rejected and passed the - reason as the first argument. - * `$onProgress` will be invoked whenever the producer of the promise - triggers progress notifications and passed a single argument (whatever it - wants) to indicate progress. - -It returns a new promise that will fulfill with the return value of either -`$onFulfilled` or `$onRejected`, whichever is called, or will reject with -the thrown exception if either throws. - -A promise makes the following guarantees about handlers registered in -the same call to `then()`: - - 1. Only one of `$onFulfilled` or `$onRejected` will be called, - never both. - 2. `$onFulfilled` and `$onRejected` will never be called more - than once. - 3. `$onProgress` may be called multiple times. - -#### Implementations - -* [Promise](#promise-1) -* [FulfilledPromise](#fulfilledpromise) -* [RejectedPromise](#rejectedpromise) -* [LazyPromise](#lazypromise) - -#### See also - -* [resolve()](#resolve) - Creating a resolved promise -* [reject()](#reject) - Creating a rejected promise - -### Promise - -Creates a promise whose state is controlled by the functions passed to -`$resolver`. - -``` php -$resolver = function (callable $resolve, callable $reject, callable $progress) { - // Do some work, possibly asynchronously, and then - // resolve or reject. You can notify of progress events - // along the way if you want/need. - - $resolve($awesomeResult); - // or $resolve($anotherPromise); - // or $reject($nastyError); - // or $progress($progressNotification); -}; - -$promise = new React\Promise\Promise($resolver); -``` - -The promise constructor receives a resolver function which will be called -with 3 arguments: - - * `$resolve($value)` - Primary function that seals the fate of the - returned promise. Accepts either a non-promise value, or another promise. - When called with a non-promise value, fulfills promise with that value. - When called with another promise, e.g. `$resolve($otherPromise)`, promise's - fate will be equivalent to that of `$otherPromise`. - * `$reject($reason)` - Function that rejects the promise. - * `$progress($update)` - Function that issues progress events for the promise. - -If the resolver throws an exception, the promise will be rejected with that -thrown exception as the rejection reason. - - -### FulfilledPromise - -Creates a already fulfilled promise. - -```php -$promise = React\Promise\FulfilledPromise($value); -``` - -Note, that `$value` **cannot** be a promise. It's recommended to use -[resolve()](#resolve) for creating resolved promises. - -### RejectedPromise - -Creates a already rejected promise. - -```php -$promise = React\Promise\RejectedPromise($reason); -``` - -Note, that `$reason` **cannot** be a promise. It's recommended to use -[reject()](#reject) for creating rejected promises. - -### LazyPromise - -Creates a promise which will be lazily initialized by `$factory` once a consumer -calls the `then()` method. - -```php -$factory = function () { - $deferred = new React\Promise\Deferred(); - - // Do some heavy stuff here and resolve the deferred once completed - - return $deferred->promise(); -}; - -$promise = React\Promise\LazyPromise($factory); - -// $factory will only be executed once we call then() -$promise->then(function ($value) { -}); -``` - -### Functions - -Useful functions for creating, joining, mapping and reducing collections of -promises. - -#### resolve() - -``` php -$promise = React\Promise\resolve(mixed $promiseOrValue); -``` - -Creates a resolved promise for the supplied `$promiseOrValue`. - -If `$promiseOrValue` is a value, it will be the resolution value of the -returned promise. - -If `$promiseOrValue` is a promise, it will simply be returned. - -#### reject() - -``` php -$promise = React\Promise\reject(mixed $promiseOrValue); -``` - -Creates a rejected promise for the supplied `$promiseOrValue`. - -If `$promiseOrValue` is a value, it will be the rejection value of the -returned promise. - -If `$promiseOrValue` is a promise, its completion value will be the rejected -value of the returned promise. - -This can be useful in situations where you need to reject a promise without -throwing an exception. For example, it allows you to propagate a rejection with -the value of another promise. - -#### all() - -``` php -$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Returns a promise that will resolve only once all the items in -`$promisesOrValues` have resolved. The resolution value of the returned promise -will be an array containing the resolution values of each of the items in -`$promisesOrValues`. - -#### race() - -``` php -$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Initiates a competitive race that allows one winner. Returns a promise which is -resolved in the same way the first settled promise resolves. - -#### any() - -``` php -$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues); -``` - -Returns a promise that will resolve when any one of the items in -`$promisesOrValues` resolves. The resolution value of the returned promise -will be the resolution value of the triggering item. - -The returned promise will only reject if *all* items in `$promisesOrValues` are -rejected. The rejection value will be an array of all rejection reasons. - -#### some() - -``` php -$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany); -``` - -Returns a promise that will resolve when `$howMany` of the supplied items in -`$promisesOrValues` resolve. The resolution value of the returned promise -will be an array of length `$howMany` containing the resolution values of the -triggering items. - -The returned promise will reject if it becomes impossible for `$howMany` items -to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items -reject). The rejection value will be an array of -`(count($promisesOrValues) - $howMany) + 1` rejection reasons. - -#### map() - -``` php -$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc); -``` - -Traditional map function, similar to `array_map()`, but allows input to contain -promises and/or values, and `$mapFunc` may return either a value or a promise. - -The map function receives each item as argument, where item is a fully resolved -value of a promise or value in `$promisesOrValues`. - -#### reduce() - -``` php -$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null); -``` - -Traditional reduce function, similar to `array_reduce()`, but input may contain -promises and/or values, and `$reduceFunc` may return either a value or a -promise, *and* `$initialValue` may be a promise or a value for the starting -value. - -### PromisorInterface - -The `React\Promise\PromisorInterface` provides a common interface for objects -that provide a promise. `React\Promise\Deferred` implements it, but since it -is part of the public API anyone can implement it. - -Examples --------- - -### How to use Deferred - -``` php -function getAwesomeResultPromise() -{ - $deferred = new React\Promise\Deferred(); - - // Pass only the Resolver, to provide the resolution value for the promise - computeAwesomeResultAsynchronously($deferred->resolver()); - - // Return only the promise, so that the caller cannot - // resolve, reject, or otherwise muck with the original deferred. - return $deferred->promise(); -} - -getAwesomeResultPromise() - ->then( - function ($value) { - // Deferred resolved, do something with $value - }, - function ($reason) { - // Deferred rejected, do something with $reason - }, - function ($update) { - // Progress notification triggered, do something with $update - } - ); -``` - -### How promise forwarding works - -A few simple examples to show how the mechanics of Promises/A forwarding works. -These examples are contrived, of course, and in real usage, promise chains will -typically be spread across several function calls, or even several levels of -your application architecture. - -#### Resolution forwarding - -Resolved promises forward resolution values to the next promise. -The first promise, `$deferred->promise()`, will resolve with the value passed -to `$deferred->resolve()` below. - -Each call to `then()` returns a new promise that will resolve with the return -value of the previous handler. This creates a promise "pipeline". - -``` php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - // $x will be the value passed to $deferred->resolve() below - // and returns a *new promise* for $x + 1 - return $x + 1; - }) - ->then(function ($x) { - // $x === 2 - // This handler receives the return value of the - // previous handler. - return $x + 1; - }) - ->then(function ($x) { - // $x === 3 - // This handler receives the return value of the - // previous handler. - return $x + 1; - }) - ->then(function ($x) { - // $x === 4 - // This handler receives the return value of the - // previous handler. - echo 'Resolve ' . $x; - }); - -$deferred->resolve(1); // Prints "Resolve 4" -``` - -#### Rejection forwarding - -Rejected promises behave similarly, and also work similarly to try/catch: -When you catch an exception, you must rethrow for it to propagate. - -Similarly, when you handle a rejected promise, to propagate the rejection, -"rethrow" it by either returning a rejected promise, or actually throwing -(since promise translates thrown exceptions into rejections) - -``` php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - throw new \Exception($x + 1); - }) - ->then(null, function (\Exception $x) { - // Propagate the rejection - throw $x; - }) - ->then(null, function (\Exception $x) { - // Can also propagate by returning another rejection - return React\Promise\reject((integer) $x->getMessage() + 1); - }) - ->then(null, function ($x) { - echo 'Reject ' . $x; // 3 - }); - -$deferred->resolve(1); // Prints "Reject 3" -``` - -#### Mixed resolution and rejection forwarding - -Just like try/catch, you can choose to propagate or not. Mixing resolutions and -rejections will still forward handler results in a predictable way. - -``` php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(function ($x) { - return $x + 1; - }) - ->then(function ($x) { - throw \Exception($x + 1); - }) - ->then(null, function (\Exception $x) { - // Handle the rejection, and don't propagate. - // This is like catch without a rethrow - return (integer) $x->getMessage() + 1; - }) - ->then(function ($x) { - echo 'Mixed ' . $x; // 4 - }); - -$deferred->resolve(1); // Prints "Mixed 4" -``` - -#### Progress event forwarding - -In the same way as resolution and rejection handlers, your progress handler -**MUST** return a progress event to be propagated to the next link in the chain. -If you return nothing, `null` will be propagated. - -Also in the same way as resolutions and rejections, if you don't register a -progress handler, the update will be propagated through. - -If your progress handler throws an exception, the exception will be propagated -to the next link in the chain. The best thing to do is to ensure your progress -handlers do not throw exceptions. - -This gives you the opportunity to transform progress events at each step in the -chain so that they are meaningful to the next step. It also allows you to choose -not to transform them, and simply let them propagate untransformed, by not -registering a progress handler. - -``` php -$deferred = new React\Promise\Deferred(); - -$deferred->promise() - ->then(null, null, function ($update) { - return $update + 1; - }) - ->then(null, null, function ($update) { - echo 'Progress ' . $update; // 2 - }); - -$deferred->progress(1); // Prints "Progress 2" -``` - -Credits -------- - -React/Promise is a port of [when.js](https://github.com/cujojs/when) -by [Brian Cavalier](https://github.com/briancavalier). - -Also, large parts of the documentation have been ported from the when.js -[Wiki](https://github.com/cujojs/when/wiki) and the -[API docs](https://github.com/cujojs/when/blob/master/docs/api.md). - -License -------- - -React/Promise is released under the [MIT](https://github.com/reactphp/promise/blob/master/LICENSE) license. +React/Promise +============= + +A lightweight implementation of +[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. + +[![Build Status](https://secure.travis-ci.org/reactphp/promise.png?branch=master)](http://travis-ci.org/reactphp/promise) + +Table of Contents +----------------- + +1. [Introduction](#introduction) +2. [Concepts](#concepts) + * [Deferred](#deferred) + * [Promise](#promise) +3. [API](#api) + * [Deferred](#deferred-1) + * [Deferred::promise()](#deferredpromise) + * [Deferred::resolve()](#deferredresolve) + * [Deferred::reject()](#deferredreject) + * [Deferred::progress()](#deferredprogress) + * [PromiseInterface](#promiseinterface) + * [PromiseInterface::then()](#promiseinterfacethen) + * [Promise](#promise-1) + * [FulfilledPromise](#fulfilledpromise) + * [RejectedPromise](#rejectedpromise) + * [LazyPromise](#lazypromise) + * [Functions](#functions) + * [resolve()](#resolve) + * [reject()](#reject) + * [all()](#all) + * [race()](#race) + * [any()](#any) + * [some()](#some) + * [map()](#map) + * [reduce()](#reduce) + * [PromisorInterface](#promisorinterface) +4. [Examples](#examples) + * [How to use Deferred](#how-to-use-deferred) + * [How promise forwarding works](#how-promise-forwarding-works) + * [Resolution forwarding](#resolution-forwarding) + * [Rejection forwarding](#rejection-forwarding) + * [Mixed resolution and rejection forwarding](#mixed-resolution-and-rejection-forwarding) + * [Progress event forwarding](#progress-event-forwarding) +5. [Credits](#credits) +6. [License](#license) + +Introduction +------------ + +React/Promise is a library implementing +[CommonJS Promises/A](http://wiki.commonjs.org/wiki/Promises/A) for PHP. + +It also provides several other useful promise-related concepts, such as joining +multiple promises and mapping and reducing collections of promises. + +If you've never heard about promises before, +[read this first](https://gist.github.com/3889970). + +Concepts +-------- + +### Deferred + +A **Deferred** represents a computation or unit of work that may not have +completed yet. Typically (but not always), that computation will be something +that executes asynchronously and completes at some point in the future. + +### Promise + +While a deferred represents the computation itself, a **Promise** represents +the result of that computation. Thus, each deferred has a promise that acts as +a placeholder for its actual result. + +API +--- + +### Deferred + +A deferred represents an operation whose resolution is pending. It has separate +promise and resolver parts. + +``` php +$deferred = new React\Promise\Deferred(); + +$promise = $deferred->promise(); + +$deferred->resolve(mixed $value = null); +$deferred->reject(mixed $reason = null); +$deferred->progress(mixed $update = null); +``` + +The `promise` method returns the promise of the deferred. + +The `resolve` and `reject` methods control the state of the deferred. + +The `progress` method is for progress notification. + +#### Deferred::promise() + +``` php +$promise = $deferred->promise(); +``` + +Returns the promise of the deferred, which you can hand out to others while +keeping the authority to modify its state to yourself. + +#### Deferred::resolve() + +``` php +$deferred->resolve(mixed $value = null); +``` + +Resolves the promise returned by `promise()`. All consumers are notified by +having `$onFulfilled` (which they registered via `$promise->then()`) called with +`$value`. + +If `$value` itself is a promise, the promise will transition to the state of +this promise once it is resolved. + +#### Deferred::reject() + +``` php +$resolver->reject(mixed $reason = null); +``` + +Rejects the promise returned by `promise()`, signalling that the deferred's +computation failed. +All consumers are notified by having `$onRejected` (which they registered via +`$promise->then()`) called with `$reason`. + +If `$reason` itself is a promise, the promise will be rejected with the outcome +of this promise regardless whether it fulfills or rejects. + +#### Deferred::progress() + +``` php +$resolver->progress(mixed $update = null); +``` + +Triggers progress notifications, to indicate to consumers that the computation +is making progress toward its result. + +All consumers are notified by having `$onProgress` (which they registered via +`$promise->then()`) called with `$update`. + +### PromiseInterface + +The promise interface provides the common interface for all promise +implementations. + +A promise represents an eventual outcome, which is either fulfillment (success) +and an associated value, or rejection (failure) and an associated reason. + +Once in the fulfilled or rejected state, a promise becomes immutable. +Neither its state nor its result (or error) can be modified. + +#### PromiseInterface::then() + +``` php +$newPromise = $promise->then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null); +``` + +The `then()` method registers new fulfilled, rejection and progress handlers +with this promise (all parameters are optional): + + * `$onFulfilled` will be invoked once the promise is fulfilled and passed + the result as the first argument. + * `$onRejected` will be invoked once the promise is rejected and passed the + reason as the first argument. + * `$onProgress` will be invoked whenever the producer of the promise + triggers progress notifications and passed a single argument (whatever it + wants) to indicate progress. + +It returns a new promise that will fulfill with the return value of either +`$onFulfilled` or `$onRejected`, whichever is called, or will reject with +the thrown exception if either throws. + +A promise makes the following guarantees about handlers registered in +the same call to `then()`: + + 1. Only one of `$onFulfilled` or `$onRejected` will be called, + never both. + 2. `$onFulfilled` and `$onRejected` will never be called more + than once. + 3. `$onProgress` may be called multiple times. + +#### Implementations + +* [Promise](#promise-1) +* [FulfilledPromise](#fulfilledpromise) +* [RejectedPromise](#rejectedpromise) +* [LazyPromise](#lazypromise) + +#### See also + +* [resolve()](#resolve) - Creating a resolved promise +* [reject()](#reject) - Creating a rejected promise + +### Promise + +Creates a promise whose state is controlled by the functions passed to +`$resolver`. + +``` php +$resolver = function (callable $resolve, callable $reject, callable $progress) { + // Do some work, possibly asynchronously, and then + // resolve or reject. You can notify of progress events + // along the way if you want/need. + + $resolve($awesomeResult); + // or $resolve($anotherPromise); + // or $reject($nastyError); + // or $progress($progressNotification); +}; + +$promise = new React\Promise\Promise($resolver); +``` + +The promise constructor receives a resolver function which will be called +with 3 arguments: + + * `$resolve($value)` - Primary function that seals the fate of the + returned promise. Accepts either a non-promise value, or another promise. + When called with a non-promise value, fulfills promise with that value. + When called with another promise, e.g. `$resolve($otherPromise)`, promise's + fate will be equivalent to that of `$otherPromise`. + * `$reject($reason)` - Function that rejects the promise. + * `$progress($update)` - Function that issues progress events for the promise. + +If the resolver throws an exception, the promise will be rejected with that +thrown exception as the rejection reason. + + +### FulfilledPromise + +Creates a already fulfilled promise. + +```php +$promise = React\Promise\FulfilledPromise($value); +``` + +Note, that `$value` **cannot** be a promise. It's recommended to use +[resolve()](#resolve) for creating resolved promises. + +### RejectedPromise + +Creates a already rejected promise. + +```php +$promise = React\Promise\RejectedPromise($reason); +``` + +Note, that `$reason` **cannot** be a promise. It's recommended to use +[reject()](#reject) for creating rejected promises. + +### LazyPromise + +Creates a promise which will be lazily initialized by `$factory` once a consumer +calls the `then()` method. + +```php +$factory = function () { + $deferred = new React\Promise\Deferred(); + + // Do some heavy stuff here and resolve the deferred once completed + + return $deferred->promise(); +}; + +$promise = React\Promise\LazyPromise($factory); + +// $factory will only be executed once we call then() +$promise->then(function ($value) { +}); +``` + +### Functions + +Useful functions for creating, joining, mapping and reducing collections of +promises. + +#### resolve() + +``` php +$promise = React\Promise\resolve(mixed $promiseOrValue); +``` + +Creates a resolved promise for the supplied `$promiseOrValue`. + +If `$promiseOrValue` is a value, it will be the resolution value of the +returned promise. + +If `$promiseOrValue` is a promise, it will simply be returned. + +#### reject() + +``` php +$promise = React\Promise\reject(mixed $promiseOrValue); +``` + +Creates a rejected promise for the supplied `$promiseOrValue`. + +If `$promiseOrValue` is a value, it will be the rejection value of the +returned promise. + +If `$promiseOrValue` is a promise, its completion value will be the rejected +value of the returned promise. + +This can be useful in situations where you need to reject a promise without +throwing an exception. For example, it allows you to propagate a rejection with +the value of another promise. + +#### all() + +``` php +$promise = React\Promise\all(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Returns a promise that will resolve only once all the items in +`$promisesOrValues` have resolved. The resolution value of the returned promise +will be an array containing the resolution values of each of the items in +`$promisesOrValues`. + +#### race() + +``` php +$promise = React\Promise\race(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Initiates a competitive race that allows one winner. Returns a promise which is +resolved in the same way the first settled promise resolves. + +#### any() + +``` php +$promise = React\Promise\any(array|React\Promise\PromiseInterface $promisesOrValues); +``` + +Returns a promise that will resolve when any one of the items in +`$promisesOrValues` resolves. The resolution value of the returned promise +will be the resolution value of the triggering item. + +The returned promise will only reject if *all* items in `$promisesOrValues` are +rejected. The rejection value will be an array of all rejection reasons. + +#### some() + +``` php +$promise = React\Promise\some(array|React\Promise\PromiseInterface $promisesOrValues, integer $howMany); +``` + +Returns a promise that will resolve when `$howMany` of the supplied items in +`$promisesOrValues` resolve. The resolution value of the returned promise +will be an array of length `$howMany` containing the resolution values of the +triggering items. + +The returned promise will reject if it becomes impossible for `$howMany` items +to resolve (that is, when `(count($promisesOrValues) - $howMany) + 1` items +reject). The rejection value will be an array of +`(count($promisesOrValues) - $howMany) + 1` rejection reasons. + +#### map() + +``` php +$promise = React\Promise\map(array|React\Promise\PromiseInterface $promisesOrValues, callable $mapFunc); +``` + +Traditional map function, similar to `array_map()`, but allows input to contain +promises and/or values, and `$mapFunc` may return either a value or a promise. + +The map function receives each item as argument, where item is a fully resolved +value of a promise or value in `$promisesOrValues`. + +#### reduce() + +``` php +$promise = React\Promise\reduce(array|React\Promise\PromiseInterface $promisesOrValues, callable $reduceFunc , $initialValue = null); +``` + +Traditional reduce function, similar to `array_reduce()`, but input may contain +promises and/or values, and `$reduceFunc` may return either a value or a +promise, *and* `$initialValue` may be a promise or a value for the starting +value. + +### PromisorInterface + +The `React\Promise\PromisorInterface` provides a common interface for objects +that provide a promise. `React\Promise\Deferred` implements it, but since it +is part of the public API anyone can implement it. + +Examples +-------- + +### How to use Deferred + +``` php +function getAwesomeResultPromise() +{ + $deferred = new React\Promise\Deferred(); + + // Pass only the Resolver, to provide the resolution value for the promise + computeAwesomeResultAsynchronously($deferred->resolver()); + + // Return only the promise, so that the caller cannot + // resolve, reject, or otherwise muck with the original deferred. + return $deferred->promise(); +} + +getAwesomeResultPromise() + ->then( + function ($value) { + // Deferred resolved, do something with $value + }, + function ($reason) { + // Deferred rejected, do something with $reason + }, + function ($update) { + // Progress notification triggered, do something with $update + } + ); +``` + +### How promise forwarding works + +A few simple examples to show how the mechanics of Promises/A forwarding works. +These examples are contrived, of course, and in real usage, promise chains will +typically be spread across several function calls, or even several levels of +your application architecture. + +#### Resolution forwarding + +Resolved promises forward resolution values to the next promise. +The first promise, `$deferred->promise()`, will resolve with the value passed +to `$deferred->resolve()` below. + +Each call to `then()` returns a new promise that will resolve with the return +value of the previous handler. This creates a promise "pipeline". + +``` php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + // $x will be the value passed to $deferred->resolve() below + // and returns a *new promise* for $x + 1 + return $x + 1; + }) + ->then(function ($x) { + // $x === 2 + // This handler receives the return value of the + // previous handler. + return $x + 1; + }) + ->then(function ($x) { + // $x === 3 + // This handler receives the return value of the + // previous handler. + return $x + 1; + }) + ->then(function ($x) { + // $x === 4 + // This handler receives the return value of the + // previous handler. + echo 'Resolve ' . $x; + }); + +$deferred->resolve(1); // Prints "Resolve 4" +``` + +#### Rejection forwarding + +Rejected promises behave similarly, and also work similarly to try/catch: +When you catch an exception, you must rethrow for it to propagate. + +Similarly, when you handle a rejected promise, to propagate the rejection, +"rethrow" it by either returning a rejected promise, or actually throwing +(since promise translates thrown exceptions into rejections) + +``` php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + throw new \Exception($x + 1); + }) + ->then(null, function (\Exception $x) { + // Propagate the rejection + throw $x; + }) + ->then(null, function (\Exception $x) { + // Can also propagate by returning another rejection + return React\Promise\reject((integer) $x->getMessage() + 1); + }) + ->then(null, function ($x) { + echo 'Reject ' . $x; // 3 + }); + +$deferred->resolve(1); // Prints "Reject 3" +``` + +#### Mixed resolution and rejection forwarding + +Just like try/catch, you can choose to propagate or not. Mixing resolutions and +rejections will still forward handler results in a predictable way. + +``` php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(function ($x) { + return $x + 1; + }) + ->then(function ($x) { + throw \Exception($x + 1); + }) + ->then(null, function (\Exception $x) { + // Handle the rejection, and don't propagate. + // This is like catch without a rethrow + return (integer) $x->getMessage() + 1; + }) + ->then(function ($x) { + echo 'Mixed ' . $x; // 4 + }); + +$deferred->resolve(1); // Prints "Mixed 4" +``` + +#### Progress event forwarding + +In the same way as resolution and rejection handlers, your progress handler +**MUST** return a progress event to be propagated to the next link in the chain. +If you return nothing, `null` will be propagated. + +Also in the same way as resolutions and rejections, if you don't register a +progress handler, the update will be propagated through. + +If your progress handler throws an exception, the exception will be propagated +to the next link in the chain. The best thing to do is to ensure your progress +handlers do not throw exceptions. + +This gives you the opportunity to transform progress events at each step in the +chain so that they are meaningful to the next step. It also allows you to choose +not to transform them, and simply let them propagate untransformed, by not +registering a progress handler. + +``` php +$deferred = new React\Promise\Deferred(); + +$deferred->promise() + ->then(null, null, function ($update) { + return $update + 1; + }) + ->then(null, null, function ($update) { + echo 'Progress ' . $update; // 2 + }); + +$deferred->progress(1); // Prints "Progress 2" +``` + +Credits +------- + +React/Promise is a port of [when.js](https://github.com/cujojs/when) +by [Brian Cavalier](https://github.com/briancavalier). + +Also, large parts of the documentation have been ported from the when.js +[Wiki](https://github.com/cujojs/when/wiki) and the +[API docs](https://github.com/cujojs/when/blob/master/docs/api.md). + +License +------- + +React/Promise is released under the [MIT](https://github.com/reactphp/promise/blob/master/LICENSE) license. diff --git a/app/libs/vendor/react/promise/composer.json b/app/libs/vendor/react/promise/composer.json index 79e50fb1..ee83717a 100644 --- a/app/libs/vendor/react/promise/composer.json +++ b/app/libs/vendor/react/promise/composer.json @@ -1,22 +1,22 @@ -{ - "name": "react/promise", - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "license": "MIT", - "authors": [ - {"name": "Jan Sorgalla", "email": "jsorgalla@googlemail.com"} - ], - "require": { - "php": ">=5.4.0" - }, - "autoload": { - "psr-0": { - "React\\Promise": "src/" - }, - "files": ["src/React/Promise/functions.php"] - }, - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - } -} +{ + "name": "react/promise", + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "license": "MIT", + "authors": [ + {"name": "Jan Sorgalla", "email": "jsorgalla@googlemail.com"} + ], + "require": { + "php": ">=5.4.0" + }, + "autoload": { + "psr-0": { + "React\\Promise": "src/" + }, + "files": ["src/React/Promise/functions.php"] + }, + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + } +} diff --git a/app/libs/vendor/react/promise/phpunit.xml.dist b/app/libs/vendor/react/promise/phpunit.xml.dist index d394c106..0eebb58b 100644 --- a/app/libs/vendor/react/promise/phpunit.xml.dist +++ b/app/libs/vendor/react/promise/phpunit.xml.dist @@ -1,25 +1,25 @@ - - - - - - ./tests/React/Promise/ - - - - - - ./src/ - - - + + + + + + ./tests/React/Promise/ + + + + + + ./src/ + + + diff --git a/app/libs/vendor/react/promise/src/React/Promise/Deferred.php b/app/libs/vendor/react/promise/src/React/Promise/Deferred.php index 7952bab8..1a7e4895 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/Deferred.php +++ b/app/libs/vendor/react/promise/src/React/Promise/Deferred.php @@ -1,45 +1,45 @@ -promise) { - $this->promise = new Promise(function ($resolve, $reject, $progress) { - $this->resolveCallback = $resolve; - $this->rejectCallback = $reject; - $this->progressCallback = $progress; - }); - } - - return $this->promise; - } - - public function resolve($value = null) - { - $this->promise(); - - call_user_func($this->resolveCallback, $value); - } - - public function reject($reason = null) - { - $this->promise(); - - call_user_func($this->rejectCallback, $reason); - } - - public function progress($update = null) - { - $this->promise(); - - call_user_func($this->progressCallback, $update); - } -} +promise) { + $this->promise = new Promise(function ($resolve, $reject, $progress) { + $this->resolveCallback = $resolve; + $this->rejectCallback = $reject; + $this->progressCallback = $progress; + }); + } + + return $this->promise; + } + + public function resolve($value = null) + { + $this->promise(); + + call_user_func($this->resolveCallback, $value); + } + + public function reject($reason = null) + { + $this->promise(); + + call_user_func($this->rejectCallback, $reason); + } + + public function progress($update = null) + { + $this->promise(); + + call_user_func($this->progressCallback, $update); + } +} diff --git a/app/libs/vendor/react/promise/src/React/Promise/FulfilledPromise.php b/app/libs/vendor/react/promise/src/React/Promise/FulfilledPromise.php index 31698b53..44e1a798 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/FulfilledPromise.php +++ b/app/libs/vendor/react/promise/src/React/Promise/FulfilledPromise.php @@ -1,32 +1,32 @@ -value = $value; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - try { - $value = $this->value; - - if (null !== $onFulfilled) { - $value = $onFulfilled($value); - } - - return resolve($value); - } catch (\Exception $exception) { - return new RejectedPromise($exception); - } - } -} +value = $value; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + try { + $value = $this->value; + + if (null !== $onFulfilled) { + $value = $onFulfilled($value); + } + + return resolve($value); + } catch (\Exception $exception) { + return new RejectedPromise($exception); + } + } +} diff --git a/app/libs/vendor/react/promise/src/React/Promise/LazyPromise.php b/app/libs/vendor/react/promise/src/React/Promise/LazyPromise.php index de89178b..82acce19 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/LazyPromise.php +++ b/app/libs/vendor/react/promise/src/React/Promise/LazyPromise.php @@ -1,27 +1,27 @@ -factory = $factory; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null === $this->promise) { - try { - $this->promise = resolve(call_user_func($this->factory)); - } catch (\Exception $exception) { - $this->promise = new RejectedPromise($exception); - } - } - - return $this->promise->then($onFulfilled, $onRejected, $onProgress); - } -} +factory = $factory; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null === $this->promise) { + try { + $this->promise = resolve(call_user_func($this->factory)); + } catch (\Exception $exception) { + $this->promise = new RejectedPromise($exception); + } + } + + return $this->promise->then($onFulfilled, $onRejected, $onProgress); + } +} diff --git a/app/libs/vendor/react/promise/src/React/Promise/Promise.php b/app/libs/vendor/react/promise/src/React/Promise/Promise.php index 056f4974..061d960c 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/Promise.php +++ b/app/libs/vendor/react/promise/src/React/Promise/Promise.php @@ -1,104 +1,104 @@ -resolve($value); - }, - function ($reason = null) { - $this->reject($reason); - }, - function ($update = null) { - $this->progress($update); - } - ); - } catch (\Exception $e) { - $this->reject($e); - } - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - if (null !== $this->result) { - return $this->result->then($onFulfilled, $onRejected, $onProgress); - } - - return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); - } - - private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - return function ($resolve, $reject, $progress) use ($onFulfilled, $onRejected, $onProgress) { - if ($onProgress) { - $progressHandler = function ($update) use ($progress, $onProgress) { - try { - $progress($onProgress($update)); - } catch (\Exception $e) { - $progress($e); - } - }; - } else { - $progressHandler = $progress; - } - - $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { - $promise - ->then($onFulfilled, $onRejected) - ->then($resolve, $reject, $progressHandler); - }; - - $this->progressHandlers[] = $progressHandler; - }; - } - - private function resolve($value = null) - { - if (null !== $this->result) { - return; - } - - $this->settle(resolve($value)); - } - - private function reject($reason = null) - { - if (null !== $this->result) { - return; - } - - $this->settle(reject($reason)); - } - - private function progress($update = null) - { - if (null !== $this->result) { - return; - } - - foreach ($this->progressHandlers as $handler) { - $handler($update); - } - } - - private function settle(PromiseInterface $result) - { - foreach ($this->handlers as $handler) { - $handler($result); - } - - $this->progressHandlers = $this->handlers = []; - - $this->result = $result; - } -} +resolve($value); + }, + function ($reason = null) { + $this->reject($reason); + }, + function ($update = null) { + $this->progress($update); + } + ); + } catch (\Exception $e) { + $this->reject($e); + } + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + if (null !== $this->result) { + return $this->result->then($onFulfilled, $onRejected, $onProgress); + } + + return new static($this->resolver($onFulfilled, $onRejected, $onProgress)); + } + + private function resolver(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + return function ($resolve, $reject, $progress) use ($onFulfilled, $onRejected, $onProgress) { + if ($onProgress) { + $progressHandler = function ($update) use ($progress, $onProgress) { + try { + $progress($onProgress($update)); + } catch (\Exception $e) { + $progress($e); + } + }; + } else { + $progressHandler = $progress; + } + + $this->handlers[] = function (PromiseInterface $promise) use ($onFulfilled, $onRejected, $resolve, $reject, $progressHandler) { + $promise + ->then($onFulfilled, $onRejected) + ->then($resolve, $reject, $progressHandler); + }; + + $this->progressHandlers[] = $progressHandler; + }; + } + + private function resolve($value = null) + { + if (null !== $this->result) { + return; + } + + $this->settle(resolve($value)); + } + + private function reject($reason = null) + { + if (null !== $this->result) { + return; + } + + $this->settle(reject($reason)); + } + + private function progress($update = null) + { + if (null !== $this->result) { + return; + } + + foreach ($this->progressHandlers as $handler) { + $handler($update); + } + } + + private function settle(PromiseInterface $result) + { + foreach ($this->handlers as $handler) { + $handler($result); + } + + $this->progressHandlers = $this->handlers = []; + + $this->result = $result; + } +} diff --git a/app/libs/vendor/react/promise/src/React/Promise/PromiseInterface.php b/app/libs/vendor/react/promise/src/React/Promise/PromiseInterface.php index 91b5d7e7..422f9f16 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/PromiseInterface.php +++ b/app/libs/vendor/react/promise/src/React/Promise/PromiseInterface.php @@ -1,8 +1,8 @@ -reason = $reason; - } - - public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) - { - try { - if (null === $onRejected) { - return new RejectedPromise($this->reason); - } - - return resolve($onRejected($this->reason)); - } catch (\Exception $exception) { - return new RejectedPromise($exception); - } - } -} +reason = $reason; + } + + public function then(callable $onFulfilled = null, callable $onRejected = null, callable $onProgress = null) + { + try { + if (null === $onRejected) { + return new RejectedPromise($this->reason); + } + + return resolve($onRejected($this->reason)); + } catch (\Exception $exception) { + return new RejectedPromise($exception); + } + } +} diff --git a/app/libs/vendor/react/promise/src/React/Promise/functions.php b/app/libs/vendor/react/promise/src/React/Promise/functions.php index 1bc40769..e4b8aa57 100644 --- a/app/libs/vendor/react/promise/src/React/Promise/functions.php +++ b/app/libs/vendor/react/promise/src/React/Promise/functions.php @@ -1,164 +1,164 @@ -then(function ($value) { - return new RejectedPromise($value); - }); - } - - return new RejectedPromise($promiseOrValue); -} - -function all($promisesOrValues) -{ - return map($promisesOrValues, function ($val) { - return $val; - }); -} - -function race($promisesOrValues) -{ - return resolve($promisesOrValues) - ->then(function ($array) { - if (!is_array($array) || !$array) { - return resolve(); - } - - return new Promise(function ($resolve, $reject, $progress) use ($array) { - foreach ($array as $promiseOrValue) { - resolve($promiseOrValue) - ->then($resolve, $reject, $progress); - } - }); - }); -} - -function any($promisesOrValues) -{ - return some($promisesOrValues, 1) - ->then(function ($val) { - return array_shift($val); - }); -} - -function some($promisesOrValues, $howMany) -{ - return resolve($promisesOrValues) - ->then(function ($array) use ($howMany) { - if (!is_array($array) || !$array || $howMany < 1) { - return resolve([]); - } - - return new Promise(function ($resolve, $reject, $progress) use ($array, $howMany) { - $len = count($array); - $toResolve = min($howMany, $len); - $toReject = ($len - $toResolve) + 1; - $values = []; - $reasons = []; - - foreach ($array as $i => $promiseOrValue) { - $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) { - if ($toResolve < 1 || $toReject < 1) { - return; - } - - $values[$i] = $val; - - if (0 === --$toResolve) { - $resolve($values); - } - }; - - $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) { - if ($toResolve < 1 || $toReject < 1) { - return; - } - - $reasons[$i] = $reason; - - if (0 === --$toReject) { - $reject($reasons); - } - }; - - resolve($promiseOrValue) - ->then($fulfiller, $rejecter, $progress); - } - }); - }); -} - -function map($promisesOrValues, callable $mapFunc) -{ - return resolve($promisesOrValues) - ->then(function ($array) use ($mapFunc) { - if (!is_array($array) || !$array) { - return resolve([]); - } - - return new Promise(function ($resolve, $reject, $progress) use ($array, $mapFunc) { - $toResolve = count($array); - $values = []; - - foreach ($array as $i => $promiseOrValue) { - resolve($promiseOrValue) - ->then($mapFunc) - ->then( - function ($mapped) use ($i, &$values, &$toResolve, $resolve) { - if ($toResolve < 1) { - return; - } - - $values[$i] = $mapped; - - if (0 === --$toResolve) { - $resolve($values); - } - }, - $reject, - $progress - ); - } - }); - }); -} - -function reduce($promisesOrValues, callable $reduceFunc , $initialValue = null) -{ - return resolve($promisesOrValues) - ->then(function ($array) use ($reduceFunc, $initialValue) { - if (!is_array($array)) { - $array = []; - } - - $total = count($array); - $i = 0; - - // Wrap the supplied $reduceFunc with one that handles promises and then - // delegates to the supplied. - $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $total, &$i) { - return resolve($current) - ->then(function ($c) use ($reduceFunc, $total, &$i, $val) { - return resolve($val) - ->then(function ($value) use ($reduceFunc, $total, &$i, $c) { - return $reduceFunc($c, $value, $i++, $total); - }); - }); - }; - - return array_reduce($array, $wrappedReduceFunc, $initialValue); - }); -} +then(function ($value) { + return new RejectedPromise($value); + }); + } + + return new RejectedPromise($promiseOrValue); +} + +function all($promisesOrValues) +{ + return map($promisesOrValues, function ($val) { + return $val; + }); +} + +function race($promisesOrValues) +{ + return resolve($promisesOrValues) + ->then(function ($array) { + if (!is_array($array) || !$array) { + return resolve(); + } + + return new Promise(function ($resolve, $reject, $progress) use ($array) { + foreach ($array as $promiseOrValue) { + resolve($promiseOrValue) + ->then($resolve, $reject, $progress); + } + }); + }); +} + +function any($promisesOrValues) +{ + return some($promisesOrValues, 1) + ->then(function ($val) { + return array_shift($val); + }); +} + +function some($promisesOrValues, $howMany) +{ + return resolve($promisesOrValues) + ->then(function ($array) use ($howMany) { + if (!is_array($array) || !$array || $howMany < 1) { + return resolve([]); + } + + return new Promise(function ($resolve, $reject, $progress) use ($array, $howMany) { + $len = count($array); + $toResolve = min($howMany, $len); + $toReject = ($len - $toResolve) + 1; + $values = []; + $reasons = []; + + foreach ($array as $i => $promiseOrValue) { + $fulfiller = function ($val) use ($i, &$values, &$toResolve, $toReject, $resolve) { + if ($toResolve < 1 || $toReject < 1) { + return; + } + + $values[$i] = $val; + + if (0 === --$toResolve) { + $resolve($values); + } + }; + + $rejecter = function ($reason) use ($i, &$reasons, &$toReject, $toResolve, $reject) { + if ($toResolve < 1 || $toReject < 1) { + return; + } + + $reasons[$i] = $reason; + + if (0 === --$toReject) { + $reject($reasons); + } + }; + + resolve($promiseOrValue) + ->then($fulfiller, $rejecter, $progress); + } + }); + }); +} + +function map($promisesOrValues, callable $mapFunc) +{ + return resolve($promisesOrValues) + ->then(function ($array) use ($mapFunc) { + if (!is_array($array) || !$array) { + return resolve([]); + } + + return new Promise(function ($resolve, $reject, $progress) use ($array, $mapFunc) { + $toResolve = count($array); + $values = []; + + foreach ($array as $i => $promiseOrValue) { + resolve($promiseOrValue) + ->then($mapFunc) + ->then( + function ($mapped) use ($i, &$values, &$toResolve, $resolve) { + if ($toResolve < 1) { + return; + } + + $values[$i] = $mapped; + + if (0 === --$toResolve) { + $resolve($values); + } + }, + $reject, + $progress + ); + } + }); + }); +} + +function reduce($promisesOrValues, callable $reduceFunc , $initialValue = null) +{ + return resolve($promisesOrValues) + ->then(function ($array) use ($reduceFunc, $initialValue) { + if (!is_array($array)) { + $array = []; + } + + $total = count($array); + $i = 0; + + // Wrap the supplied $reduceFunc with one that handles promises and then + // delegates to the supplied. + $wrappedReduceFunc = function ($current, $val) use ($reduceFunc, $total, &$i) { + return resolve($current) + ->then(function ($c) use ($reduceFunc, $total, &$i, $val) { + return resolve($val) + ->then(function ($value) use ($reduceFunc, $total, &$i, $c) { + return $reduceFunc($c, $value, $i++, $total); + }); + }); + }; + + return array_reduce($array, $wrappedReduceFunc, $initialValue); + }); +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/DeferredTest.php b/app/libs/vendor/react/promise/tests/React/Promise/DeferredTest.php index 45ae682b..e66aceb9 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/DeferredTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/DeferredTest.php @@ -1,20 +1,20 @@ - [$d, 'promise'], - 'resolve' => [$d, 'resolve'], - 'reject' => [$d, 'reject'], - 'progress' => [$d, 'progress'], - ]; - } -} + [$d, 'promise'], + 'resolve' => [$d, 'resolve'], + 'reject' => [$d, 'reject'], + 'progress' => [$d, 'progress'], + ]; + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FulfilledPromiseTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FulfilledPromiseTest.php index ad1e9809..d34065b7 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FulfilledPromiseTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FulfilledPromiseTest.php @@ -1,44 +1,44 @@ - function () use (&$val, &$promiseCalled) { - $promiseCalled = true; - - return new FulfilledPromise($val); - }, - 'resolve' => function ($value) use (&$val, &$promiseCalled) { - if ($promiseCalled) { - throw new \LogicException('You must call resolve() before promise() for React\Promise\FulfilledPromise'); - } - - $val = $value; - }, - 'reject' => function () { - throw new \LogicException('You cannot call reject() for React\Promise\FulfilledPromise'); - }, - 'progress' => function () { - throw new \LogicException('You cannot call progress() for React\Promise\FulfilledPromise'); - }, - ]; - } - - /** @test */ - public function shouldThrowExceptionIfConstructedWithAPromise() - { - $this->setExpectedException('\InvalidArgumentException'); - - return new FulfilledPromise(new FulfilledPromise()); - } -} + function () use (&$val, &$promiseCalled) { + $promiseCalled = true; + + return new FulfilledPromise($val); + }, + 'resolve' => function ($value) use (&$val, &$promiseCalled) { + if ($promiseCalled) { + throw new \LogicException('You must call resolve() before promise() for React\Promise\FulfilledPromise'); + } + + $val = $value; + }, + 'reject' => function () { + throw new \LogicException('You cannot call reject() for React\Promise\FulfilledPromise'); + }, + 'progress' => function () { + throw new \LogicException('You cannot call progress() for React\Promise\FulfilledPromise'); + }, + ]; + } + + /** @test */ + public function shouldThrowExceptionIfConstructedWithAPromise() + { + $this->setExpectedException('\InvalidArgumentException'); + + return new FulfilledPromise(new FulfilledPromise()); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionAllTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionAllTest.php index 8777610a..fcd0a5df 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionAllTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionAllTest.php @@ -1,97 +1,97 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - all([]) - ->then($mock); - } - - /** @test */ - public function shouldResolveValuesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2, 3])); - - all([1, 2, 3]) - ->then($mock); - } - - /** @test */ - public function shouldResolvePromisesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2, 3])); - - all([resolve(1), resolve(2), resolve(3)]) - ->then($mock); - } - - /** @test */ - public function shouldResolveSparseArrayInput() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([null, 1, null, 1, 1])); - - all([null, 1, null, 1, 1]) - ->then($mock); - } - - /** @test */ - public function shouldRejectIfAnyInputPromiseRejects() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - all([resolve(1), reject(2), resolve(3)]) - ->then($this->expectCallableNever(), $mock); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2, 3])); - - all(resolve([1, 2, 3])) - ->then($mock); - } - - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - all(resolve(1)) - ->then($mock); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + all([]) + ->then($mock); + } + + /** @test */ + public function shouldResolveValuesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2, 3])); + + all([1, 2, 3]) + ->then($mock); + } + + /** @test */ + public function shouldResolvePromisesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2, 3])); + + all([resolve(1), resolve(2), resolve(3)]) + ->then($mock); + } + + /** @test */ + public function shouldResolveSparseArrayInput() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([null, 1, null, 1, 1])); + + all([null, 1, null, 1, 1]) + ->then($mock); + } + + /** @test */ + public function shouldRejectIfAnyInputPromiseRejects() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + all([resolve(1), reject(2), resolve(3)]) + ->then($this->expectCallableNever(), $mock); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2, 3])); + + all(resolve([1, 2, 3])) + ->then($mock); + } + + /** @test */ + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + all(resolve(1)) + ->then($mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionAnyTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionAnyTest.php index 24dd84d4..bf8a0db4 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionAnyTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionAnyTest.php @@ -1,116 +1,116 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - any([]) - ->then($mock); - } - - /** @test */ - public function shouldResolveWithAnInputValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - any([1, 2, 3]) - ->then($mock); - } - - /** @test */ - public function shouldResolveWithAPromisedInputValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - any([resolve(1), resolve(2), resolve(3)]) - ->then($mock); - } - - /** @test */ - public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([0 => 1, 1 => 2, 2 => 3])); - - any([reject(1), reject(2), reject(3)]) - ->then($this->expectCallableNever(), $mock); - } - - /** @test */ - public function shouldResolveWhenFirstInputPromiseResolves() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - any([resolve(1), reject(2), reject(3)]) - ->then($mock); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - any(resolve([1, 2, 3])) - ->then($mock); - } - - /** @test */ - public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - any(resolve(1)) - ->then($mock); - } - - /** @test */ - public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $d1 = new Deferred(); - $d2 = new Deferred(); - - any(['abc' => $d1->promise(), 1 => $d2->promise()]) - ->then($mock); - - $d2->resolve(2); - $d1->resolve(1); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + any([]) + ->then($mock); + } + + /** @test */ + public function shouldResolveWithAnInputValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + any([1, 2, 3]) + ->then($mock); + } + + /** @test */ + public function shouldResolveWithAPromisedInputValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + any([resolve(1), resolve(2), resolve(3)]) + ->then($mock); + } + + /** @test */ + public function shouldRejectWithAllRejectedInputValuesIfAllInputsAreRejected() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([0 => 1, 1 => 2, 2 => 3])); + + any([reject(1), reject(2), reject(3)]) + ->then($this->expectCallableNever(), $mock); + } + + /** @test */ + public function shouldResolveWhenFirstInputPromiseResolves() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + any([resolve(1), reject(2), reject(3)]) + ->then($mock); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + any(resolve([1, 2, 3])) + ->then($mock); + } + + /** @test */ + public function shouldResolveToNullArrayWhenInputPromiseDoesNotResolveToArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + any(resolve(1)) + ->then($mock); + } + + /** @test */ + public function shouldNotRelyOnArryIndexesWhenUnwrappingToASingleResolutionValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $d1 = new Deferred(); + $d2 = new Deferred(); + + any(['abc' => $d1->promise(), 1 => $d2->promise()]) + ->then($mock); + + $d2->resolve(2); + $d1->resolve(1); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionMapTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionMapTest.php index c9c0797c..b8bf3a83 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionMapTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionMapTest.php @@ -1,125 +1,125 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([2, 4, 6])); - - map( - [1, 2, 3], - $this->mapper() - )->then($mock); - } - - /** @test */ - public function shouldMapInputPromisesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([2, 4, 6])); - - map( - [resolve(1), resolve(2), resolve(3)], - $this->mapper() - )->then($mock); - } - - /** @test */ - public function shouldMapMixedInputArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([2, 4, 6])); - - map( - [1, resolve(2), 3], - $this->mapper() - )->then($mock); - } - - /** @test */ - public function shouldMapInputWhenMapperReturnsAPromise() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([2, 4, 6])); - - map( - [1, 2, 3], - $this->promiseMapper() - )->then($mock); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([2, 4, 6])); - - map( - resolve([1, resolve(2), 3]), - $this->mapper() - )->then($mock); - } - - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - map( - resolve(1), - $this->mapper() - )->then($mock); - } - - /** @test */ - public function shouldRejectWhenInputContainsRejection() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - map( - [resolve(1), reject(2), resolve(3)], - $this->mapper() - )->then($this->expectCallableNever(), $mock); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([2, 4, 6])); + + map( + [1, 2, 3], + $this->mapper() + )->then($mock); + } + + /** @test */ + public function shouldMapInputPromisesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([2, 4, 6])); + + map( + [resolve(1), resolve(2), resolve(3)], + $this->mapper() + )->then($mock); + } + + /** @test */ + public function shouldMapMixedInputArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([2, 4, 6])); + + map( + [1, resolve(2), 3], + $this->mapper() + )->then($mock); + } + + /** @test */ + public function shouldMapInputWhenMapperReturnsAPromise() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([2, 4, 6])); + + map( + [1, 2, 3], + $this->promiseMapper() + )->then($mock); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([2, 4, 6])); + + map( + resolve([1, resolve(2), 3]), + $this->mapper() + )->then($mock); + } + + /** @test */ + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + map( + resolve(1), + $this->mapper() + )->then($mock); + } + + /** @test */ + public function shouldRejectWhenInputContainsRejection() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + map( + [resolve(1), reject(2), resolve(3)], + $this->mapper() + )->then($this->expectCallableNever(), $mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionRaceTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionRaceTest.php index eba02351..553220c5 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionRaceTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionRaceTest.php @@ -1,122 +1,122 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - race( - [] - )->then($mock); - } - - /** @test */ - public function shouldResolveValuesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - race( - [1, 2, 3] - )->then($mock); - } - - /** @test */ - public function shouldResolvePromisesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $d1 = new Deferred(); - $d2 = new Deferred(); - $d3 = new Deferred(); - - race( - [$d1->promise(), $d2->promise(), $d3->promise()] - )->then($mock); - - $d2->resolve(2); - - $d1->resolve(1); - $d3->resolve(3); - } - - /** @test */ - public function shouldResolveSparseArrayInput() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - race( - [null, 1, null, 2, 3] - )->then($mock); - } - - /** @test */ - public function shouldRejectIfFirstSettledPromiseRejects() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $d1 = new Deferred(); - $d2 = new Deferred(); - $d3 = new Deferred(); - - race( - [$d1->promise(), $d2->promise(), $d3->promise()] - )->then($this->expectCallableNever(), $mock); - - $d2->reject(2); - - $d1->resolve(1); - $d3->resolve(3); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - race( - resolve([1, 2, 3]) - )->then($mock); - } - - /** @test */ - public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - race( - resolve(1) - )->then($mock); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + race( + [] + )->then($mock); + } + + /** @test */ + public function shouldResolveValuesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + race( + [1, 2, 3] + )->then($mock); + } + + /** @test */ + public function shouldResolvePromisesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $d1 = new Deferred(); + $d2 = new Deferred(); + $d3 = new Deferred(); + + race( + [$d1->promise(), $d2->promise(), $d3->promise()] + )->then($mock); + + $d2->resolve(2); + + $d1->resolve(1); + $d3->resolve(3); + } + + /** @test */ + public function shouldResolveSparseArrayInput() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + race( + [null, 1, null, 2, 3] + )->then($mock); + } + + /** @test */ + public function shouldRejectIfFirstSettledPromiseRejects() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $d1 = new Deferred(); + $d2 = new Deferred(); + $d3 = new Deferred(); + + race( + [$d1->promise(), $d2->promise(), $d3->promise()] + )->then($this->expectCallableNever(), $mock); + + $d2->reject(2); + + $d1->resolve(1); + $d3->resolve(3); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + race( + resolve([1, 2, 3]) + )->then($mock); + } + + /** @test */ + public function shouldResolveToNullWhenInputPromiseDoesNotResolveToArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + race( + resolve(1) + )->then($mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionReduceTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionReduceTest.php index a20d0ef5..715e8477 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionReduceTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionReduceTest.php @@ -1,290 +1,290 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(6)); - - reduce( - [1, 2, 3], - $this->plus() - )->then($mock); - } - - /** @test */ - public function shouldReduceValuesWithInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(7)); - - reduce( - [1, 2, 3], - $this->plus(), - 1 - )->then($mock); - } - - /** @test */ - public function shouldReduceValuesWithInitialPromise() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(7)); - - reduce( - [1, 2, 3], - $this->plus(), - resolve(1) - )->then($mock); - } - - /** @test */ - public function shouldReducePromisedValuesWithoutInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(6)); - - reduce( - [resolve(1), resolve(2), resolve(3)], - $this->plus() - )->then($mock); - } - - /** @test */ - public function shouldReducePromisedValuesWithInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(7)); - - reduce( - [resolve(1), resolve(2), resolve(3)], - $this->plus(), - 1 - )->then($mock); - } - - /** @test */ - public function shouldReducePromisedValuesWithInitialPromise() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(7)); - - reduce( - [resolve(1), resolve(2), resolve(3)], - $this->plus(), - resolve(1) - )->then($mock); - } - - /** @test */ - public function shouldReduceEmptyInputWithInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - reduce( - [], - $this->plus(), - 1 - )->then($mock); - } - - /** @test */ - public function shouldReduceEmptyInputWithInitialPromise() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - reduce( - [], - $this->plus(), - resolve(1) - )->then($mock); - } - - /** @test */ - public function shouldRejectWhenInputContainsRejection() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - reduce( - [resolve(1), reject(2), resolve(3)], - $this->plus(), - resolve(1) - )->then($this->expectCallableNever(), $mock); - } - - /** @test */ - public function shouldResolveWithNullWhenInputIsEmptyAndNoInitialValueOrPromiseProvided() - { - // Note: this is different from when.js's behavior! - // In when.reduce(), this rejects with a TypeError exception (following - // JavaScript's [].reduce behavior. - // We're following PHP's array_reduce behavior and resolve with NULL. - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(null)); - - reduce( - [], - $this->plus() - )->then($mock); - } - - /** @test */ - public function shouldAllowSparseArrayInputWithoutInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(3)); - - reduce( - [null, null, 1, null, 1, 1], - $this->plus() - )->then($mock); - } - - /** @test */ - public function shouldAllowSparseArrayInputWithInitialValue() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(4)); - - reduce( - [null, null, 1, null, 1, 1], - $this->plus(), - 1 - )->then($mock); - } - - /** @test */ - public function shouldReduceInInputOrder() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo('123')); - - reduce( - [1, 2, 3], - $this->append(), - '' - )->then($mock); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo('123')); - - reduce( - resolve([1, 2, 3]), - $this->append(), - '' - )->then($mock); - } - - /** @test */ - public function shouldResolveToInitialValueWhenInputPromiseDoesNotResolveToAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - reduce( - resolve(1), - $this->plus(), - 1 - )->then($mock); - } - - /** @test */ - public function shouldProvideCorrectBasisValue() - { - $insertIntoArray = function ($arr, $val, $i) { - $arr[$i] = $val; - - return $arr; - }; - - $d1 = new Deferred(); - $d2 = new Deferred(); - $d3 = new Deferred(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2, 3])); - - reduce( - [$d1->promise(), $d2->promise(), $d3->promise()], - $insertIntoArray, - [] - )->then($mock); - - $d3->resolve(3); - $d1->resolve(1); - $d2->resolve(2); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(6)); + + reduce( + [1, 2, 3], + $this->plus() + )->then($mock); + } + + /** @test */ + public function shouldReduceValuesWithInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(7)); + + reduce( + [1, 2, 3], + $this->plus(), + 1 + )->then($mock); + } + + /** @test */ + public function shouldReduceValuesWithInitialPromise() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(7)); + + reduce( + [1, 2, 3], + $this->plus(), + resolve(1) + )->then($mock); + } + + /** @test */ + public function shouldReducePromisedValuesWithoutInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(6)); + + reduce( + [resolve(1), resolve(2), resolve(3)], + $this->plus() + )->then($mock); + } + + /** @test */ + public function shouldReducePromisedValuesWithInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(7)); + + reduce( + [resolve(1), resolve(2), resolve(3)], + $this->plus(), + 1 + )->then($mock); + } + + /** @test */ + public function shouldReducePromisedValuesWithInitialPromise() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(7)); + + reduce( + [resolve(1), resolve(2), resolve(3)], + $this->plus(), + resolve(1) + )->then($mock); + } + + /** @test */ + public function shouldReduceEmptyInputWithInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + reduce( + [], + $this->plus(), + 1 + )->then($mock); + } + + /** @test */ + public function shouldReduceEmptyInputWithInitialPromise() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + reduce( + [], + $this->plus(), + resolve(1) + )->then($mock); + } + + /** @test */ + public function shouldRejectWhenInputContainsRejection() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + reduce( + [resolve(1), reject(2), resolve(3)], + $this->plus(), + resolve(1) + )->then($this->expectCallableNever(), $mock); + } + + /** @test */ + public function shouldResolveWithNullWhenInputIsEmptyAndNoInitialValueOrPromiseProvided() + { + // Note: this is different from when.js's behavior! + // In when.reduce(), this rejects with a TypeError exception (following + // JavaScript's [].reduce behavior. + // We're following PHP's array_reduce behavior and resolve with NULL. + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(null)); + + reduce( + [], + $this->plus() + )->then($mock); + } + + /** @test */ + public function shouldAllowSparseArrayInputWithoutInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(3)); + + reduce( + [null, null, 1, null, 1, 1], + $this->plus() + )->then($mock); + } + + /** @test */ + public function shouldAllowSparseArrayInputWithInitialValue() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(4)); + + reduce( + [null, null, 1, null, 1, 1], + $this->plus(), + 1 + )->then($mock); + } + + /** @test */ + public function shouldReduceInInputOrder() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo('123')); + + reduce( + [1, 2, 3], + $this->append(), + '' + )->then($mock); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo('123')); + + reduce( + resolve([1, 2, 3]), + $this->append(), + '' + )->then($mock); + } + + /** @test */ + public function shouldResolveToInitialValueWhenInputPromiseDoesNotResolveToAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + reduce( + resolve(1), + $this->plus(), + 1 + )->then($mock); + } + + /** @test */ + public function shouldProvideCorrectBasisValue() + { + $insertIntoArray = function ($arr, $val, $i) { + $arr[$i] = $val; + + return $arr; + }; + + $d1 = new Deferred(); + $d2 = new Deferred(); + $d3 = new Deferred(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2, 3])); + + reduce( + [$d1->promise(), $d2->promise(), $d3->promise()], + $insertIntoArray, + [] + )->then($mock); + + $d3->resolve(3); + $d1->resolve(1); + $d2->resolve(2); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionRejectTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionRejectTest.php index 3aceee43..84b8ec6a 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionRejectTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionRejectTest.php @@ -1,64 +1,64 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - reject($expected) - ->then( - $this->expectCallableNever(), - $mock - ); - } - - /** @test */ - public function shouldRejectAFulfilledPromise() - { - $expected = 123; - - $resolved = new FulfilledPromise($expected); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - reject($resolved) - ->then( - $this->expectCallableNever(), - $mock - ); - } - - /** @test */ - public function shouldRejectARejectedPromise() - { - $expected = 123; - - $resolved = new RejectedPromise($expected); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - reject($resolved) - ->then( - $this->expectCallableNever(), - $mock - ); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + reject($expected) + ->then( + $this->expectCallableNever(), + $mock + ); + } + + /** @test */ + public function shouldRejectAFulfilledPromise() + { + $expected = 123; + + $resolved = new FulfilledPromise($expected); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + reject($resolved) + ->then( + $this->expectCallableNever(), + $mock + ); + } + + /** @test */ + public function shouldRejectARejectedPromise() + { + $expected = 123; + + $resolved = new RejectedPromise($expected); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + reject($resolved) + ->then( + $this->expectCallableNever(), + $mock + ); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionResolveTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionResolveTest.php index f6bc827e..01307d5a 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionResolveTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionResolveTest.php @@ -1,94 +1,94 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - resolve($expected) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function shouldResolveAFulfilledPromise() - { - $expected = 123; - - $resolved = new FulfilledPromise($expected); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - resolve($resolved) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function shouldRejectARejectedPromise() - { - $expected = 123; - - $resolved = new RejectedPromise($expected); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($expected)); - - resolve($resolved) - ->then( - $this->expectCallableNever(), - $mock - ); - } - - /** @test */ - public function shouldSupportDeepNestingInPromiseChains() - { - $d = new Deferred(); - $d->resolve(false); - - $result = resolve(resolve($d->promise()->then(function ($val) { - $d = new Deferred(); - $d->resolve($val); - - $identity = function ($val) { - return $val; - }; - - return resolve($d->promise()->then($identity))->then( - function ($val) { - return !$val; - } - ); - }))); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(true)); - - $result->then($mock); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + resolve($expected) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function shouldResolveAFulfilledPromise() + { + $expected = 123; + + $resolved = new FulfilledPromise($expected); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + resolve($resolved) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function shouldRejectARejectedPromise() + { + $expected = 123; + + $resolved = new RejectedPromise($expected); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($expected)); + + resolve($resolved) + ->then( + $this->expectCallableNever(), + $mock + ); + } + + /** @test */ + public function shouldSupportDeepNestingInPromiseChains() + { + $d = new Deferred(); + $d->resolve(false); + + $result = resolve(resolve($d->promise()->then(function ($val) { + $d = new Deferred(); + $d->resolve($val); + + $identity = function ($val) { + return $val; + }; + + return resolve($d->promise()->then($identity))->then( + function ($val) { + return !$val; + } + ); + }))); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(true)); + + $result->then($mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/FunctionSomeTest.php b/app/libs/vendor/react/promise/tests/React/Promise/FunctionSomeTest.php index 7f370b5a..09e53504 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/FunctionSomeTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/FunctionSomeTest.php @@ -1,126 +1,126 @@ -createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - some( - [], - 1 - )->then($mock); - } - - /** @test */ - public function shouldResolveValuesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2])); - - some( - [1, 2, 3], - 2 - )->then($mock); - } - - /** @test */ - public function shouldResolvePromisesArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2])); - - some( - [resolve(1), resolve(2), resolve(3)], - 2 - )->then($mock); - } - - /** @test */ - public function shouldResolveSparseArrayInput() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([null, 1])); - - some( - [null, 1, null, 2, 3], - 2 - )->then($mock); - } - - /** @test */ - public function shouldRejectIfAnyInputPromiseRejectsBeforeDesiredNumberOfInputsAreResolved() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1 => 2, 2 => 3])); - - some( - [resolve(1), reject(2), reject(3)], - 2 - )->then($this->expectCallableNever(), $mock); - } - - /** @test */ - public function shouldAcceptAPromiseForAnArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([1, 2])); - - some( - resolve([1, 2, 3]), - 2 - )->then($mock); - } - - /** @test */ - public function shouldResolveWithEmptyArrayIfHowManyIsLessThanOne() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - some( - [1], - 0 - )->then($mock); - } - - /** @test */ - public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo([])); - - some( - resolve(1), - 1 - )->then($mock); - } -} +createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + some( + [], + 1 + )->then($mock); + } + + /** @test */ + public function shouldResolveValuesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2])); + + some( + [1, 2, 3], + 2 + )->then($mock); + } + + /** @test */ + public function shouldResolvePromisesArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2])); + + some( + [resolve(1), resolve(2), resolve(3)], + 2 + )->then($mock); + } + + /** @test */ + public function shouldResolveSparseArrayInput() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([null, 1])); + + some( + [null, 1, null, 2, 3], + 2 + )->then($mock); + } + + /** @test */ + public function shouldRejectIfAnyInputPromiseRejectsBeforeDesiredNumberOfInputsAreResolved() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1 => 2, 2 => 3])); + + some( + [resolve(1), reject(2), reject(3)], + 2 + )->then($this->expectCallableNever(), $mock); + } + + /** @test */ + public function shouldAcceptAPromiseForAnArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([1, 2])); + + some( + resolve([1, 2, 3]), + 2 + )->then($mock); + } + + /** @test */ + public function shouldResolveWithEmptyArrayIfHowManyIsLessThanOne() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + some( + [1], + 0 + )->then($mock); + } + + /** @test */ + public function shouldResolveToEmptyArrayWhenInputPromiseDoesNotResolveToArray() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo([])); + + some( + resolve(1), + 1 + )->then($mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/LazyPromiseTest.php b/app/libs/vendor/react/promise/tests/React/Promise/LazyPromiseTest.php index 57ca12c0..f10609cc 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/LazyPromiseTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/LazyPromiseTest.php @@ -1,104 +1,104 @@ -promise(); - }; - - return [ - 'promise' => function () use ($factory) { - return new LazyPromise($factory); - }, - 'resolve' => [$d, 'resolve'], - 'reject' => [$d, 'reject'], - 'progress' => [$d, 'progress'], - ]; - } - - /** @test */ - public function shouldNotCallFactoryIfThenIsNotInvoked() - { - $factory = $this->createCallableMock(); - $factory - ->expects($this->never()) - ->method('__invoke'); - - new LazyPromise($factory); - } - - /** @test */ - public function shouldCallFactoryIfThenIsInvoked() - { - $factory = $this->createCallableMock(); - $factory - ->expects($this->once()) - ->method('__invoke'); - - $p = new LazyPromise($factory); - $p->then(); - } - - /** @test */ - public function shouldReturnPromiseFromFactory() - { - $factory = $this->createCallableMock(); - $factory - ->expects($this->once()) - ->method('__invoke') - ->will($this->returnValue(new FulfilledPromise(1))); - - $onFulfilled = $this->createCallableMock(); - $onFulfilled - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $p = new LazyPromise($factory); - - $p->then($onFulfilled); - } - - /** @test */ - public function shouldReturnPromiseIfFactoryReturnsNull() - { - $factory = $this->createCallableMock(); - $factory - ->expects($this->once()) - ->method('__invoke') - ->will($this->returnValue(null)); - - $p = new LazyPromise($factory); - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $p->then()); - } - - /** @test */ - public function shouldReturnRejectedPromiseIfFactoryThrowsException() - { - $exception = new \Exception(); - - $factory = $this->createCallableMock(); - $factory - ->expects($this->once()) - ->method('__invoke') - ->will($this->throwException($exception)); - - $onRejected = $this->createCallableMock(); - $onRejected - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($exception)); - - $p = new LazyPromise($factory); - - $p->then($this->expectCallableNever(), $onRejected); - } -} +promise(); + }; + + return [ + 'promise' => function () use ($factory) { + return new LazyPromise($factory); + }, + 'resolve' => [$d, 'resolve'], + 'reject' => [$d, 'reject'], + 'progress' => [$d, 'progress'], + ]; + } + + /** @test */ + public function shouldNotCallFactoryIfThenIsNotInvoked() + { + $factory = $this->createCallableMock(); + $factory + ->expects($this->never()) + ->method('__invoke'); + + new LazyPromise($factory); + } + + /** @test */ + public function shouldCallFactoryIfThenIsInvoked() + { + $factory = $this->createCallableMock(); + $factory + ->expects($this->once()) + ->method('__invoke'); + + $p = new LazyPromise($factory); + $p->then(); + } + + /** @test */ + public function shouldReturnPromiseFromFactory() + { + $factory = $this->createCallableMock(); + $factory + ->expects($this->once()) + ->method('__invoke') + ->will($this->returnValue(new FulfilledPromise(1))); + + $onFulfilled = $this->createCallableMock(); + $onFulfilled + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $p = new LazyPromise($factory); + + $p->then($onFulfilled); + } + + /** @test */ + public function shouldReturnPromiseIfFactoryReturnsNull() + { + $factory = $this->createCallableMock(); + $factory + ->expects($this->once()) + ->method('__invoke') + ->will($this->returnValue(null)); + + $p = new LazyPromise($factory); + $this->assertInstanceOf('React\\Promise\\PromiseInterface', $p->then()); + } + + /** @test */ + public function shouldReturnRejectedPromiseIfFactoryThrowsException() + { + $exception = new \Exception(); + + $factory = $this->createCallableMock(); + $factory + ->expects($this->once()) + ->method('__invoke') + ->will($this->throwException($exception)); + + $onRejected = $this->createCallableMock(); + $onRejected + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $p = new LazyPromise($factory); + + $p->then($this->expectCallableNever(), $onRejected); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest.php index d33de759..46f0abe3 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest.php @@ -1,47 +1,47 @@ - function () use ($promise) { - return $promise; - }, - 'resolve' => $resolveCallback, - 'reject' => $rejectCallback, - 'progress' => $progressCallback, - ]; - } - - /** @test */ - public function shouldRejectIfResolverThrowsException() - { - $exception = new \Exception('foo'); - - $promise = new Promise(function () use ($exception) { - throw $exception; - }); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($exception)); - - $promise - ->then($this->expectCallableNever(), $mock); - } -} + function () use ($promise) { + return $promise; + }, + 'resolve' => $resolveCallback, + 'reject' => $rejectCallback, + 'progress' => $progressCallback, + ]; + } + + /** @test */ + public function shouldRejectIfResolverThrowsException() + { + $exception = new \Exception('foo'); + + $promise = new Promise(function () use ($exception) { + throw $exception; + }); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $promise + ->then($this->expectCallableNever(), $mock); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/FullTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/FullTestTrait.php index cf96fca4..ca3cda78 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/FullTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/FullTestTrait.php @@ -1,13 +1,13 @@ -getPromiseTestAdapter()); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - $promise() - ->then($this->expectCallableNever(), $this->expectCallableNever(), $mock); - - $progress($sentinel); - } - - /** @test */ - public function progressShouldPropagateProgressToDownstreamPromises() - { - extract($this->getPromiseTestAdapter()); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->returnArgument(0)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - $promise() - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock2 - ); - - $progress($sentinel); - } - - /** @test */ - public function progressShouldPropagateTransformedProgressToDownstreamPromises() - { - extract($this->getPromiseTestAdapter()); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->returnValue($sentinel)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - $promise() - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock2 - ); - - $progress(1); - } - - /** @test */ - public function progressShouldPropagateCaughtExceptionValueAsProgress() - { - extract($this->getPromiseTestAdapter()); - - $exception = new \Exception(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->throwException($exception)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($exception)); - - $promise() - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock2 - ); - - $progress(1); - } - - /** @test */ - public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise() - { - extract($this->getPromiseTestAdapter()); - extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - // resolve BEFORE attaching progress handler - $resolve(); - - $promise() - ->then(function () use ($other_promise) { - return $other_promise(); - }) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ); - - $other_progress($sentinel); - } - - /** @test */ - public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise() - { - extract($this->getPromiseTestAdapter()); - extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - $promise() - ->then(function () use ($other_promise) { - return $other_promise(); - }) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ); - - // resolve AFTER attaching progress handler - $resolve(); - $other_progress($sentinel); - } - - /** @test */ - public function progressShouldForwardProgressWhenResolvedWithAnotherPromise() - { - extract($this->getPromiseTestAdapter()); - extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); - - $sentinel = new \stdClass(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->returnValue($sentinel)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($sentinel); - - $promise() - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock - ) - ->then( - $this->expectCallableNever(), - $this->expectCallableNever(), - $mock2 - ); - - $resolve($other_promise()); - $other_progress($sentinel); - } - - /** @test */ - public function progressShouldAllowResolveAfterProgress() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->at(0)) - ->method('__invoke') - ->with($this->identicalTo(1)); - $mock - ->expects($this->at(1)) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $promise() - ->then( - $mock, - $this->expectCallableNever(), - $mock - ); - - $progress(1); - $resolve(2); - } - - /** @test */ - public function progressShouldAllowRejectAfterProgress() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->at(0)) - ->method('__invoke') - ->with($this->identicalTo(1)); - $mock - ->expects($this->at(1)) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $promise() - ->then( - $this->expectCallableNever(), - $mock, - $mock - ); - - $progress(1); - $reject(2); - } - - /** @test */ - public function progressShouldReturnSilentlyOnProgressWhenAlreadyResolved() - { - extract($this->getPromiseTestAdapter()); - - $resolve(1); - - $this->assertNull($progress()); - } - - /** @test */ - public function progressShouldReturnSilentlyOnProgressWhenAlreadyRejected() - { - extract($this->getPromiseTestAdapter()); - - $reject(1); - - $this->assertNull($progress()); - } -} +getPromiseTestAdapter()); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + $promise() + ->then($this->expectCallableNever(), $this->expectCallableNever(), $mock); + + $progress($sentinel); + } + + /** @test */ + public function progressShouldPropagateProgressToDownstreamPromises() + { + extract($this->getPromiseTestAdapter()); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->returnArgument(0)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + $promise() + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock2 + ); + + $progress($sentinel); + } + + /** @test */ + public function progressShouldPropagateTransformedProgressToDownstreamPromises() + { + extract($this->getPromiseTestAdapter()); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->returnValue($sentinel)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + $promise() + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock2 + ); + + $progress(1); + } + + /** @test */ + public function progressShouldPropagateCaughtExceptionValueAsProgress() + { + extract($this->getPromiseTestAdapter()); + + $exception = new \Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->throwException($exception)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $promise() + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock2 + ); + + $progress(1); + } + + /** @test */ + public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAResolvedPromiseReturnsAPromise() + { + extract($this->getPromiseTestAdapter()); + extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + // resolve BEFORE attaching progress handler + $resolve(); + + $promise() + ->then(function () use ($other_promise) { + return $other_promise(); + }) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ); + + $other_progress($sentinel); + } + + /** @test */ + public function progressShouldForwardProgressEventsWhenIntermediaryCallbackTiedToAnUnresolvedPromiseReturnsAPromise() + { + extract($this->getPromiseTestAdapter()); + extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + $promise() + ->then(function () use ($other_promise) { + return $other_promise(); + }) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ); + + // resolve AFTER attaching progress handler + $resolve(); + $other_progress($sentinel); + } + + /** @test */ + public function progressShouldForwardProgressWhenResolvedWithAnotherPromise() + { + extract($this->getPromiseTestAdapter()); + extract($this->getPromiseTestAdapter(), EXTR_PREFIX_ALL, 'other'); + + $sentinel = new \stdClass(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->returnValue($sentinel)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($sentinel); + + $promise() + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock + ) + ->then( + $this->expectCallableNever(), + $this->expectCallableNever(), + $mock2 + ); + + $resolve($other_promise()); + $other_progress($sentinel); + } + + /** @test */ + public function progressShouldAllowResolveAfterProgress() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->at(0)) + ->method('__invoke') + ->with($this->identicalTo(1)); + $mock + ->expects($this->at(1)) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $promise() + ->then( + $mock, + $this->expectCallableNever(), + $mock + ); + + $progress(1); + $resolve(2); + } + + /** @test */ + public function progressShouldAllowRejectAfterProgress() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->at(0)) + ->method('__invoke') + ->with($this->identicalTo(1)); + $mock + ->expects($this->at(1)) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $promise() + ->then( + $this->expectCallableNever(), + $mock, + $mock + ); + + $progress(1); + $reject(2); + } + + /** @test */ + public function progressShouldReturnSilentlyOnProgressWhenAlreadyResolved() + { + extract($this->getPromiseTestAdapter()); + + $resolve(1); + + $this->assertNull($progress()); + } + + /** @test */ + public function progressShouldReturnSilentlyOnProgressWhenAlreadyRejected() + { + extract($this->getPromiseTestAdapter()); + + $reject(1); + + $this->assertNull($progress()); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseFulfilledTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseFulfilledTestTrait.php index d27cec81..0a1967af 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseFulfilledTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseFulfilledTestTrait.php @@ -1,137 +1,137 @@ -getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $resolve(1); - $promise() - ->then( - null, - $this->expectCallableNever() - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function thenShouldForwardCallbackResultToNextCallback() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $resolve(1); - $promise() - ->then( - function ($val) { - return $val + 1; - }, - $this->expectCallableNever() - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function thenShouldForwardPromisedCallbackResultValueToNextCallback() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $resolve(1); - $promise() - ->then( - function ($val) { - return \React\Promise\resolve($val + 1); - }, - $this->expectCallableNever() - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejection() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $resolve(1); - $promise() - ->then( - function ($val) { - return \React\Promise\reject($val + 1); - }, - $this->expectCallableNever() - ) - ->then( - $this->expectCallableNever(), - $mock - ); - } - - /** @test */ - public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows() - { - extract($this->getPromiseTestAdapter()); - - $exception = new \Exception(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->throwException($exception)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($exception)); - - $resolve(1); - $promise() - ->then( - $mock, - $this->expectCallableNever() - ) - ->then( - $this->expectCallableNever(), - $mock2 - ); - } -} +getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $resolve(1); + $promise() + ->then( + null, + $this->expectCallableNever() + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function thenShouldForwardCallbackResultToNextCallback() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $resolve(1); + $promise() + ->then( + function ($val) { + return $val + 1; + }, + $this->expectCallableNever() + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function thenShouldForwardPromisedCallbackResultValueToNextCallback() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $resolve(1); + $promise() + ->then( + function ($val) { + return \React\Promise\resolve($val + 1); + }, + $this->expectCallableNever() + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackReturnsARejection() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $resolve(1); + $promise() + ->then( + function ($val) { + return \React\Promise\reject($val + 1); + }, + $this->expectCallableNever() + ) + ->then( + $this->expectCallableNever(), + $mock + ); + } + + /** @test */ + public function thenShouldSwitchFromCallbacksToErrbacksWhenCallbackThrows() + { + extract($this->getPromiseTestAdapter()); + + $exception = new \Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->throwException($exception)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $resolve(1); + $promise() + ->then( + $mock, + $this->expectCallableNever() + ) + ->then( + $this->expectCallableNever(), + $mock2 + ); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseRejectedTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseRejectedTestTrait.php index 9eed856b..8c97186e 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseRejectedTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseRejectedTestTrait.php @@ -1,142 +1,142 @@ -getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with(null); - - $reject(1); - $promise() - ->then( - $this->expectCallableNever(), - function () { - // Presence of rejection handler is enough to switch back - // to resolve mode, even though it returns undefined. - // The ONLY way to propagate a rejection is to re-throw or - // return a rejected promise; - } - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyPropagate() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $reject(1); - $promise() - ->then( - $this->expectCallableNever(), - function ($val) { - return $val + 1; - } - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $reject(1); - $promise() - ->then( - $this->expectCallableNever(), - function ($val) { - return \React\Promise\resolve($val + 1); - } - ) - ->then( - $mock, - $this->expectCallableNever() - ); - } - - /** @test */ - public function shouldPropagateRejectionsWhenErrbackThrows() - { - extract($this->getPromiseTestAdapter()); - - $exception = new \Exception(); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->will($this->throwException($exception)); - - $mock2 = $this->createCallableMock(); - $mock2 - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo($exception)); - - $reject(1); - $promise() - ->then( - $this->expectCallableNever(), - $mock - ) - ->then( - $this->expectCallableNever(), - $mock2 - ); - } - - /** @test */ - public function shouldPropagateRejectionsWhenErrbackReturnsARejection() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(2)); - - $reject(1); - $promise() - ->then( - $this->expectCallableNever(), - function ($val) { - return \React\Promise\reject($val + 1); - } - ) - ->then( - $this->expectCallableNever(), - $mock - ); - } -} +getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with(null); + + $reject(1); + $promise() + ->then( + $this->expectCallableNever(), + function () { + // Presence of rejection handler is enough to switch back + // to resolve mode, even though it returns undefined. + // The ONLY way to propagate a rejection is to re-throw or + // return a rejected promise; + } + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function shouldSwitchFromErrbacksToCallbacksWhenErrbackDoesNotExplicitlyPropagate() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $reject(1); + $promise() + ->then( + $this->expectCallableNever(), + function ($val) { + return $val + 1; + } + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function shouldSwitchFromErrbacksToCallbacksWhenErrbackReturnsAResolution() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $reject(1); + $promise() + ->then( + $this->expectCallableNever(), + function ($val) { + return \React\Promise\resolve($val + 1); + } + ) + ->then( + $mock, + $this->expectCallableNever() + ); + } + + /** @test */ + public function shouldPropagateRejectionsWhenErrbackThrows() + { + extract($this->getPromiseTestAdapter()); + + $exception = new \Exception(); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->will($this->throwException($exception)); + + $mock2 = $this->createCallableMock(); + $mock2 + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo($exception)); + + $reject(1); + $promise() + ->then( + $this->expectCallableNever(), + $mock + ) + ->then( + $this->expectCallableNever(), + $mock2 + ); + } + + /** @test */ + public function shouldPropagateRejectionsWhenErrbackReturnsARejection() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(2)); + + $reject(1); + $promise() + ->then( + $this->expectCallableNever(), + function ($val) { + return \React\Promise\reject($val + 1); + } + ) + ->then( + $this->expectCallableNever(), + $mock + ); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseTestTrait.php index 1fdc0c0f..9c83b937 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/PromiseTestTrait.php @@ -1,24 +1,24 @@ -getPromiseTestAdapter()); - - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $promise()->then()); - } - - /** @test */ - public function thenShouldReturnAllowNull() - { - extract($this->getPromiseTestAdapter()); - - $this->assertInstanceOf('React\\Promise\\PromiseInterface', $promise()->then(null, null, null)); - } -} +getPromiseTestAdapter()); + + $this->assertInstanceOf('React\\Promise\\PromiseInterface', $promise()->then()); + } + + /** @test */ + public function thenShouldReturnAllowNull() + { + extract($this->getPromiseTestAdapter()); + + $this->assertInstanceOf('React\\Promise\\PromiseInterface', $promise()->then(null, null, null)); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/RejectTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/RejectTestTrait.php index 783b87e7..09119ead 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/RejectTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/RejectTestTrait.php @@ -1,101 +1,101 @@ -getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($this->expectCallableNever(), $mock); - - $reject(1); - } - - /** @test */ - public function rejectShouldRejectWithFulfilledPromise() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($this->expectCallableNever(), $mock); - - $reject(Promise\resolve(1)); - } - - /** @test */ - public function rejectShouldRejectWithRejectedPromise() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($this->expectCallableNever(), $mock); - - $reject(Promise\reject(1)); - } - - /** @test */ - public function rejectShouldInvokeNewlyAddedErrbackWhenAlreadyRejected() - { - extract($this->getPromiseTestAdapter()); - - $reject(1); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($this->expectCallableNever(), $mock); - } - - /** @test */ - public function rejectShouldForwardReasonWhenCallbackIsNull() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then( - $this->expectCallableNever() - ) - ->then( - $this->expectCallableNever(), - $mock - ); - - $reject(1); - } -} +getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($this->expectCallableNever(), $mock); + + $reject(1); + } + + /** @test */ + public function rejectShouldRejectWithFulfilledPromise() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($this->expectCallableNever(), $mock); + + $reject(Promise\resolve(1)); + } + + /** @test */ + public function rejectShouldRejectWithRejectedPromise() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($this->expectCallableNever(), $mock); + + $reject(Promise\reject(1)); + } + + /** @test */ + public function rejectShouldInvokeNewlyAddedErrbackWhenAlreadyRejected() + { + extract($this->getPromiseTestAdapter()); + + $reject(1); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($this->expectCallableNever(), $mock); + } + + /** @test */ + public function rejectShouldForwardReasonWhenCallbackIsNull() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then( + $this->expectCallableNever() + ) + ->then( + $this->expectCallableNever(), + $mock + ); + + $reject(1); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/ResolveTestTrait.php b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/ResolveTestTrait.php index 18b45367..d6bdd9d0 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/ResolveTestTrait.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/PromiseTest/ResolveTestTrait.php @@ -1,102 +1,102 @@ -getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($mock); - - $resolve(1); - } - - /** @test */ - public function resolveShouldResolveWithPromisedValue() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($mock); - - $resolve(Promise\resolve(1)); - } - - /** @test */ - public function resolveShouldRejectWhenResolvedWithRejectedPromise() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($this->expectCallableNever(), $mock); - - $resolve(Promise\reject(1)); - } - - /** @test */ - public function resolveShouldInvokeNewlyAddedCallbackWhenAlreadyResolved() - { - extract($this->getPromiseTestAdapter()); - - $resolve(1); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then($mock, $this->expectCallableNever()); - } - - /** @test */ - public function resolveShouldForwardValueWhenCallbackIsNull() - { - extract($this->getPromiseTestAdapter()); - - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke') - ->with($this->identicalTo(1)); - - $promise() - ->then( - null, - $this->expectCallableNever() - ) - ->then( - $mock, - $this->expectCallableNever() - ); - - $resolve(1); - } -} +getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($mock); + + $resolve(1); + } + + /** @test */ + public function resolveShouldResolveWithPromisedValue() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($mock); + + $resolve(Promise\resolve(1)); + } + + /** @test */ + public function resolveShouldRejectWhenResolvedWithRejectedPromise() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($this->expectCallableNever(), $mock); + + $resolve(Promise\reject(1)); + } + + /** @test */ + public function resolveShouldInvokeNewlyAddedCallbackWhenAlreadyResolved() + { + extract($this->getPromiseTestAdapter()); + + $resolve(1); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then($mock, $this->expectCallableNever()); + } + + /** @test */ + public function resolveShouldForwardValueWhenCallbackIsNull() + { + extract($this->getPromiseTestAdapter()); + + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke') + ->with($this->identicalTo(1)); + + $promise() + ->then( + null, + $this->expectCallableNever() + ) + ->then( + $mock, + $this->expectCallableNever() + ); + + $resolve(1); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/RejectedPromiseTest.php b/app/libs/vendor/react/promise/tests/React/Promise/RejectedPromiseTest.php index 8050a4ad..97cd6da1 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/RejectedPromiseTest.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/RejectedPromiseTest.php @@ -1,44 +1,44 @@ - function () use (&$val, &$promiseCalled) { - $promiseCalled = true; - - return new RejectedPromise($val); - }, - 'resolve' => function ($value) { - throw new \LogicException('You cannot call resolve() for React\Promise\RejectedPromise'); - }, - 'reject' => function ($reason) use (&$val, &$promiseCalled) { - if ($promiseCalled) { - throw new \LogicException('You must call reject() before promise() for React\Promise\RejectedPromise'); - } - - $val = $reason; - }, - 'progress' => function () { - throw new \LogicException('You cannot call progress() for React\Promise\RejectedPromise'); - }, - ]; - } - - /** @test */ - public function shouldThrowExceptionIfConstructedWithAPromise() - { - $this->setExpectedException('\InvalidArgumentException'); - - return new RejectedPromise(new RejectedPromise()); - } -} + function () use (&$val, &$promiseCalled) { + $promiseCalled = true; + + return new RejectedPromise($val); + }, + 'resolve' => function ($value) { + throw new \LogicException('You cannot call resolve() for React\Promise\RejectedPromise'); + }, + 'reject' => function ($reason) use (&$val, &$promiseCalled) { + if ($promiseCalled) { + throw new \LogicException('You must call reject() before promise() for React\Promise\RejectedPromise'); + } + + $val = $reason; + }, + 'progress' => function () { + throw new \LogicException('You cannot call progress() for React\Promise\RejectedPromise'); + }, + ]; + } + + /** @test */ + public function shouldThrowExceptionIfConstructedWithAPromise() + { + $this->setExpectedException('\InvalidArgumentException'); + + return new RejectedPromise(new RejectedPromise()); + } +} diff --git a/app/libs/vendor/react/promise/tests/React/Promise/Stub/CallableStub.php b/app/libs/vendor/react/promise/tests/React/Promise/Stub/CallableStub.php index 70456e44..01208933 100644 --- a/app/libs/vendor/react/promise/tests/React/Promise/Stub/CallableStub.php +++ b/app/libs/vendor/react/promise/tests/React/Promise/Stub/CallableStub.php @@ -1,10 +1,10 @@ -createCallableMock(); - $mock - ->expects($this->exactly($amount)) - ->method('__invoke'); - - return $mock; - } - - public function expectCallableOnce() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->once()) - ->method('__invoke'); - - return $mock; - } - - public function expectCallableNever() - { - $mock = $this->createCallableMock(); - $mock - ->expects($this->never()) - ->method('__invoke'); - - return $mock; - } - - public function createCallableMock() - { - return $this->getMock('React\\Promise\Stub\CallableStub'); - } -} +createCallableMock(); + $mock + ->expects($this->exactly($amount)) + ->method('__invoke'); + + return $mock; + } + + public function expectCallableOnce() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->once()) + ->method('__invoke'); + + return $mock; + } + + public function expectCallableNever() + { + $mock = $this->createCallableMock(); + $mock + ->expects($this->never()) + ->method('__invoke'); + + return $mock; + } + + public function createCallableMock() + { + return $this->getMock('React\\Promise\Stub\CallableStub'); + } +} diff --git a/app/libs/vendor/react/promise/tests/bootstrap.php b/app/libs/vendor/react/promise/tests/bootstrap.php index 3826688f..e2333359 100644 --- a/app/libs/vendor/react/promise/tests/bootstrap.php +++ b/app/libs/vendor/react/promise/tests/bootstrap.php @@ -1,4 +1,4 @@ -add('React\Promise', __DIR__); +add('React\Promise', __DIR__); diff --git a/app/libs/vendor/react/react/.gitignore b/app/libs/vendor/react/react/.gitignore index 2e5fba29..7c97585f 100644 --- a/app/libs/vendor/react/react/.gitignore +++ b/app/libs/vendor/react/react/.gitignore @@ -1,2 +1,2 @@ -.subsplit -vendor +.subsplit +vendor diff --git a/app/libs/vendor/react/react/.travis.yml b/app/libs/vendor/react/react/.travis.yml index 6996f4e4..39432951 100644 --- a/app/libs/vendor/react/react/.travis.yml +++ b/app/libs/vendor/react/react/.travis.yml @@ -1,14 +1,14 @@ -language: php - -php: - - 5.4 - - 5.5 - - hhvm - -matrix: - allow_failures: - - php: hhvm - -install: ./scripts/travis-init.sh - -script: php vendor/bin/phpunit --coverage-text +language: php + +php: + - 5.4 + - 5.5 + - hhvm + +matrix: + allow_failures: + - php: hhvm + +install: ./scripts/travis-init.sh + +script: php vendor/bin/phpunit --coverage-text diff --git a/app/libs/vendor/react/react/CHANGELOG.md b/app/libs/vendor/react/react/CHANGELOG.md index bd38bcb5..f0103f00 100644 --- a/app/libs/vendor/react/react/CHANGELOG.md +++ b/app/libs/vendor/react/react/CHANGELOG.md @@ -1,112 +1,112 @@ -CHANGELOG -========= - -### 0.4.1 (2014-04-13) - - * Bug fix: [EventLoop] null timeout in StreamSelectLoop causing 100% CPU usage (@clue) - * Bug fix: [Socket] Check read buffer for data before shutdown signal and end emit (@ArtyDev) - * Bug fix: [DNS] Fixed PSR-4 autoload path (@marcj/WyriHaximus) - * Bug fix: v0.3.4 changes merged for v0.4.1 - -### 0.3.4 (2014-03-30) - - * Bug fix: [Stream] Fixed 100% CPU spike from non-empty write buffer on closed stream - * Buf fix: [Socket] Reset socket to non-blocking after shutting down (PHP bug) - -### 0.4.0 (2014-02-02) - - * Feature: Added ChildProcess to run async child processes within the event loop (@jmikola) - * Feature: [EventLoop] Added `EventLoopInterface::nextTick()`, implemented in all event loops (@jmalloc) - * Feature: [EventLoop] Added `EventLoopInterface::futureTick()`, implemented in all event loops (@jmalloc) - * Feature: [EventLoop] Added `ExtEventLoop` implementation using pecl/event (@jmalloc) - * BC break: [HttpClient] Drop unused `Response::getBody()` - * BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks - * BC break: Remove `$loop` argument from `HttpClient`: `Client`, `Request`, `Response` - * BC break: Update to React/Promise 2.0 - * BC break: Update to Evenement 2.0 - * BC break: [EventLoop] New method: `EventLoopInterface::nextTick()` - * BC break: [EventLoop] New method: `EventLoopInterface::futureTick()` - * Bug fix: [Dns] Properly resolve CNAME aliases - * Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0 - -### 0.3.3 (2013-07-08) - - * Bug fix: [EventLoop] No error on removing non-existent streams (@clue) - * Bug fix: [EventLoop] Do not silently remove feof listeners in `LibEvLoop` - * Bug fix: [Stream] Correctly detect closed connections - -### 0.3.2 (2013-05-10) - - * Feature: [Dns] Support default port for IPv6 addresses (@clue) - * Bug fix: [Stream] Make sure CompositeStream is closed properly - -### 0.3.1 (2013-04-21) - - * Feature: [Socket] Support binding to IPv6 addresses (@clue) - * Feature: [SocketClient] Support connecting to IPv6 addresses (@clue) - * Bug fix: [Stream] Allow any `ReadableStreamInterface` on `BufferedSink::createPromise()` - * Bug fix: [HttpClient] Correct requirement for socket-client - -### 0.3.0 (2013-04-14) - - * BC break: [EventLoop] New timers API (@nrk) - * BC break: [EventLoop] Remove check on return value from stream callbacks (@nrk) - * BC break: [HttpClient] Socket connection handling moved to new SocketClient component - * Feature: [SocketClient] New SocketClient component extracted from HttpClient (@clue) - * Feature: [Stream] Factory method for BufferedSink - -### 0.2.7 (2013-01-05) - - * Bug fix: [EventLoop] Fix libevent timers with PHP 5.3 - * Bug fix: [EventLoop] Fix libevent timer cancellation (@nrk) - -### 0.2.6 (2012-12-26) - - * Feature: [Cache] New cache component, used by DNS - * Bug fix: [Http] Emit end event when Response closes (@beaucollins) - * Bug fix: [EventLoop] Plug memory issue in libevent timers (@cameronjacobson) - * Bug fix: [EventLoop] Correctly pause LibEvLoop on stop() - -### 0.2.5 (2012-11-26) - - * Feature: [Stream] Make BufferedSink trigger progress events on the promise (@jsor) - * Feature: [HttpClient] Use a promise-based API internally - * Bug fix: [HttpClient] Use DNS resolver correctly - -### 0.2.4 (2012-11-18) - - * Feature: [Stream] Added ThroughStream, CompositeStream, ReadableStream and WritableStream - * Feature: [Stream] Added BufferedSink - * Feature: [Dns] Change to promise-based API (@jsor) - -### 0.2.3 (2012-11-14) - - * Feature: LibEvLoop, integration of `php-libev` - * Bug fix: Forward drain events from HTTP response (@cs278) - * Dependency: Updated guzzle deps to `3.0.*` - -### 0.2.2 (2012-10-28) - - * Major: Dropped Espresso as a core component now available as `react/espresso` only - * Feature: DNS executor timeout handling (@arnaud-lb) - * Feature: DNS retry executor (@arnaud-lb) - * Feature: HTTP client (@arnaud-lb) - -### 0.2.1 (2012-10-14) - - * Feature: Support HTTP 1.1 continue - * Bug fix: Check for EOF in `Buffer::write()` - * Bug fix: Make `Espresso\Stack` work with invokables (such as `Espresso\Application`) - * Minor adjustments to DNS parser - -### 0.2.0 (2012-09-10) - - * Feature: DNS resolver - -### 0.1.1 (2012-07-12) - - * Bug fix: Testing and functional against PHP >= 5.3.3 and <= 5.3.8 - -### 0.1.0 (2012-07-11) - - * First tagged release +CHANGELOG +========= + +### 0.4.1 (2014-04-13) + + * Bug fix: [EventLoop] null timeout in StreamSelectLoop causing 100% CPU usage (@clue) + * Bug fix: [Socket] Check read buffer for data before shutdown signal and end emit (@ArtyDev) + * Bug fix: [DNS] Fixed PSR-4 autoload path (@marcj/WyriHaximus) + * Bug fix: v0.3.4 changes merged for v0.4.1 + +### 0.3.4 (2014-03-30) + + * Bug fix: [Stream] Fixed 100% CPU spike from non-empty write buffer on closed stream + * Buf fix: [Socket] Reset socket to non-blocking after shutting down (PHP bug) + +### 0.4.0 (2014-02-02) + + * Feature: Added ChildProcess to run async child processes within the event loop (@jmikola) + * Feature: [EventLoop] Added `EventLoopInterface::nextTick()`, implemented in all event loops (@jmalloc) + * Feature: [EventLoop] Added `EventLoopInterface::futureTick()`, implemented in all event loops (@jmalloc) + * Feature: [EventLoop] Added `ExtEventLoop` implementation using pecl/event (@jmalloc) + * BC break: [HttpClient] Drop unused `Response::getBody()` + * BC break: Bump minimum PHP version to PHP 5.4, remove 5.3 specific hacks + * BC break: Remove `$loop` argument from `HttpClient`: `Client`, `Request`, `Response` + * BC break: Update to React/Promise 2.0 + * BC break: Update to Evenement 2.0 + * BC break: [EventLoop] New method: `EventLoopInterface::nextTick()` + * BC break: [EventLoop] New method: `EventLoopInterface::futureTick()` + * Bug fix: [Dns] Properly resolve CNAME aliases + * Dependency: Autoloading and filesystem structure now PSR-4 instead of PSR-0 + +### 0.3.3 (2013-07-08) + + * Bug fix: [EventLoop] No error on removing non-existent streams (@clue) + * Bug fix: [EventLoop] Do not silently remove feof listeners in `LibEvLoop` + * Bug fix: [Stream] Correctly detect closed connections + +### 0.3.2 (2013-05-10) + + * Feature: [Dns] Support default port for IPv6 addresses (@clue) + * Bug fix: [Stream] Make sure CompositeStream is closed properly + +### 0.3.1 (2013-04-21) + + * Feature: [Socket] Support binding to IPv6 addresses (@clue) + * Feature: [SocketClient] Support connecting to IPv6 addresses (@clue) + * Bug fix: [Stream] Allow any `ReadableStreamInterface` on `BufferedSink::createPromise()` + * Bug fix: [HttpClient] Correct requirement for socket-client + +### 0.3.0 (2013-04-14) + + * BC break: [EventLoop] New timers API (@nrk) + * BC break: [EventLoop] Remove check on return value from stream callbacks (@nrk) + * BC break: [HttpClient] Socket connection handling moved to new SocketClient component + * Feature: [SocketClient] New SocketClient component extracted from HttpClient (@clue) + * Feature: [Stream] Factory method for BufferedSink + +### 0.2.7 (2013-01-05) + + * Bug fix: [EventLoop] Fix libevent timers with PHP 5.3 + * Bug fix: [EventLoop] Fix libevent timer cancellation (@nrk) + +### 0.2.6 (2012-12-26) + + * Feature: [Cache] New cache component, used by DNS + * Bug fix: [Http] Emit end event when Response closes (@beaucollins) + * Bug fix: [EventLoop] Plug memory issue in libevent timers (@cameronjacobson) + * Bug fix: [EventLoop] Correctly pause LibEvLoop on stop() + +### 0.2.5 (2012-11-26) + + * Feature: [Stream] Make BufferedSink trigger progress events on the promise (@jsor) + * Feature: [HttpClient] Use a promise-based API internally + * Bug fix: [HttpClient] Use DNS resolver correctly + +### 0.2.4 (2012-11-18) + + * Feature: [Stream] Added ThroughStream, CompositeStream, ReadableStream and WritableStream + * Feature: [Stream] Added BufferedSink + * Feature: [Dns] Change to promise-based API (@jsor) + +### 0.2.3 (2012-11-14) + + * Feature: LibEvLoop, integration of `php-libev` + * Bug fix: Forward drain events from HTTP response (@cs278) + * Dependency: Updated guzzle deps to `3.0.*` + +### 0.2.2 (2012-10-28) + + * Major: Dropped Espresso as a core component now available as `react/espresso` only + * Feature: DNS executor timeout handling (@arnaud-lb) + * Feature: DNS retry executor (@arnaud-lb) + * Feature: HTTP client (@arnaud-lb) + +### 0.2.1 (2012-10-14) + + * Feature: Support HTTP 1.1 continue + * Bug fix: Check for EOF in `Buffer::write()` + * Bug fix: Make `Espresso\Stack` work with invokables (such as `Espresso\Application`) + * Minor adjustments to DNS parser + +### 0.2.0 (2012-09-10) + + * Feature: DNS resolver + +### 0.1.1 (2012-07-12) + + * Bug fix: Testing and functional against PHP >= 5.3.3 and <= 5.3.8 + +### 0.1.0 (2012-07-11) + + * First tagged release diff --git a/app/libs/vendor/react/react/README.md b/app/libs/vendor/react/react/README.md index 22f47b7f..3addd463 100644 --- a/app/libs/vendor/react/react/README.md +++ b/app/libs/vendor/react/react/README.md @@ -1,104 +1,104 @@ -# React - -Event-driven, non-blocking I/O with PHP. - -[![Build Status](https://secure.travis-ci.org/reactphp/react.png?branch=master)](http://travis-ci.org/reactphp/react) - -## Install - -The recommended way to install react is [through composer](http://getcomposer.org). - -```JSON -{ - "require": { - "react/react": "0.4.*" - } -} -``` - -## What is it? - -React is a low-level library for event-driven programming in PHP. At its core -is an event loop, on top of which it provides low-level utilities, such as: -Streams abstraction, async dns resolver, network client/server, http -client/server, interaction with processes. Third-party libraries can use these -components to create async network clients/servers and more. - -The event loop is based on the reactor pattern (hence the name) and strongly -inspired by libraries such as EventMachine (Ruby), Twisted (Python) and -Node.js (V8). - -## Design goals - -* Usable with a bare minimum of PHP extensions, add more extensions to get better performance. -* Provide a standalone event-loop component that can be re-used by other libraries. -* Decouple parts so they can be replaced by alternate implementations. - -React is non-blocking by default. Use workers for blocking I/O. - -## High-level abstractions - -There are two main abstractions that make dealing with control flow a lot more -manageable. - -* **Stream:** A stream represents an I/O source (ReadableStream) or - destination (WritableStream). These can be used to model pipes, similar - to a unix pipe that is composed of processes. Streams represent very large - values as chunks. - -* **Promise:** A promise represents an eventual return value. Promises can be - composed and are a lot easier to deal with than traditional CPS callback - spaghetti and allow for almost sane error handling. Promises represent the - computation for producing single values. - -You should use these abstractions whenever you can. - -## Usage - -Here is an example of a simple HTTP server listening on port 1337: -```php - 'text/plain'); - - $response->writeHead(200, $headers); - $response->end($text); -}; - -$loop = React\EventLoop\Factory::create(); -$socket = new React\Socket\Server($loop); -$http = new React\Http\Server($socket); - -$http->on('request', $app); - -$socket->listen(1337); -$loop->run(); -``` - -## Documentation - -Superficial documentation can be found in the README files of the individual -components. See `src/*/README.md`. - -## Community - -Check out #reactphp on irc.freenode.net. Also follow -[@reactphp](https://twitter.com/reactphp) on twitter. - -## Tests - -To run the test suite, you need install the dependencies via composer, then -run PHPUnit. - - $ composer install - $ phpunit - -## License - -MIT, see LICENSE. +# React + +Event-driven, non-blocking I/O with PHP. + +[![Build Status](https://secure.travis-ci.org/reactphp/react.png?branch=master)](http://travis-ci.org/reactphp/react) + +## Install + +The recommended way to install react is [through composer](http://getcomposer.org). + +```JSON +{ + "require": { + "react/react": "0.4.*" + } +} +``` + +## What is it? + +React is a low-level library for event-driven programming in PHP. At its core +is an event loop, on top of which it provides low-level utilities, such as: +Streams abstraction, async dns resolver, network client/server, http +client/server, interaction with processes. Third-party libraries can use these +components to create async network clients/servers and more. + +The event loop is based on the reactor pattern (hence the name) and strongly +inspired by libraries such as EventMachine (Ruby), Twisted (Python) and +Node.js (V8). + +## Design goals + +* Usable with a bare minimum of PHP extensions, add more extensions to get better performance. +* Provide a standalone event-loop component that can be re-used by other libraries. +* Decouple parts so they can be replaced by alternate implementations. + +React is non-blocking by default. Use workers for blocking I/O. + +## High-level abstractions + +There are two main abstractions that make dealing with control flow a lot more +manageable. + +* **Stream:** A stream represents an I/O source (ReadableStream) or + destination (WritableStream). These can be used to model pipes, similar + to a unix pipe that is composed of processes. Streams represent very large + values as chunks. + +* **Promise:** A promise represents an eventual return value. Promises can be + composed and are a lot easier to deal with than traditional CPS callback + spaghetti and allow for almost sane error handling. Promises represent the + computation for producing single values. + +You should use these abstractions whenever you can. + +## Usage + +Here is an example of a simple HTTP server listening on port 1337: +```php + 'text/plain'); + + $response->writeHead(200, $headers); + $response->end($text); +}; + +$loop = React\EventLoop\Factory::create(); +$socket = new React\Socket\Server($loop); +$http = new React\Http\Server($socket); + +$http->on('request', $app); + +$socket->listen(1337); +$loop->run(); +``` + +## Documentation + +Superficial documentation can be found in the README files of the individual +components. See `src/*/README.md`. + +## Community + +Check out #reactphp on irc.freenode.net. Also follow +[@reactphp](https://twitter.com/reactphp) on twitter. + +## Tests + +To run the test suite, you need install the dependencies via composer, then +run PHPUnit. + + $ composer install + $ phpunit + +## License + +MIT, see LICENSE. diff --git a/app/libs/vendor/react/react/UPGRADE-0.3.md b/app/libs/vendor/react/react/UPGRADE-0.3.md index 21b7c94b..e26bce81 100644 --- a/app/libs/vendor/react/react/UPGRADE-0.3.md +++ b/app/libs/vendor/react/react/UPGRADE-0.3.md @@ -1,33 +1,33 @@ -UPGRADE for 0.3.x -================= - -EventLoop ---------- - -* The timer callback now receives a `Timer` instance, with the following - useful methods: - - * `cancel` - * `isActive` - * `setData($data)` - * `getData` - - And some other less common ones. These are prefered over - `LoopInterface::cancelTimer` and `LoopInterface::isTimerActive`. - -* You can no longer return a boolean from a periodic timer callback to abort - it. - -HttpClient ----------- - -* `HttpClient\*ConnectionManager` has been moved to `SocketClient\*Connector`, - and the `getConnection` method has been renamed to `create`. - - Before: - - $connectionManager->getConnection($host, $port); - - After: - - $connector->create($host, $port); +UPGRADE for 0.3.x +================= + +EventLoop +--------- + +* The timer callback now receives a `Timer` instance, with the following + useful methods: + + * `cancel` + * `isActive` + * `setData($data)` + * `getData` + + And some other less common ones. These are prefered over + `LoopInterface::cancelTimer` and `LoopInterface::isTimerActive`. + +* You can no longer return a boolean from a periodic timer callback to abort + it. + +HttpClient +---------- + +* `HttpClient\*ConnectionManager` has been moved to `SocketClient\*Connector`, + and the `getConnection` method has been renamed to `create`. + + Before: + + $connectionManager->getConnection($host, $port); + + After: + + $connector->create($host, $port); diff --git a/app/libs/vendor/react/react/benchmark/bench.php b/app/libs/vendor/react/react/benchmark/bench.php index aaac778a..0a21c835 100644 --- a/app/libs/vendor/react/react/benchmark/bench.php +++ b/app/libs/vendor/react/react/benchmark/bench.php @@ -1,47 +1,47 @@ -prev = microtime(true); - } - - public function snap() { - $prev = $this->prev; - - $current = microtime(true); - $this->prev = $current; - - return $current - $prev; - } - - public function printSnap($name) { - printf("%-40s: %s s\n", $name, $this->snap()); - } -} - -function benchLoops(array $tests) { - $loops = array( - 'StreamSelectLoop', - 'LibEventLoop', - 'LibEvLoop', - // 'LibUvLoop', - ); - - foreach ($tests as $testName => $test) { - foreach ($loops as $loopName) { - $loopClass = "React\\EventLoop\\$loopName"; - $loop = new $loopClass(); - - $bench = new Bench(); - $bench->start(); - - $test($loop); - - $bench->printSnap("$loopName: $testName"); - } - - printf("----------------------------------------\n"); - } -} +prev = microtime(true); + } + + public function snap() { + $prev = $this->prev; + + $current = microtime(true); + $this->prev = $current; + + return $current - $prev; + } + + public function printSnap($name) { + printf("%-40s: %s s\n", $name, $this->snap()); + } +} + +function benchLoops(array $tests) { + $loops = array( + 'StreamSelectLoop', + 'LibEventLoop', + 'LibEvLoop', + // 'LibUvLoop', + ); + + foreach ($tests as $testName => $test) { + foreach ($loops as $loopName) { + $loopClass = "React\\EventLoop\\$loopName"; + $loop = new $loopClass(); + + $bench = new Bench(); + $bench->start(); + + $test($loop); + + $bench->printSnap("$loopName: $testName"); + } + + printf("----------------------------------------\n"); + } +} diff --git a/app/libs/vendor/react/react/benchmark/timers.php b/app/libs/vendor/react/react/benchmark/timers.php index 008bd47f..e0c30a34 100644 --- a/app/libs/vendor/react/react/benchmark/timers.php +++ b/app/libs/vendor/react/react/benchmark/timers.php @@ -1,32 +1,32 @@ - function ($loop) use ($x) { - for ($i = 0; $i < $x; $i++) { - $loop->addTimer(1, function ($signature, $loop) {}); - } - $loop->run(); - }, - $x . ' periodic timers' => function ($loop) use ($x) { - for ($i = 0; $i < $x; $i++) { - $loop->addPeriodicTimer(2, function ($signature, $loop) use (&$i, $x) { - if ($i >= $x) { - $loop->cancelTimer($signature); - } - }); - } - $loop->run(); - }, -); - -benchLoops($tests); + function ($loop) use ($x) { + for ($i = 0; $i < $x; $i++) { + $loop->addTimer(1, function ($signature, $loop) {}); + } + $loop->run(); + }, + $x . ' periodic timers' => function ($loop) use ($x) { + for ($i = 0; $i < $x; $i++) { + $loop->addPeriodicTimer(2, function ($signature, $loop) use (&$i, $x) { + if ($i >= $x) { + $loop->cancelTimer($signature); + } + }); + } + $loop->run(); + }, +); + +benchLoops($tests); diff --git a/app/libs/vendor/react/react/composer.json b/app/libs/vendor/react/react/composer.json index 89cd088e..2cb3eb17 100644 --- a/app/libs/vendor/react/react/composer.json +++ b/app/libs/vendor/react/react/composer.json @@ -1,44 +1,44 @@ -{ - "name": "react/react", - "description": "Nuclear Reactor written in PHP.", - "keywords": ["event-loop", "reactor"], - "license": "MIT", - "support": { - "issues": "https://github.com/reactphp/react/issues", - "irc": "irc://irc.freenode.org/reactphp" - }, - "require": { - "php": ">=5.4.0", - "evenement/evenement": "~2.0", - "guzzle/parser": "~3.0", - "react/promise": "~2.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "replace": { - "react/event-loop": "self.version", - "react/cache": "self.version", - "react/stream": "self.version", - "react/socket": "self.version", - "react/socket-client": "self.version", - "react/http": "self.version", - "react/http-client": "self.version", - "react/dns": "self.version" - }, - "suggest": { - "ext-libevent": "Allows for use of a more performant event-loop implementation.", - "ext-libev": "Allows for use of a more performant event-loop implementation.", - "ext-event": "Allows for use of a more performant event-loop implementation." - }, - "autoload": { - "psr-4": { - "React\\": "src" - } - }, - "extra": { - "branch-alias": { - "dev-master": "0.5-dev" - } - } -} +{ + "name": "react/react", + "description": "Nuclear Reactor written in PHP.", + "keywords": ["event-loop", "reactor"], + "license": "MIT", + "support": { + "issues": "https://github.com/reactphp/react/issues", + "irc": "irc://irc.freenode.org/reactphp" + }, + "require": { + "php": ">=5.4.0", + "evenement/evenement": "~2.0", + "guzzle/parser": "~3.0", + "react/promise": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*" + }, + "replace": { + "react/event-loop": "self.version", + "react/cache": "self.version", + "react/stream": "self.version", + "react/socket": "self.version", + "react/socket-client": "self.version", + "react/http": "self.version", + "react/http-client": "self.version", + "react/dns": "self.version" + }, + "suggest": { + "ext-libevent": "Allows for use of a more performant event-loop implementation.", + "ext-libev": "Allows for use of a more performant event-loop implementation.", + "ext-event": "Allows for use of a more performant event-loop implementation." + }, + "autoload": { + "psr-4": { + "React\\": "src" + } + }, + "extra": { + "branch-alias": { + "dev-master": "0.5-dev" + } + } +} diff --git a/app/libs/vendor/react/react/composer.lock b/app/libs/vendor/react/react/composer.lock index 23ec0d45..aa1e5e5c 100644 --- a/app/libs/vendor/react/react/composer.lock +++ b/app/libs/vendor/react/react/composer.lock @@ -1,574 +1,574 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" - ], - "hash": "29bd288f4bd1d8239306634ed2ba8636", - "packages": [ - { - "name": "evenement/evenement", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/igorw/evenement.git", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-0": { - "Evenement": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Igor Wiedler", - "email": "igor@wiedler.ch", - "homepage": "http://wiedler.ch/igor/" - } - ], - "description": "Événement is a very simple event dispatching library for PHP", - "keywords": [ - "event-dispatcher", - "event-emitter" - ], - "time": "2012-11-02 14:49:47" - }, - { - "name": "guzzle/parser", - "version": "v3.8.1", - "target-dir": "Guzzle/Parser", - "source": { - "type": "git", - "url": "https://github.com/guzzle/parser.git", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", - "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle\\Parser": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Interchangeable parsers used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "URI Template", - "cookie", - "http", - "message", - "url" - ], - "time": "2013-10-24 00:04:09" - }, - { - "name": "react/promise", - "version": "v2.0.0", - "source": { - "type": "git", - "url": "https://github.com/reactphp/promise.git", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", - "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", - "shasum": "" - }, - "require": { - "php": ">=5.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-0": { - "React\\Promise": "src/" - }, - "files": [ - "src/React/Promise/functions.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jan Sorgalla", - "email": "jsorgalla@googlemail.com", - "homepage": "http://sorgalla.com", - "role": "maintainer" - } - ], - "description": "A lightweight implementation of CommonJS Promises/A for PHP", - "time": "2013-12-10 15:40:36" - } - ], - "packages-dev": [ - { - "name": "phpunit/php-code-coverage", - "version": "1.2.15", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ba4ed2895d538a039d5d5866edc4ec0424c7852", - "reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-file-iterator": ">=1.3.0@stable", - "phpunit/php-text-template": ">=1.2.0@stable", - "phpunit/php-token-stream": ">=1.1.3@stable" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*@dev" - }, - "suggest": { - "ext-dom": "*", - "ext-xdebug": ">=2.0.5" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", - "homepage": "https://github.com/sebastianbergmann/php-code-coverage", - "keywords": [ - "coverage", - "testing", - "xunit" - ], - "time": "2014-02-03 07:44:47" - }, - { - "name": "phpunit/php-file-iterator", - "version": "1.3.4", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", - "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "File/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "FilterIterator implementation that filters files based on a list of suffixes.", - "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", - "keywords": [ - "filesystem", - "iterator" - ], - "time": "2013-10-10 15:34:57" - }, - { - "name": "phpunit/php-text-template", - "version": "1.2.0", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "Text/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", - "keywords": [ - "template" - ], - "time": "2014-01-30 17:20:04" - }, - { - "name": "phpunit/php-timer", - "version": "1.0.5", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", - "keywords": [ - "timer" - ], - "time": "2013-08-02 07:42:54" - }, - { - "name": "phpunit/php-token-stream", - "version": "1.2.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", - "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2-dev" - } - }, - "autoload": { - "classmap": [ - "PHP/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", - "keywords": [ - "tokenizer" - ], - "time": "2013-09-13 04:58:23" - }, - { - "name": "phpunit/phpunit", - "version": "3.7.30", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "2f33258fa5a0c330515b7deba2bc040fa5c3953b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2f33258fa5a0c330515b7deba2bc040fa5c3953b", - "reference": "2f33258fa5a0c330515b7deba2bc040fa5c3953b", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", - "phpunit/php-code-coverage": "~1.2.1", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-timer": ">=1.0.4", - "phpunit/phpunit-mock-objects": "~1.2.0", - "symfony/yaml": "~2.0" - }, - "require-dev": { - "pear-pear/pear": "1.9.4" - }, - "suggest": { - "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "phpunit/php-invoker": ">=1.1.0,<1.2.0" - }, - "bin": [ - "composer/bin/phpunit" - ], - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "", - "../../symfony/yaml/" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "lead" - } - ], - "description": "The PHP Unit Testing framework.", - "homepage": "http://www.phpunit.de/", - "keywords": [ - "phpunit", - "testing", - "xunit" - ], - "time": "2014-01-31 08:54:33" - }, - { - "name": "phpunit/phpunit-mock-objects", - "version": "1.2.3", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "phpunit/php-text-template": ">=1.1.1@stable" - }, - "suggest": { - "ext-soap": "*" - }, - "type": "library", - "autoload": { - "classmap": [ - "PHPUnit/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "include-path": [ - "" - ], - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sb@sebastian-bergmann.de", - "role": "lead" - } - ], - "description": "Mock Object library for PHPUnit", - "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", - "keywords": [ - "mock", - "xunit" - ], - "time": "2013-01-13 10:24:48" - }, - { - "name": "symfony/yaml", - "version": "v2.4.1", - "target-dir": "Symfony/Component/Yaml", - "source": { - "type": "git", - "url": "https://github.com/symfony/Yaml.git", - "reference": "4e1a237fc48145fae114b96458d799746ad89aa0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/Yaml/zipball/4e1a237fc48145fae114b96458d799746ad89aa0", - "reference": "4e1a237fc48145fae114b96458d799746ad89aa0", - "shasum": "" - }, - "require": { - "php": ">=5.3.3" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.4-dev" - } - }, - "autoload": { - "psr-0": { - "Symfony\\Component\\Yaml\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - }, - { - "name": "Symfony Community", - "homepage": "http://symfony.com/contributors" - } - ], - "description": "Symfony Yaml Component", - "homepage": "http://symfony.com", - "time": "2013-12-28 08:12:03" - } - ], - "aliases": [ - - ], - "minimum-stability": "stable", - "stability-flags": [ - - ], - "platform": { - "php": ">=5.4.0" - }, - "platform-dev": [ - - ] -} +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" + ], + "hash": "29bd288f4bd1d8239306634ed2ba8636", + "packages": [ + { + "name": "evenement/evenement", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/igorw/evenement.git", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/igorw/evenement/zipball/f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "reference": "f6e843799fd4f4184d54d8fc7b5b3551c9fa803e", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "Evenement": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Igor Wiedler", + "email": "igor@wiedler.ch", + "homepage": "http://wiedler.ch/igor/" + } + ], + "description": "Événement is a very simple event dispatching library for PHP", + "keywords": [ + "event-dispatcher", + "event-emitter" + ], + "time": "2012-11-02 14:49:47" + }, + { + "name": "guzzle/parser", + "version": "v3.8.1", + "target-dir": "Guzzle/Parser", + "source": { + "type": "git", + "url": "https://github.com/guzzle/parser.git", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/parser/zipball/3f52387052f2e4ef083145a0f73c3654aa14e086", + "reference": "3f52387052f2e4ef083145a0f73c3654aa14e086", + "shasum": "" + }, + "require": { + "php": ">=5.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7-dev" + } + }, + "autoload": { + "psr-0": { + "Guzzle\\Parser": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Interchangeable parsers used by Guzzle", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "URI Template", + "cookie", + "http", + "message", + "url" + ], + "time": "2013-10-24 00:04:09" + }, + { + "name": "react/promise", + "version": "v2.0.0", + "source": { + "type": "git", + "url": "https://github.com/reactphp/promise.git", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/reactphp/promise/zipball/58129a9cb9da88f2055309a805e2696b06928bb0", + "reference": "58129a9cb9da88f2055309a805e2696b06928bb0", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-0": { + "React\\Promise": "src/" + }, + "files": [ + "src/React/Promise/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jan Sorgalla", + "email": "jsorgalla@googlemail.com", + "homepage": "http://sorgalla.com", + "role": "maintainer" + } + ], + "description": "A lightweight implementation of CommonJS Promises/A for PHP", + "time": "2013-12-10 15:40:36" + } + ], + "packages-dev": [ + { + "name": "phpunit/php-code-coverage", + "version": "1.2.15", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6ba4ed2895d538a039d5d5866edc4ec0424c7852", + "reference": "6ba4ed2895d538a039d5d5866edc4ec0424c7852", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": ">=1.3.0@stable", + "phpunit/php-text-template": ">=1.2.0@stable", + "phpunit/php-token-stream": ">=1.1.3@stable" + }, + "require-dev": { + "phpunit/phpunit": "3.7.*@dev" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.0.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2014-02-03 07:44:47" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.3.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/acd690379117b042d1c8af1fafd61bde001bf6bb", + "reference": "acd690379117b042d1c8af1fafd61bde001bf6bb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "File/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2013-10-10 15:34:57" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "reference": "206dfefc0ffe9cebf65c413e3d0e809c82fbf00a", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "Text/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2014-01-30 17:20:04" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "reference": "19689d4354b295ee3d8c54b4f42c3efb69cbc17c", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2013-08-02 07:42:54" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", + "reference": "5220af2a7929aa35cf663d97c89ad3d50cf5fa3e", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "classmap": [ + "PHP/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2013-09-13 04:58:23" + }, + { + "name": "phpunit/phpunit", + "version": "3.7.30", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "2f33258fa5a0c330515b7deba2bc040fa5c3953b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2f33258fa5a0c330515b7deba2bc040fa5c3953b", + "reference": "2f33258fa5a0c330515b7deba2bc040fa5c3953b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpunit/php-code-coverage": "~1.2.1", + "phpunit/php-file-iterator": ">=1.3.1", + "phpunit/php-text-template": ">=1.1.1", + "phpunit/php-timer": ">=1.0.4", + "phpunit/phpunit-mock-objects": "~1.2.0", + "symfony/yaml": "~2.0" + }, + "require-dev": { + "pear-pear/pear": "1.9.4" + }, + "suggest": { + "ext-json": "*", + "ext-simplexml": "*", + "ext-tokenizer": "*", + "phpunit/php-invoker": ">=1.1.0,<1.2.0" + }, + "bin": [ + "composer/bin/phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.7.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "", + "../../symfony/yaml/" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "http://www.phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2014-01-31 08:54:33" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "reference": "5794e3c5c5ba0fb037b11d8151add2a07fa82875", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-text-template": ">=1.1.1@stable" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "autoload": { + "classmap": [ + "PHPUnit/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "include-path": [ + "" + ], + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2013-01-13 10:24:48" + }, + { + "name": "symfony/yaml", + "version": "v2.4.1", + "target-dir": "Symfony/Component/Yaml", + "source": { + "type": "git", + "url": "https://github.com/symfony/Yaml.git", + "reference": "4e1a237fc48145fae114b96458d799746ad89aa0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/Yaml/zipball/4e1a237fc48145fae114b96458d799746ad89aa0", + "reference": "4e1a237fc48145fae114b96458d799746ad89aa0", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.4-dev" + } + }, + "autoload": { + "psr-0": { + "Symfony\\Component\\Yaml\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "http://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "http://symfony.com", + "time": "2013-12-28 08:12:03" + } + ], + "aliases": [ + + ], + "minimum-stability": "stable", + "stability-flags": [ + + ], + "platform": { + "php": ">=5.4.0" + }, + "platform-dev": [ + + ] +} diff --git a/app/libs/vendor/react/react/examples/child-child.php b/app/libs/vendor/react/react/examples/child-child.php index d883d62d..a86064ec 100644 --- a/app/libs/vendor/react/react/examples/child-child.php +++ b/app/libs/vendor/react/react/examples/child-child.php @@ -1,10 +1,10 @@ -on('exit', function($exitCode, $termSignal) { - echo "Child exit\n"; -}); - -$loop->addTimer(0.001, function($timer) use ($process) { - $process->start($timer->getLoop()); - - $process->stdout->on('data', function($output) { - echo "Child script says: {$output}"; - }); -}); - -$loop->addPeriodicTimer(5, function($timer) { - echo "Parent cannot be blocked by child\n"; -}); - -$loop->run(); +on('exit', function($exitCode, $termSignal) { + echo "Child exit\n"; +}); + +$loop->addTimer(0.001, function($timer) use ($process) { + $process->start($timer->getLoop()); + + $process->stdout->on('data', function($output) { + echo "Child script says: {$output}"; + }); +}); + +$loop->addPeriodicTimer(5, function($timer) { + echo "Parent cannot be blocked by child\n"; +}); + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/dns-resolver.php b/app/libs/vendor/react/react/examples/dns-resolver.php index fd4f0ea2..3cac3bee 100644 --- a/app/libs/vendor/react/react/examples/dns-resolver.php +++ b/app/libs/vendor/react/react/examples/dns-resolver.php @@ -1,23 +1,23 @@ -create('8.8.8.8', $loop); - -$domain = 'igor.io'; - -$dns - ->resolve($domain) - ->then(function ($ip) { - echo "Host: $ip\n"; - }, function ($e) { - echo "Error: {$e->getMessage()}\n"; - }); - -echo "Resolving domain $domain...\n"; - -$loop->run(); +create('8.8.8.8', $loop); + +$domain = 'igor.io'; + +$dns + ->resolve($domain) + ->then(function ($ip) { + echo "Host: $ip\n"; + }, function ($e) { + echo "Error: {$e->getMessage()}\n"; + }); + +echo "Resolving domain $domain...\n"; + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/echo-server.php b/app/libs/vendor/react/react/examples/echo-server.php index f8cf1fc5..8f1ec12c 100644 --- a/app/libs/vendor/react/react/examples/echo-server.php +++ b/app/libs/vendor/react/react/examples/echo-server.php @@ -1,18 +1,18 @@ -on('connection', function ($conn) { - $conn->pipe($conn); -}); - -echo "Socket server listening on port 4000.\n"; -echo "You can connect to it by running: telnet localhost 4000\n"; - -$socket->listen(4000); -$loop->run(); +on('connection', function ($conn) { + $conn->pipe($conn); +}); + +echo "Socket server listening on port 4000.\n"; +echo "You can connect to it by running: telnet localhost 4000\n"; + +$socket->listen(4000); +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/http-client.php b/app/libs/vendor/react/react/examples/http-client.php index 1a116233..af8925ae 100644 --- a/app/libs/vendor/react/react/examples/http-client.php +++ b/app/libs/vendor/react/react/examples/http-client.php @@ -1,40 +1,40 @@ -createCached('8.8.8.8', $loop); - -$factory = new React\HttpClient\Factory(); -$client = $factory->create($loop, $dnsResolver); - -$request = $client->request('GET', 'https://api.github.com/repos/reactphp/react/commits'); -$request->on('response', function ($response) { - $buffer = ''; - - $response->on('data', function ($data) use (&$buffer) { - $buffer .= $data; - echo "."; - }); - - $response->on('end', function () use (&$buffer) { - $decoded = json_decode($buffer, true); - $latest = $decoded[0]['commit']; - $author = $latest['author']['name']; - $date = date('F j, Y', strtotime($latest['author']['date'])); - - echo "\n"; - echo "Latest commit on react was done by {$author} on {$date}\n"; - echo "{$latest['message']}\n"; - }); -}); -$request->on('end', function ($error, $response) { - echo $error; -}); -$request->end(); - -$loop->run(); +createCached('8.8.8.8', $loop); + +$factory = new React\HttpClient\Factory(); +$client = $factory->create($loop, $dnsResolver); + +$request = $client->request('GET', 'https://api.github.com/repos/reactphp/react/commits'); +$request->on('response', function ($response) { + $buffer = ''; + + $response->on('data', function ($data) use (&$buffer) { + $buffer .= $data; + echo "."; + }); + + $response->on('end', function () use (&$buffer) { + $decoded = json_decode($buffer, true); + $latest = $decoded[0]['commit']; + $author = $latest['author']['name']; + $date = date('F j, Y', strtotime($latest['author']['date'])); + + echo "\n"; + echo "Latest commit on react was done by {$author} on {$date}\n"; + echo "{$latest['message']}\n"; + }); +}); +$request->on('end', function ($error, $response) { + echo $error; +}); +$request->end(); + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/next-tick.php b/app/libs/vendor/react/react/examples/next-tick.php index 7cfd020f..64b9bcfb 100644 --- a/app/libs/vendor/react/react/examples/next-tick.php +++ b/app/libs/vendor/react/react/examples/next-tick.php @@ -1,58 +1,58 @@ -addTimer( - 0, - function () { - echo 'timer' . PHP_EOL; - } -); - -$loop->nextTick( - function ($loop) { - echo 'next-tick #1' . PHP_EOL; - - $loop->nextTick( - function () { - echo 'next-tick #2' . PHP_EOL; - } - ); - } -); - -$loop->futureTick( - function ($loop) { - echo 'future-tick #1' . PHP_EOL; - - $loop->futureTick( - function () { - echo 'future-tick #2' . PHP_EOL; - } - ); - } -); - -$loop->run(); +addTimer( + 0, + function () { + echo 'timer' . PHP_EOL; + } +); + +$loop->nextTick( + function ($loop) { + echo 'next-tick #1' . PHP_EOL; + + $loop->nextTick( + function () { + echo 'next-tick #2' . PHP_EOL; + } + ); + } +); + +$loop->futureTick( + function ($loop) { + echo 'future-tick #1' . PHP_EOL; + + $loop->futureTick( + function () { + echo 'future-tick #2' . PHP_EOL; + } + ); + } +); + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/parallel-download.php b/app/libs/vendor/react/react/examples/parallel-download.php index 6439fa56..a6de5fe2 100644 --- a/app/libs/vendor/react/react/examples/parallel-download.php +++ b/app/libs/vendor/react/react/examples/parallel-download.php @@ -1,46 +1,46 @@ - 'http://nodejs.org/dist/v0.6.18/node-v0.6.18.tar.gz', - 'php-5.4.3.tar.gz' => 'http://it.php.net/get/php-5.4.3.tar.gz/from/this/mirror', -); - -foreach ($files as $file => $url) { - $readStream = fopen($url, 'r'); - $writeStream = fopen($file, 'w'); - - stream_set_blocking($readStream, 0); - stream_set_blocking($writeStream, 0); - - $read = new React\Stream\Stream($readStream, $loop); - $write = new React\Stream\Stream($writeStream, $loop); - - $read->on('end', function () use ($file, &$files) { - unset($files[$file]); - echo "Finished downloading $file\n"; - }); - - $read->pipe($write); -} - -$loop->addPeriodicTimer(5, function ($timer) use (&$files) { - if (0 === count($files)) { - $timer->cancel(); - } - - foreach ($files as $file => $url) { - $mbytes = filesize($file) / (1024 * 1024); - $formatted = number_format($mbytes, 3); - echo "$file: $formatted MiB\n"; - } -}); - -echo "This script will show the download status every 5 seconds.\n"; - -$loop->run(); + 'http://nodejs.org/dist/v0.6.18/node-v0.6.18.tar.gz', + 'php-5.4.3.tar.gz' => 'http://it.php.net/get/php-5.4.3.tar.gz/from/this/mirror', +); + +foreach ($files as $file => $url) { + $readStream = fopen($url, 'r'); + $writeStream = fopen($file, 'w'); + + stream_set_blocking($readStream, 0); + stream_set_blocking($writeStream, 0); + + $read = new React\Stream\Stream($readStream, $loop); + $write = new React\Stream\Stream($writeStream, $loop); + + $read->on('end', function () use ($file, &$files) { + unset($files[$file]); + echo "Finished downloading $file\n"; + }); + + $read->pipe($write); +} + +$loop->addPeriodicTimer(5, function ($timer) use (&$files) { + if (0 === count($files)) { + $timer->cancel(); + } + + foreach ($files as $file => $url) { + $mbytes = filesize($file) / (1024 * 1024); + $formatted = number_format($mbytes, 3); + echo "$file: $formatted MiB\n"; + } +}); + +echo "This script will show the download status every 5 seconds.\n"; + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/pump-shitload-of-data.php b/app/libs/vendor/react/react/examples/pump-shitload-of-data.php index 540ad772..7efad58e 100644 --- a/app/libs/vendor/react/react/examples/pump-shitload-of-data.php +++ b/app/libs/vendor/react/react/examples/pump-shitload-of-data.php @@ -1,23 +1,23 @@ -on('connection', function ($conn) { - $shitload = str_repeat('a', 1024*1024*32); - $conn->write($shitload); - $conn->end(); -}); - -echo "Socket server listening on port 4000.\n"; -echo "You can connect to it by running: telnet localhost 4000\n"; - -$socket->listen(4000); -$loop->run(); +on('connection', function ($conn) { + $shitload = str_repeat('a', 1024*1024*32); + $conn->write($shitload); + $conn->end(); +}); + +echo "Socket server listening on port 4000.\n"; +echo "You can connect to it by running: telnet localhost 4000\n"; + +$socket->listen(4000); +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/scalability.php b/app/libs/vendor/react/react/examples/scalability.php index bb540dc5..84276118 100644 --- a/app/libs/vendor/react/react/examples/scalability.php +++ b/app/libs/vendor/react/react/examples/scalability.php @@ -1,21 +1,21 @@ -addReadStream($s, function ($s) use ($i) { - $c=stream_socket_accept($s); - $len=strlen($i)+4; - fwrite($c,"HTTP/1.1 200 OK\r\nContent-Length: $len\r\n\r\nHi:$i\n"); - echo "Served on port 800$i\n"; - }); -} - -echo "Access your brand new HTTP server on 127.0.0.1:800x. Replace x with any number from 0-9\n"; - -$loop->run(); +addReadStream($s, function ($s) use ($i) { + $c=stream_socket_accept($s); + $len=strlen($i)+4; + fwrite($c,"HTTP/1.1 200 OK\r\nContent-Length: $len\r\n\r\nHi:$i\n"); + echo "Served on port 800$i\n"; + }); +} + +echo "Access your brand new HTTP server on 127.0.0.1:800x. Replace x with any number from 0-9\n"; + +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/tcp-chat.php b/app/libs/vendor/react/react/examples/tcp-chat.php index f3b31e68..8ed2ffc5 100644 --- a/app/libs/vendor/react/react/examples/tcp-chat.php +++ b/app/libs/vendor/react/react/examples/tcp-chat.php @@ -1,35 +1,35 @@ -on('connection', function ($conn) use ($conns) { - $conns->attach($conn); - - $conn->on('data', function ($data) use ($conns, $conn) { - foreach ($conns as $current) { - if ($conn === $current) { - continue; - } - - $current->write($conn->getRemoteAddress().': '); - $current->write($data); - } - }); - - $conn->on('end', function () use ($conns, $conn) { - $conns->detach($conn); - }); -}); - -echo "Socket server listening on port 4000.\n"; -echo "You can connect to it by running: telnet localhost 4000\n"; - -$socket->listen(4000); -$loop->run(); +on('connection', function ($conn) use ($conns) { + $conns->attach($conn); + + $conn->on('data', function ($data) use ($conns, $conn) { + foreach ($conns as $current) { + if ($conn === $current) { + continue; + } + + $current->write($conn->getRemoteAddress().': '); + $current->write($data); + } + }); + + $conn->on('end', function () use ($conns, $conn) { + $conns->detach($conn); + }); +}); + +echo "Socket server listening on port 4000.\n"; +echo "You can connect to it by running: telnet localhost 4000\n"; + +$socket->listen(4000); +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/test-close-conn.php b/app/libs/vendor/react/react/examples/test-close-conn.php index 739f8b7f..a949aeaa 100644 --- a/app/libs/vendor/react/react/examples/test-close-conn.php +++ b/app/libs/vendor/react/react/examples/test-close-conn.php @@ -1,22 +1,22 @@ -on('connection', function ($conn) use (&$i, $loop) { - $i++; - - $conn->on('end', function () use (&$i) { - $i--; - }); -}); - -$loop->addPeriodicTimer(2, function () use (&$i) { - echo "$i open connections?\n"; -}); - -$socket->listen(8080); -$loop->run(); +on('connection', function ($conn) use (&$i, $loop) { + $i++; + + $conn->on('end', function () use (&$i) { + $i--; + }); +}); + +$loop->addPeriodicTimer(2, function () use (&$i) { + echo "$i open connections?\n"; +}); + +$socket->listen(8080); +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/test-memory-http.php b/app/libs/vendor/react/react/examples/test-memory-http.php index 61bf6180..634dd8bc 100644 --- a/app/libs/vendor/react/react/examples/test-memory-http.php +++ b/app/libs/vendor/react/react/examples/test-memory-http.php @@ -1,28 +1,28 @@ -on('request', function ($request, $response) use (&$i) { - $i++; - $response->writeHead(); - $response->end("Hello World!\n"); -}); - -$loop->addPeriodicTimer(2, function () use (&$i) { - $kmem = memory_get_usage(true) / 1024; - echo "Request: $i\n"; - echo "Memory: $kmem KiB\n"; -}); - -$socket->listen(8080); -$loop->run(); +on('request', function ($request, $response) use (&$i) { + $i++; + $response->writeHead(); + $response->end("Hello World!\n"); +}); + +$loop->addPeriodicTimer(2, function () use (&$i) { + $kmem = memory_get_usage(true) / 1024; + echo "Request: $i\n"; + echo "Memory: $kmem KiB\n"; +}); + +$socket->listen(8080); +$loop->run(); diff --git a/app/libs/vendor/react/react/examples/test-memory.php b/app/libs/vendor/react/react/examples/test-memory.php index 46d5be6a..4e478011 100644 --- a/app/libs/vendor/react/react/examples/test-memory.php +++ b/app/libs/vendor/react/react/examples/test-memory.php @@ -1,26 +1,26 @@ -addPeriodicTimer(0.001, function () use (&$i, $loop) { - $i++; - - // $loop->addTimer(1, function ($timer) { - // }); - - $loop->addPeriodicTimer(1, function ($timer) { - $timer->cancel(); - }); -}); - -$loop->addPeriodicTimer(2, function () use (&$i) { - $kmem = memory_get_usage(true) / 1024; - echo "Run: $i\n"; - echo "Memory: $kmem KiB\n"; -}); - -$loop->run(); +addPeriodicTimer(0.001, function () use (&$i, $loop) { + $i++; + + // $loop->addTimer(1, function ($timer) { + // }); + + $loop->addPeriodicTimer(1, function ($timer) { + $timer->cancel(); + }); +}); + +$loop->addPeriodicTimer(2, function () use (&$i) { + $kmem = memory_get_usage(true) / 1024; + echo "Run: $i\n"; + echo "Memory: $kmem KiB\n"; +}); + +$loop->run(); diff --git a/app/libs/vendor/react/react/phpunit.xml.dist b/app/libs/vendor/react/react/phpunit.xml.dist index b90a30ff..cba6d4dd 100644 --- a/app/libs/vendor/react/react/phpunit.xml.dist +++ b/app/libs/vendor/react/react/phpunit.xml.dist @@ -1,25 +1,25 @@ - - - - - - ./tests/ - - - - - - ./src/ - - - + + + + + + ./tests/ + + + + + + ./src/ + + + diff --git a/app/libs/vendor/react/react/scripts/do-split.sh b/app/libs/vendor/react/react/scripts/do-split.sh index a049e7b3..171c1755 100644 --- a/app/libs/vendor/react/react/scripts/do-split.sh +++ b/app/libs/vendor/react/react/scripts/do-split.sh @@ -1,22 +1,22 @@ -#!/bin/bash -# -# Using git-subsplit -# https://github.com/dflydev/git-subsplit - -GIT_SUBSPLIT=$(pwd)/$(dirname $0)/git-subsplit.sh - -$GIT_SUBSPLIT init https://github.com/reactphp/react - -$GIT_SUBSPLIT update - -$GIT_SUBSPLIT publish " - src/EventLoop:git@github.com:reactphp/event-loop.git - src/Stream:git@github.com:reactphp/stream.git - src/Cache:git@github.com:reactphp/cache.git - src/Socket:git@github.com:reactphp/socket.git - src/SocketClient:git@github.com:reactphp/socket-client.git - src/Http:git@github.com:reactphp/http.git - src/HttpClient:git@github.com:reactphp/http-client.git - src/Dns:git@github.com:reactphp/dns.git - src/ChildProcess:git@github.com/reactphp/child-process.git -" --heads=master +#!/bin/bash +# +# Using git-subsplit +# https://github.com/dflydev/git-subsplit + +GIT_SUBSPLIT=$(pwd)/$(dirname $0)/git-subsplit.sh + +$GIT_SUBSPLIT init https://github.com/reactphp/react + +$GIT_SUBSPLIT update + +$GIT_SUBSPLIT publish " + src/EventLoop:git@github.com:reactphp/event-loop.git + src/Stream:git@github.com:reactphp/stream.git + src/Cache:git@github.com:reactphp/cache.git + src/Socket:git@github.com:reactphp/socket.git + src/SocketClient:git@github.com:reactphp/socket-client.git + src/Http:git@github.com:reactphp/http.git + src/HttpClient:git@github.com:reactphp/http-client.git + src/Dns:git@github.com:reactphp/dns.git + src/ChildProcess:git@github.com/reactphp/child-process.git +" --heads=master diff --git a/app/libs/vendor/react/react/scripts/git-subsplit.sh b/app/libs/vendor/react/react/scripts/git-subsplit.sh index 6c1b7da7..d956c121 100644 --- a/app/libs/vendor/react/react/scripts/git-subsplit.sh +++ b/app/libs/vendor/react/react/scripts/git-subsplit.sh @@ -1,232 +1,232 @@ -#!/bin/bash -# -# git-subsplit.sh: Automate and simplify the process of managing one-way -# read-only subtree splits. -# -# Copyright (C) 2012 Dragonfly Development Inc. -# -if [ $# -eq 0 ]; then - set -- -h -fi -OPTS_SPEC="\ -git subsplit init url -git subsplit publish splits --heads= --tags= --splits= -git subsplit update --- -h,help show the help -q quiet -n,dry-run do everything except actually send the updates -work-dir directory that contains the subsplit working directory - - options for 'publish' -heads= only publish for listed heads instead of all heads -no-heads do not publish any heads -tags= only publish for listed tags instead of all tags -no-tags do not publish any tags -update fetch updates from repository before publishing -rebuild-tags rebuild all tags (as opposed to skipping tags that are already synced) -" -eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" - -# We can run this from anywhere. -NONGIT_OK=1 - -PATH=$PATH:$(git --exec-path) - -. git-sh-setup - -if [ "$(hash git-subtree &>/dev/null && echo OK)" = "" ] -then - die "Git subplit needs git subtree; install git subtree or upgrade git to >=1.7.11" -fi - -ANNOTATE= -QUIET= -COMMAND= -SPLITS= -REPO_URL= -WORK_DIR="${PWD}/.subsplit" -HEADS= -TAGS= -REBUILD_TAGS= -DRY_RUN= - -subsplit_main() -{ - while [ $# -gt 0 ]; do - opt="$1" - shift - case "$opt" in - -q) QUIET=1 ;; - --heads) HEADS="$1"; shift ;; - --no-heads) NO_HEADS=1 ;; - --tags) TAGS="$1"; shift ;; - --no-tags) NO_TAGS=1 ;; - --update) UPDATE=1 ;; - -n) DRY_RUN="--dry-run" ;; - --dry-run) DRY_RUN="--dry-run" ;; - --rebuild-tags) REBUILD_TAGS=1 ;; - --) break ;; - *) die "Unexpected option: $opt" ;; - esac - done - - COMMAND="$1" - shift - - case "$COMMAND" in - init) - if [ $# -lt 1 ]; then die "init command requires url to be passed as first argument"; fi - REPO_URL="$1" - shift - subsplit_init - ;; - publish) - if [ $# -lt 1 ]; then die "publish command requires splits to be passed as first argument"; fi - SPLITS="$1" - shift - subsplit_publish - ;; - update) - subsplit_update - ;; - *) die "Unknown command '$COMMAND'" ;; - esac -} -say() -{ - if [ -z "$QUIET" ]; then - echo "$@" >&2 - fi -} - -subsplit_require_work_dir() -{ - if [ ! -e "$WORK_DIR" ] - then - die "Working directory not found at ${WORK_DIR}; please run init first" - fi - - pushd "$WORK_DIR" >/dev/null -} - -subsplit_init() -{ - if [ -e "$WORK_DIR" ] - then - die "Working directory already found at ${WORK_DIR}; please remove or run update" - fi - - say "Initializing subsplit from origin (${REPO_URL})" - - git clone -q "$REPO_URL" "$WORK_DIR" || die "Could not clone repository" -} - -subsplit_publish() -{ - subsplit_require_work_dir - - if [ -n "$UPDATE" ]; - then - subsplit_update - fi - - if [ -z "$HEADS" ] && [ -z "$NO_HEADS" ] - then - # If heads are not specified and we want heads, discover them. - HEADS="$(git ls-remote origin 2>/dev/null | grep "refs/heads/" | cut -f3- -d/)" - fi - - if [ -z "$TAGS" ] && [ -z "$NO_TAGS" ] - then - # If tags are not specified and we want tags, discover them. - TAGS="$(git ls-remote origin 2>/dev/null | grep -v "\^{}" | grep "refs/tags/" | cut -f3 -d/)" - fi - - for SPLIT in $SPLITS - do - SUBPATH=$(echo "$SPLIT" | cut -f1 -d:) - REMOTE_URL=$(echo "$SPLIT" | cut -f2- -d:) - REMOTE_NAME=$(echo "$SPLIT" | git hash-object --stdin) - - if ! git remote | grep "^${REMOTE_NAME}$" >/dev/null - then - git remote add "$REMOTE_NAME" "$REMOTE_URL" - fi - - - say "Syncing ${SUBPATH} -> ${REMOTE_URL}" - - for HEAD in $HEADS - do - if ! git show-ref --quiet --verify -- "refs/remotes/origin/${HEAD}" - then - say " - skipping head '${HEAD}' (does not exist)" - continue - fi - LOCAL_BRANCH="${REMOTE_NAME}-branch-${HEAD}" - say " - syncing branch '${HEAD}'" - git branch -D "$LOCAL_BRANCH" >/dev/null 2>&1 - git subtree split -q --prefix="$SUBPATH" --branch="$LOCAL_BRANCH" "origin/${HEAD}" >/dev/null - if [ $? -eq 0 ] - then - PUSH_CMD="git push -q ${DRY_RUN} --force $REMOTE_NAME ${LOCAL_BRANCH}:${HEAD}" - if [ -n "$DRY_RUN" ] - then - echo \# $PUSH_CMD - $PUSH_CMD - else - $PUSH_CMD - fi - fi - done - - for TAG in $TAGS - do - if ! git show-ref --quiet --verify -- "refs/tags/${TAG}" - then - say " - skipping tag '${TAG}' (does not exist)" - continue - fi - LOCAL_TAG="${REMOTE_NAME}-tag-${TAG}" - if git branch | grep "${LOCAL_TAG}$" >/dev/null && [ -z "$REBUILD_TAGS" ] - then - say " - skpping tag '${TAG}' (already synced)" - continue - fi - say " - syncing tag '${TAG}'" - say " - deleting '${LOCAL_TAG}'" - git branch -D "$LOCAL_TAG" >/dev/null 2>&1 - say " - subtree split for '${TAG}'" - git subtree split -q --annotate="${ANNOTATE}" --prefix="$SUBPATH" --branch="$LOCAL_TAG" "$TAG" >/dev/null - say " - subtree split for '${TAG}' [DONE]" - if [ $? -eq 0 ] - then - PUSH_CMD="git push -q ${DRY_RUN} --force ${REMOTE_NAME} ${LOCAL_TAG}:refs/tags/${TAG}" - if [ -n "$DRY_RUN" ] - then - echo \# $PUSH_CMD - $PUSH_CMD - else - $PUSH_CMD - fi - fi - done - done - - popd >/dev/null -} - -subsplit_update() -{ - subsplit_require_work_dir - - say "Updating subsplit from origin" - - git fetch -q origin - git fetch -q -t origin - - popd >/dev/null -} - -subsplit_main "$@" +#!/bin/bash +# +# git-subsplit.sh: Automate and simplify the process of managing one-way +# read-only subtree splits. +# +# Copyright (C) 2012 Dragonfly Development Inc. +# +if [ $# -eq 0 ]; then + set -- -h +fi +OPTS_SPEC="\ +git subsplit init url +git subsplit publish splits --heads= --tags= --splits= +git subsplit update +-- +h,help show the help +q quiet +n,dry-run do everything except actually send the updates +work-dir directory that contains the subsplit working directory + + options for 'publish' +heads= only publish for listed heads instead of all heads +no-heads do not publish any heads +tags= only publish for listed tags instead of all tags +no-tags do not publish any tags +update fetch updates from repository before publishing +rebuild-tags rebuild all tags (as opposed to skipping tags that are already synced) +" +eval "$(echo "$OPTS_SPEC" | git rev-parse --parseopt -- "$@" || echo exit $?)" + +# We can run this from anywhere. +NONGIT_OK=1 + +PATH=$PATH:$(git --exec-path) + +. git-sh-setup + +if [ "$(hash git-subtree &>/dev/null && echo OK)" = "" ] +then + die "Git subplit needs git subtree; install git subtree or upgrade git to >=1.7.11" +fi + +ANNOTATE= +QUIET= +COMMAND= +SPLITS= +REPO_URL= +WORK_DIR="${PWD}/.subsplit" +HEADS= +TAGS= +REBUILD_TAGS= +DRY_RUN= + +subsplit_main() +{ + while [ $# -gt 0 ]; do + opt="$1" + shift + case "$opt" in + -q) QUIET=1 ;; + --heads) HEADS="$1"; shift ;; + --no-heads) NO_HEADS=1 ;; + --tags) TAGS="$1"; shift ;; + --no-tags) NO_TAGS=1 ;; + --update) UPDATE=1 ;; + -n) DRY_RUN="--dry-run" ;; + --dry-run) DRY_RUN="--dry-run" ;; + --rebuild-tags) REBUILD_TAGS=1 ;; + --) break ;; + *) die "Unexpected option: $opt" ;; + esac + done + + COMMAND="$1" + shift + + case "$COMMAND" in + init) + if [ $# -lt 1 ]; then die "init command requires url to be passed as first argument"; fi + REPO_URL="$1" + shift + subsplit_init + ;; + publish) + if [ $# -lt 1 ]; then die "publish command requires splits to be passed as first argument"; fi + SPLITS="$1" + shift + subsplit_publish + ;; + update) + subsplit_update + ;; + *) die "Unknown command '$COMMAND'" ;; + esac +} +say() +{ + if [ -z "$QUIET" ]; then + echo "$@" >&2 + fi +} + +subsplit_require_work_dir() +{ + if [ ! -e "$WORK_DIR" ] + then + die "Working directory not found at ${WORK_DIR}; please run init first" + fi + + pushd "$WORK_DIR" >/dev/null +} + +subsplit_init() +{ + if [ -e "$WORK_DIR" ] + then + die "Working directory already found at ${WORK_DIR}; please remove or run update" + fi + + say "Initializing subsplit from origin (${REPO_URL})" + + git clone -q "$REPO_URL" "$WORK_DIR" || die "Could not clone repository" +} + +subsplit_publish() +{ + subsplit_require_work_dir + + if [ -n "$UPDATE" ]; + then + subsplit_update + fi + + if [ -z "$HEADS" ] && [ -z "$NO_HEADS" ] + then + # If heads are not specified and we want heads, discover them. + HEADS="$(git ls-remote origin 2>/dev/null | grep "refs/heads/" | cut -f3- -d/)" + fi + + if [ -z "$TAGS" ] && [ -z "$NO_TAGS" ] + then + # If tags are not specified and we want tags, discover them. + TAGS="$(git ls-remote origin 2>/dev/null | grep -v "\^{}" | grep "refs/tags/" | cut -f3 -d/)" + fi + + for SPLIT in $SPLITS + do + SUBPATH=$(echo "$SPLIT" | cut -f1 -d:) + REMOTE_URL=$(echo "$SPLIT" | cut -f2- -d:) + REMOTE_NAME=$(echo "$SPLIT" | git hash-object --stdin) + + if ! git remote | grep "^${REMOTE_NAME}$" >/dev/null + then + git remote add "$REMOTE_NAME" "$REMOTE_URL" + fi + + + say "Syncing ${SUBPATH} -> ${REMOTE_URL}" + + for HEAD in $HEADS + do + if ! git show-ref --quiet --verify -- "refs/remotes/origin/${HEAD}" + then + say " - skipping head '${HEAD}' (does not exist)" + continue + fi + LOCAL_BRANCH="${REMOTE_NAME}-branch-${HEAD}" + say " - syncing branch '${HEAD}'" + git branch -D "$LOCAL_BRANCH" >/dev/null 2>&1 + git subtree split -q --prefix="$SUBPATH" --branch="$LOCAL_BRANCH" "origin/${HEAD}" >/dev/null + if [ $? -eq 0 ] + then + PUSH_CMD="git push -q ${DRY_RUN} --force $REMOTE_NAME ${LOCAL_BRANCH}:${HEAD}" + if [ -n "$DRY_RUN" ] + then + echo \# $PUSH_CMD + $PUSH_CMD + else + $PUSH_CMD + fi + fi + done + + for TAG in $TAGS + do + if ! git show-ref --quiet --verify -- "refs/tags/${TAG}" + then + say " - skipping tag '${TAG}' (does not exist)" + continue + fi + LOCAL_TAG="${REMOTE_NAME}-tag-${TAG}" + if git branch | grep "${LOCAL_TAG}$" >/dev/null && [ -z "$REBUILD_TAGS" ] + then + say " - skpping tag '${TAG}' (already synced)" + continue + fi + say " - syncing tag '${TAG}'" + say " - deleting '${LOCAL_TAG}'" + git branch -D "$LOCAL_TAG" >/dev/null 2>&1 + say " - subtree split for '${TAG}'" + git subtree split -q --annotate="${ANNOTATE}" --prefix="$SUBPATH" --branch="$LOCAL_TAG" "$TAG" >/dev/null + say " - subtree split for '${TAG}' [DONE]" + if [ $? -eq 0 ] + then + PUSH_CMD="git push -q ${DRY_RUN} --force ${REMOTE_NAME} ${LOCAL_TAG}:refs/tags/${TAG}" + if [ -n "$DRY_RUN" ] + then + echo \# $PUSH_CMD + $PUSH_CMD + else + $PUSH_CMD + fi + fi + done + done + + popd >/dev/null +} + +subsplit_update() +{ + subsplit_require_work_dir + + say "Updating subsplit from origin" + + git fetch -q origin + git fetch -q -t origin + + popd >/dev/null +} + +subsplit_main "$@" diff --git a/app/libs/vendor/react/react/scripts/travis-init.sh b/app/libs/vendor/react/react/scripts/travis-init.sh index f1a7cf7e..6360e58f 100644 --- a/app/libs/vendor/react/react/scripts/travis-init.sh +++ b/app/libs/vendor/react/react/scripts/travis-init.sh @@ -1,36 +1,36 @@ -#!/bin/bash -set -e -set -o pipefail - -if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then - - # install "libevent" (used by 'event' and 'libevent' PHP extensions) - sudo apt-get install -y libevent-dev - - # install 'event' PHP extension - echo "yes" | pecl install event - - # install 'libevent' PHP extension - curl http://pecl.php.net/get/libevent-0.0.5.tgz | tar -xz - pushd libevent-0.0.5 - phpize - ./configure - make - make install - popd - echo "extension=libevent.so" >> "$(php -r 'echo php_ini_loaded_file();')" - - # install 'libev' PHP extension - git clone --recursive https://github.com/m4rw3r/php-libev - pushd php-libev - phpize - ./configure --with-libev - make - make install - popd - echo "extension=libev.so" >> "$(php -r 'echo php_ini_loaded_file();')" - -fi - -composer self-update -composer install --dev --prefer-source +#!/bin/bash +set -e +set -o pipefail + +if [ "$TRAVIS_PHP_VERSION" != "hhvm" ]; then + + # install "libevent" (used by 'event' and 'libevent' PHP extensions) + sudo apt-get install -y libevent-dev + + # install 'event' PHP extension + echo "yes" | pecl install event + + # install 'libevent' PHP extension + curl http://pecl.php.net/get/libevent-0.0.5.tgz | tar -xz + pushd libevent-0.0.5 + phpize + ./configure + make + make install + popd + echo "extension=libevent.so" >> "$(php -r 'echo php_ini_loaded_file();')" + + # install 'libev' PHP extension + git clone --recursive https://github.com/m4rw3r/php-libev + pushd php-libev + phpize + ./configure --with-libev + make + make install + popd + echo "extension=libev.so" >> "$(php -r 'echo php_ini_loaded_file();')" + +fi + +composer self-update +composer install --dev --prefer-source diff --git a/app/libs/vendor/react/react/src/Cache/ArrayCache.php b/app/libs/vendor/react/react/src/Cache/ArrayCache.php index 575191d9..03dcc158 100644 --- a/app/libs/vendor/react/react/src/Cache/ArrayCache.php +++ b/app/libs/vendor/react/react/src/Cache/ArrayCache.php @@ -1,29 +1,29 @@ -data[$key])) { - return Promise\reject(); - } - - return Promise\resolve($this->data[$key]); - } - - public function set($key, $value) - { - $this->data[$key] = $value; - } - - public function remove($key) - { - unset($this->data[$key]); - } -} +data[$key])) { + return Promise\reject(); + } + + return Promise\resolve($this->data[$key]); + } + + public function set($key, $value) + { + $this->data[$key] = $value; + } + + public function remove($key) + { + unset($this->data[$key]); + } +} diff --git a/app/libs/vendor/react/react/src/Cache/CacheInterface.php b/app/libs/vendor/react/react/src/Cache/CacheInterface.php index 6dd2401a..fd5f2d54 100644 --- a/app/libs/vendor/react/react/src/Cache/CacheInterface.php +++ b/app/libs/vendor/react/react/src/Cache/CacheInterface.php @@ -1,13 +1,13 @@ -get('foo') - ->then('var_dump'); - -This example fetches the value of the key `foo` and passes it to the -`var_dump` function. You can use any of the composition provided by -[promises](https://github.com/reactphp/promise). - -If the key `foo` does not exist, the promise will be rejected. - -### set - - $cache->set('foo', 'bar'); - -This example eventually sets the value of the key `foo` to `bar`. If it -already exists, it is overridden. No guarantees are made as to when the cache -value is set. If the cache implementation has to go over the network to store -it, it may take a while. - -### remove - - $cache->remove('foo'); - -This example eventually removes the key `foo` from the cache. As with `set`, -this may not happen instantly. - -## Common usage - -### Fallback get - -A common use case of caches is to attempt fetching a cached value and as a -fallback retrieve it from the original data source if not found. Here is an -example of that: - - $cache - ->get('foo') - ->then(null, 'getFooFromDb') - ->then('var_dump'); - -First an attempt is made to retrieve the value of `foo`. A promise rejection -handler of the function `getFooFromDb` is registered. `getFooFromDb` is a -function (can be any PHP callable) that will be called if the key does not -exist in the cache. - -`getFooFromDb` can handle the missing key by returning a promise for the -actual value from the database (or any other data source). As a result, this -chain will correctly fall back, and provide the value in both cases. - -### Fallback get and set - -To expand on the fallback get example, often you want to set the value on the -cache after fetching it from the data source. - - $cache - ->get('foo') - ->then(null, array($this, 'getAndCacheFooFromDb')) - ->then('var_dump'); - - public function getAndCacheFooFromDb() - { - return $this->db - ->get('foo') - ->then(array($this, 'cacheFooFromDb')); - } - - public function cacheFooFromDb($foo) - { - $this->cache->set('foo', $foo); - - return $foo; - } - -By using chaining you can easily conditionally cache the value if it is -fetched from the database. +# Cache Component + +Promised cache interface. + +The cache component provides a promise-based cache interface and an in-memory +`ArrayCache` implementation of that. This allows consumers to type hint +against the interface and third parties to provide alternate implementations. + +## Basic usage + +### get + + $cache + ->get('foo') + ->then('var_dump'); + +This example fetches the value of the key `foo` and passes it to the +`var_dump` function. You can use any of the composition provided by +[promises](https://github.com/reactphp/promise). + +If the key `foo` does not exist, the promise will be rejected. + +### set + + $cache->set('foo', 'bar'); + +This example eventually sets the value of the key `foo` to `bar`. If it +already exists, it is overridden. No guarantees are made as to when the cache +value is set. If the cache implementation has to go over the network to store +it, it may take a while. + +### remove + + $cache->remove('foo'); + +This example eventually removes the key `foo` from the cache. As with `set`, +this may not happen instantly. + +## Common usage + +### Fallback get + +A common use case of caches is to attempt fetching a cached value and as a +fallback retrieve it from the original data source if not found. Here is an +example of that: + + $cache + ->get('foo') + ->then(null, 'getFooFromDb') + ->then('var_dump'); + +First an attempt is made to retrieve the value of `foo`. A promise rejection +handler of the function `getFooFromDb` is registered. `getFooFromDb` is a +function (can be any PHP callable) that will be called if the key does not +exist in the cache. + +`getFooFromDb` can handle the missing key by returning a promise for the +actual value from the database (or any other data source). As a result, this +chain will correctly fall back, and provide the value in both cases. + +### Fallback get and set + +To expand on the fallback get example, often you want to set the value on the +cache after fetching it from the data source. + + $cache + ->get('foo') + ->then(null, array($this, 'getAndCacheFooFromDb')) + ->then('var_dump'); + + public function getAndCacheFooFromDb() + { + return $this->db + ->get('foo') + ->then(array($this, 'cacheFooFromDb')); + } + + public function cacheFooFromDb($foo) + { + $this->cache->set('foo', $foo); + + return $foo; + } + +By using chaining you can easily conditionally cache the value if it is +fetched from the database. diff --git a/app/libs/vendor/react/react/src/Cache/composer.json b/app/libs/vendor/react/react/src/Cache/composer.json index 062ef9e2..5446a08e 100644 --- a/app/libs/vendor/react/react/src/Cache/composer.json +++ b/app/libs/vendor/react/react/src/Cache/composer.json @@ -1,18 +1,18 @@ -{ - "name": "react/cache", - "description": "Async caching.", - "keywords": ["cache"], - "license": "MIT", - "require": { - "php": ">=5.4.0", - "react/promise": "~2.0" - }, - "autoload": { - "psr-4": { "React\\Cache\\": "" } - }, - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - } -} +{ + "name": "react/cache", + "description": "Async caching.", + "keywords": ["cache"], + "license": "MIT", + "require": { + "php": ">=5.4.0", + "react/promise": "~2.0" + }, + "autoload": { + "psr-4": { "React\\Cache\\": "" } + }, + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + } +} diff --git a/app/libs/vendor/react/react/src/ChildProcess/Process.php b/app/libs/vendor/react/react/src/ChildProcess/Process.php index 1c7d31f2..b6cb8d9d 100644 --- a/app/libs/vendor/react/react/src/ChildProcess/Process.php +++ b/app/libs/vendor/react/react/src/ChildProcess/Process.php @@ -1,428 +1,428 @@ -cmd = $cmd; - $this->cwd = $cwd; - - if (null !== $env) { - $this->env = array(); - foreach ($env as $key => $value) { - $this->env[(binary) $key] = (binary) $value; - } - } - - $this->options = $options; - $this->enhanceSigchildCompatibility = $this->isSigchildEnabled(); - } - - /** - * Start the process. - * - * After the process is started, the standard IO streams will be constructed - * and available via public properties. STDIN will be paused upon creation. - * - * @param LoopInterface $loop Loop interface for stream construction - * @param float $interval Interval to periodically monitor process state (seconds) - * @throws RuntimeException If the process is already running or fails to start - */ - public function start(LoopInterface $loop, $interval = 0.1) - { - if ($this->isRunning()) { - throw new \RuntimeException('Process is already running'); - } - - $cmd = $this->cmd; - $fdSpec = array( - array('pipe', 'r'), // stdin - array('pipe', 'w'), // stdout - array('pipe', 'w'), // stderr - ); - - // Read exit code through fourth pipe to work around --enable-sigchild - if ($this->isSigchildEnabled() && $this->enhanceSigchildCompatibility) { - $fdSpec[] = array('pipe', 'w'); - $cmd = sprintf('(%s) 3>/dev/null; code=$?; echo $code >&3; exit $code', $cmd); - } - - $this->process = proc_open($cmd, $fdSpec, $this->pipes, $this->cwd, $this->env, $this->options); - - if (!is_resource($this->process)) { - throw new \RuntimeException('Unable to launch a new process.'); - } - - $this->stdin = new Stream($this->pipes[0], $loop); - $this->stdin->pause(); - $this->stdout = new Stream($this->pipes[1], $loop); - $this->stderr = new Stream($this->pipes[2], $loop); - - foreach ($this->pipes as $pipe) { - stream_set_blocking($pipe, 0); - } - - $loop->addPeriodicTimer($interval, function (Timer $timer) { - if (!$this->isRunning()) { - $this->close(); - $timer->cancel(); - $this->emit('exit', array($this->getExitCode(), $this->getTermSignal())); - } - }); - } - - /** - * Close the process. - * - * This method should only be invoked via the periodic timer that monitors - * the process state. - */ - public function close() - { - if ($this->process === null) { - return; - } - - $this->stdin->close(); - $this->stdout->close(); - $this->stderr->close(); - - if ($this->isSigchildEnabled() && $this->enhanceSigchildCompatibility) { - $this->pollExitCodePipe(); - $this->closeExitCodePipe(); - } - - $exitCode = proc_close($this->process); - $this->process = null; - - if ($this->exitCode === null && $exitCode !== -1) { - $this->exitCode = $exitCode; - } - - if ($this->exitCode === null && $this->status['exitcode'] !== -1) { - $this->exitCode = $this->status['exitcode']; - } - - if ($this->exitCode === null && $this->fallbackExitCode !== null) { - $this->exitCode = $this->fallbackExitCode; - $this->fallbackExitCode = null; - } - } - - /** - * Terminate the process with an optional signal. - * - * @param int $signal Optional signal (default: SIGTERM) - * @return boolean Whether the signal was sent successfully - */ - public function terminate($signal = null) - { - if ($signal !== null) { - return proc_terminate($this->process, $signal); - } - - return proc_terminate($this->process); - } - - /** - * Get the command string used to launch the process. - * - * @return string - */ - public function getCommand() - { - return $this->cmd; - } - - /** - * Return whether sigchild compatibility is enabled. - * - * @return boolean - */ - public final function getEnhanceSigchildCompatibility() - { - return $this->enhanceSigchildCompatibility; - } - - /** - * Enable or disable sigchild compatibility mode. - * - * Sigchild compatibility mode is required to get the exit code and - * determine the success of a process when PHP has been compiled with - * the --enable-sigchild option. - * - * @param boolean $enhance - * @return self - * @throws RuntimeException If the process is already running - */ - public final function setEnhanceSigchildCompatibility($enhance) - { - if ($this->isRunning()) { - throw new \RuntimeException('Process is already running'); - } - - $this->enhanceSigchildCompatibility = (bool) $enhance; - - return $this; - } - - /** - * Get the exit code returned by the process. - * - * This value is only meaningful if isRunning() has returned false. Null - * will be returned if the process is still running. - * - * Null may also be returned if the process has terminated, but the exit - * code could not be determined (e.g. sigchild compatibility was disabled). - * - * @return int|null - */ - public function getExitCode() - { - return $this->exitCode; - } - - /** - * Get the process ID. - * - * @return int|null - */ - public function getPid() - { - $status = $this->getCachedStatus(); - - return $status !== null ? $status['pid'] : null; - } - - /** - * Get the signal that caused the process to stop its execution. - * - * This value is only meaningful if isStopped() has returned true. Null will - * be returned if the process was never stopped. - * - * @return int|null - */ - public function getStopSignal() - { - return $this->stopSignal; - } - - /** - * Get the signal that caused the process to terminate its execution. - * - * This value is only meaningful if isTerminated() has returned true. Null - * will be returned if the process was never terminated. - * - * @return int|null - */ - public function getTermSignal() - { - return $this->termSignal; - } - - /** - * Return whether the process is still running. - * - * @return boolean - */ - public function isRunning() - { - if ($this->process === null) { - return false; - } - - $status = $this->getFreshStatus(); - - return $status !== null ? $status['running'] : false; - } - - /** - * Return whether the process has been stopped by a signal. - * - * @return boolean - */ - public function isStopped() - { - $status = $this->getFreshStatus(); - - return $status !== null ? $status['stopped'] : false; - } - - /** - * Return whether the process has been terminated by an uncaught signal. - * - * @return boolean - */ - public function isTerminated() - { - $status = $this->getFreshStatus(); - - return $status !== null ? $status['signaled'] : false; - } - - /** - * Return whether PHP has been compiled with the '--enable-sigchild' option. - * - * @see \Symfony\Component\Process\Process::isSigchildEnabled() - * @return bool - */ - public final static function isSigchildEnabled() - { - if (null !== self::$sigchild) { - return self::$sigchild; - } - - ob_start(); - phpinfo(INFO_GENERAL); - - return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); - } - - /** - * Check the fourth pipe for an exit code. - * - * This should only be used if --enable-sigchild compatibility was enabled. - */ - private function pollExitCodePipe() - { - if ( ! isset($this->pipes[3])) { - return; - } - - $r = array($this->pipes[3]); - $w = $e = null; - - $n = @stream_select($r, $w, $e, 0); - - if (1 !== $n) { - return; - } - - $data = fread($r[0], 8192); - - if (strlen($data) > 0) { - $this->fallbackExitCode = (int) $data; - } - } - - /** - * Close the fourth pipe used to relay an exit code. - * - * This should only be used if --enable-sigchild compatibility was enabled. - */ - private function closeExitCodePipe() - { - if ( ! isset($this->pipes[3])) { - return; - } - - fclose($this->pipes[3]); - unset($this->pipes[3]); - } - - /** - * Return the cached process status. - * - * @return array - */ - private function getCachedStatus() - { - if ($this->status === null) { - $this->updateStatus(); - } - - return $this->status; - } - - /** - * Return the updated process status. - * - * @return array - */ - private function getFreshStatus() - { - $this->updateStatus(); - - return $this->status; - } - - /** - * Update the process status, stop/term signals, and exit code. - * - * Stop/term signals are only updated if the process is currently stopped or - * signaled, respectively. Otherwise, signal values will remain as-is so the - * corresponding getter methods may be used at a later point in time. - */ - private function updateStatus() - { - if ($this->process === null) { - return; - } - - $this->status = proc_get_status($this->process); - - if ($this->status === false) { - throw new \UnexpectedValueException('proc_get_status() failed'); - } - - if ($this->status['stopped']) { - $this->stopSignal = $this->status['stopsig']; - } - - if ($this->status['signaled']) { - $this->termSignal = $this->status['termsig']; - } - - if (!$this->status['running'] && -1 !== $this->status['exitcode']) { - $this->exitCode = $this->status['exitcode']; - } - } -} +cmd = $cmd; + $this->cwd = $cwd; + + if (null !== $env) { + $this->env = array(); + foreach ($env as $key => $value) { + $this->env[(binary) $key] = (binary) $value; + } + } + + $this->options = $options; + $this->enhanceSigchildCompatibility = $this->isSigchildEnabled(); + } + + /** + * Start the process. + * + * After the process is started, the standard IO streams will be constructed + * and available via public properties. STDIN will be paused upon creation. + * + * @param LoopInterface $loop Loop interface for stream construction + * @param float $interval Interval to periodically monitor process state (seconds) + * @throws RuntimeException If the process is already running or fails to start + */ + public function start(LoopInterface $loop, $interval = 0.1) + { + if ($this->isRunning()) { + throw new \RuntimeException('Process is already running'); + } + + $cmd = $this->cmd; + $fdSpec = array( + array('pipe', 'r'), // stdin + array('pipe', 'w'), // stdout + array('pipe', 'w'), // stderr + ); + + // Read exit code through fourth pipe to work around --enable-sigchild + if ($this->isSigchildEnabled() && $this->enhanceSigchildCompatibility) { + $fdSpec[] = array('pipe', 'w'); + $cmd = sprintf('(%s) 3>/dev/null; code=$?; echo $code >&3; exit $code', $cmd); + } + + $this->process = proc_open($cmd, $fdSpec, $this->pipes, $this->cwd, $this->env, $this->options); + + if (!is_resource($this->process)) { + throw new \RuntimeException('Unable to launch a new process.'); + } + + $this->stdin = new Stream($this->pipes[0], $loop); + $this->stdin->pause(); + $this->stdout = new Stream($this->pipes[1], $loop); + $this->stderr = new Stream($this->pipes[2], $loop); + + foreach ($this->pipes as $pipe) { + stream_set_blocking($pipe, 0); + } + + $loop->addPeriodicTimer($interval, function (Timer $timer) { + if (!$this->isRunning()) { + $this->close(); + $timer->cancel(); + $this->emit('exit', array($this->getExitCode(), $this->getTermSignal())); + } + }); + } + + /** + * Close the process. + * + * This method should only be invoked via the periodic timer that monitors + * the process state. + */ + public function close() + { + if ($this->process === null) { + return; + } + + $this->stdin->close(); + $this->stdout->close(); + $this->stderr->close(); + + if ($this->isSigchildEnabled() && $this->enhanceSigchildCompatibility) { + $this->pollExitCodePipe(); + $this->closeExitCodePipe(); + } + + $exitCode = proc_close($this->process); + $this->process = null; + + if ($this->exitCode === null && $exitCode !== -1) { + $this->exitCode = $exitCode; + } + + if ($this->exitCode === null && $this->status['exitcode'] !== -1) { + $this->exitCode = $this->status['exitcode']; + } + + if ($this->exitCode === null && $this->fallbackExitCode !== null) { + $this->exitCode = $this->fallbackExitCode; + $this->fallbackExitCode = null; + } + } + + /** + * Terminate the process with an optional signal. + * + * @param int $signal Optional signal (default: SIGTERM) + * @return boolean Whether the signal was sent successfully + */ + public function terminate($signal = null) + { + if ($signal !== null) { + return proc_terminate($this->process, $signal); + } + + return proc_terminate($this->process); + } + + /** + * Get the command string used to launch the process. + * + * @return string + */ + public function getCommand() + { + return $this->cmd; + } + + /** + * Return whether sigchild compatibility is enabled. + * + * @return boolean + */ + public final function getEnhanceSigchildCompatibility() + { + return $this->enhanceSigchildCompatibility; + } + + /** + * Enable or disable sigchild compatibility mode. + * + * Sigchild compatibility mode is required to get the exit code and + * determine the success of a process when PHP has been compiled with + * the --enable-sigchild option. + * + * @param boolean $enhance + * @return self + * @throws RuntimeException If the process is already running + */ + public final function setEnhanceSigchildCompatibility($enhance) + { + if ($this->isRunning()) { + throw new \RuntimeException('Process is already running'); + } + + $this->enhanceSigchildCompatibility = (bool) $enhance; + + return $this; + } + + /** + * Get the exit code returned by the process. + * + * This value is only meaningful if isRunning() has returned false. Null + * will be returned if the process is still running. + * + * Null may also be returned if the process has terminated, but the exit + * code could not be determined (e.g. sigchild compatibility was disabled). + * + * @return int|null + */ + public function getExitCode() + { + return $this->exitCode; + } + + /** + * Get the process ID. + * + * @return int|null + */ + public function getPid() + { + $status = $this->getCachedStatus(); + + return $status !== null ? $status['pid'] : null; + } + + /** + * Get the signal that caused the process to stop its execution. + * + * This value is only meaningful if isStopped() has returned true. Null will + * be returned if the process was never stopped. + * + * @return int|null + */ + public function getStopSignal() + { + return $this->stopSignal; + } + + /** + * Get the signal that caused the process to terminate its execution. + * + * This value is only meaningful if isTerminated() has returned true. Null + * will be returned if the process was never terminated. + * + * @return int|null + */ + public function getTermSignal() + { + return $this->termSignal; + } + + /** + * Return whether the process is still running. + * + * @return boolean + */ + public function isRunning() + { + if ($this->process === null) { + return false; + } + + $status = $this->getFreshStatus(); + + return $status !== null ? $status['running'] : false; + } + + /** + * Return whether the process has been stopped by a signal. + * + * @return boolean + */ + public function isStopped() + { + $status = $this->getFreshStatus(); + + return $status !== null ? $status['stopped'] : false; + } + + /** + * Return whether the process has been terminated by an uncaught signal. + * + * @return boolean + */ + public function isTerminated() + { + $status = $this->getFreshStatus(); + + return $status !== null ? $status['signaled'] : false; + } + + /** + * Return whether PHP has been compiled with the '--enable-sigchild' option. + * + * @see \Symfony\Component\Process\Process::isSigchildEnabled() + * @return bool + */ + public final static function isSigchildEnabled() + { + if (null !== self::$sigchild) { + return self::$sigchild; + } + + ob_start(); + phpinfo(INFO_GENERAL); + + return self::$sigchild = false !== strpos(ob_get_clean(), '--enable-sigchild'); + } + + /** + * Check the fourth pipe for an exit code. + * + * This should only be used if --enable-sigchild compatibility was enabled. + */ + private function pollExitCodePipe() + { + if ( ! isset($this->pipes[3])) { + return; + } + + $r = array($this->pipes[3]); + $w = $e = null; + + $n = @stream_select($r, $w, $e, 0); + + if (1 !== $n) { + return; + } + + $data = fread($r[0], 8192); + + if (strlen($data) > 0) { + $this->fallbackExitCode = (int) $data; + } + } + + /** + * Close the fourth pipe used to relay an exit code. + * + * This should only be used if --enable-sigchild compatibility was enabled. + */ + private function closeExitCodePipe() + { + if ( ! isset($this->pipes[3])) { + return; + } + + fclose($this->pipes[3]); + unset($this->pipes[3]); + } + + /** + * Return the cached process status. + * + * @return array + */ + private function getCachedStatus() + { + if ($this->status === null) { + $this->updateStatus(); + } + + return $this->status; + } + + /** + * Return the updated process status. + * + * @return array + */ + private function getFreshStatus() + { + $this->updateStatus(); + + return $this->status; + } + + /** + * Update the process status, stop/term signals, and exit code. + * + * Stop/term signals are only updated if the process is currently stopped or + * signaled, respectively. Otherwise, signal values will remain as-is so the + * corresponding getter methods may be used at a later point in time. + */ + private function updateStatus() + { + if ($this->process === null) { + return; + } + + $this->status = proc_get_status($this->process); + + if ($this->status === false) { + throw new \UnexpectedValueException('proc_get_status() failed'); + } + + if ($this->status['stopped']) { + $this->stopSignal = $this->status['stopsig']; + } + + if ($this->status['signaled']) { + $this->termSignal = $this->status['termsig']; + } + + if (!$this->status['running'] && -1 !== $this->status['exitcode']) { + $this->exitCode = $this->status['exitcode']; + } + } +} diff --git a/app/libs/vendor/react/react/src/ChildProcess/README.md b/app/libs/vendor/react/react/src/ChildProcess/README.md index f17898c3..cad86416 100644 --- a/app/libs/vendor/react/react/src/ChildProcess/README.md +++ b/app/libs/vendor/react/react/src/ChildProcess/README.md @@ -1,93 +1,93 @@ -# Child Process Component - -Library for executing child processes. - -## Introduction - -This library integrates the -[Program Execution](http://php.net/manual/en/book.exec.php) extension in PHP -with React's event loop. - -Child processes launched within the event loop may be signaled and will emit an -`exit` event upon termination. Additionally, process I/O streams (i.e. stdin, -stdout, stderr) are registered with the loop. - -## Processes - -### EventEmitter Events - -* `exit`: Emitted whenever the process is no longer running. Event listeners - will receive the exit code and termination signal as two arguments. - -### Methods - -* `start()`: Launches the process and registers its IO streams with the event - loop. The stdin stream will be left in a paused state. -* `terminate()`: Send the process a signal (SIGTERM by default). - -There are additional public methods on the Process class, which may be used to -access fields otherwise available through `proc_get_status()`. - -### Stream Properties - -Once a process is started, its I/O streams will be constructed as instances of -`React\Stream\Stream`. Before `start()` is called, these properties are `null`. -Once a process terminates, the streams will become closed but not unset. - -* `$stdin` -* `$stdout` -* `$stderr` - -## Usage - - $loop = React\EventLoop\Factory::create(); - - $process = new React\ChildProcess\Process('echo foo'); - - $process->on('exit', function($exitCode, $termSignal) { - // ... - }); - - $loop->addTimer(0.001, function($timer) use ($process) { - $process->start($timer->getLoop()); - - $process->stdout->on('data', function($output) { - // ... - }); - }); - - $loop->run(); - -### Prepending Commands with `exec` - -Symfony pull request [#5759](https://github.com/symfony/symfony/issues/5759) -documents a caveat with the -[Program Execution](http://php.net/manual/en/book.exec.php) extension. PHP will -launch processes via `sh`, which obfuscates the underlying process' PID and -complicates signaling (our process becomes a child of `sh`). As a work-around, -prepend the command string with `exec`, which will cause the `sh` process to be -replaced by our process. - -### Sigchild Compatibility - -When PHP has been compiled with the `--enabled-sigchild` option, a child -process' exit code cannot be reliably determined via `proc_close()` or -`proc_get_status()`. Instead, we execute the child process with a fourth pipe -and use that to retrieve its exit code. - -This behavior is used by default and only when necessary. It may be manually -disabled by calling `setEnhanceSigchildCompatibility(false)` on the Process -before it is started, in which case the `exit` event may receive `null` instead -of the actual exit code. - -**Note:** This functionality was taken from Symfony's -[Process](https://github.com/symfony/process) compoment. - -### Command Chaining - -Command chaning with `&&` or `;`, while possible with `proc_open()`, should not -be used with this component. There is currently no way to discern when each -process in a chain ends, which would complicate working with I/O streams. As an -alternative, considering launching one process at a time and listening on its -`exit` event to conditionally start the next process in the chain. This will -give you an opportunity to configure the subsequent process' I/O streams. +# Child Process Component + +Library for executing child processes. + +## Introduction + +This library integrates the +[Program Execution](http://php.net/manual/en/book.exec.php) extension in PHP +with React's event loop. + +Child processes launched within the event loop may be signaled and will emit an +`exit` event upon termination. Additionally, process I/O streams (i.e. stdin, +stdout, stderr) are registered with the loop. + +## Processes + +### EventEmitter Events + +* `exit`: Emitted whenever the process is no longer running. Event listeners + will receive the exit code and termination signal as two arguments. + +### Methods + +* `start()`: Launches the process and registers its IO streams with the event + loop. The stdin stream will be left in a paused state. +* `terminate()`: Send the process a signal (SIGTERM by default). + +There are additional public methods on the Process class, which may be used to +access fields otherwise available through `proc_get_status()`. + +### Stream Properties + +Once a process is started, its I/O streams will be constructed as instances of +`React\Stream\Stream`. Before `start()` is called, these properties are `null`. +Once a process terminates, the streams will become closed but not unset. + +* `$stdin` +* `$stdout` +* `$stderr` + +## Usage + + $loop = React\EventLoop\Factory::create(); + + $process = new React\ChildProcess\Process('echo foo'); + + $process->on('exit', function($exitCode, $termSignal) { + // ... + }); + + $loop->addTimer(0.001, function($timer) use ($process) { + $process->start($timer->getLoop()); + + $process->stdout->on('data', function($output) { + // ... + }); + }); + + $loop->run(); + +### Prepending Commands with `exec` + +Symfony pull request [#5759](https://github.com/symfony/symfony/issues/5759) +documents a caveat with the +[Program Execution](http://php.net/manual/en/book.exec.php) extension. PHP will +launch processes via `sh`, which obfuscates the underlying process' PID and +complicates signaling (our process becomes a child of `sh`). As a work-around, +prepend the command string with `exec`, which will cause the `sh` process to be +replaced by our process. + +### Sigchild Compatibility + +When PHP has been compiled with the `--enabled-sigchild` option, a child +process' exit code cannot be reliably determined via `proc_close()` or +`proc_get_status()`. Instead, we execute the child process with a fourth pipe +and use that to retrieve its exit code. + +This behavior is used by default and only when necessary. It may be manually +disabled by calling `setEnhanceSigchildCompatibility(false)` on the Process +before it is started, in which case the `exit` event may receive `null` instead +of the actual exit code. + +**Note:** This functionality was taken from Symfony's +[Process](https://github.com/symfony/process) compoment. + +### Command Chaining + +Command chaning with `&&` or `;`, while possible with `proc_open()`, should not +be used with this component. There is currently no way to discern when each +process in a chain ends, which would complicate working with I/O streams. As an +alternative, considering launching one process at a time and listening on its +`exit` event to conditionally start the next process in the chain. This will +give you an opportunity to configure the subsequent process' I/O streams. diff --git a/app/libs/vendor/react/react/src/ChildProcess/composer.json b/app/libs/vendor/react/react/src/ChildProcess/composer.json index 65ea5b70..dc4917e8 100644 --- a/app/libs/vendor/react/react/src/ChildProcess/composer.json +++ b/app/libs/vendor/react/react/src/ChildProcess/composer.json @@ -1,20 +1,20 @@ -{ - "name": "react/child-process", - "description": "Library for executing child processes.", - "keywords": ["process"], - "license": "MIT", - "require": { - "php": ">=5.4.0", - "evenement/evenement": "~2.0", - "react/event-loop": "0.4.*", - "react/stream": "0.4.*" - }, - "autoload": { - "psr-4": { "React\\ChildProcess\\": "" } - }, - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - } -} +{ + "name": "react/child-process", + "description": "Library for executing child processes.", + "keywords": ["process"], + "license": "MIT", + "require": { + "php": ">=5.4.0", + "evenement/evenement": "~2.0", + "react/event-loop": "0.4.*", + "react/stream": "0.4.*" + }, + "autoload": { + "psr-4": { "React\\ChildProcess\\": "" } + }, + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + } +} diff --git a/app/libs/vendor/react/react/src/Dns/BadServerException.php b/app/libs/vendor/react/react/src/Dns/BadServerException.php index c059cfc7..3bf50f15 100644 --- a/app/libs/vendor/react/react/src/Dns/BadServerException.php +++ b/app/libs/vendor/react/react/src/Dns/BadServerException.php @@ -1,7 +1,7 @@ -loop = $loop; - } - - public function create($filename) - { - return $this - ->loadEtcResolvConf($filename) - ->then(array($this, 'parseEtcResolvConf')); - } - - public function parseEtcResolvConf($contents) - { - $nameservers = array(); - - $contents = preg_replace('/^#/', '', $contents); - $lines = preg_split('/\r?\n/is', $contents); - foreach ($lines as $line) { - if (preg_match('/^nameserver (.+)/', $line, $match)) { - $nameservers[] = $match[1]; - } - } - - $config = new Config(); - $config->nameservers = $nameservers; - - return Promise\resolve($config); - } - - public function loadEtcResolvConf($filename) - { - if (!file_exists($filename)) { - return Promise\reject(new \InvalidArgumentException("The filename for /etc/resolv.conf given does not exist: $filename")); - } - - try { - $deferred = new Deferred(); - - $fd = fopen($filename, 'r'); - stream_set_blocking($fd, 0); - - $contents = ''; - - $stream = new Stream($fd, $this->loop); - $stream->on('data', function ($data) use (&$contents) { - $contents .= $data; - }); - $stream->on('end', function () use (&$contents, $deferred) { - $deferred->resolve($contents); - }); - $stream->on('error', function ($error) use ($deferred) { - $deferred->reject($error); - }); - - return $deferred->promise(); - } catch (\Exception $e) { - return Promise\reject($e); - } - } -} +loop = $loop; + } + + public function create($filename) + { + return $this + ->loadEtcResolvConf($filename) + ->then(array($this, 'parseEtcResolvConf')); + } + + public function parseEtcResolvConf($contents) + { + $nameservers = array(); + + $contents = preg_replace('/^#/', '', $contents); + $lines = preg_split('/\r?\n/is', $contents); + foreach ($lines as $line) { + if (preg_match('/^nameserver (.+)/', $line, $match)) { + $nameservers[] = $match[1]; + } + } + + $config = new Config(); + $config->nameservers = $nameservers; + + return Promise\resolve($config); + } + + public function loadEtcResolvConf($filename) + { + if (!file_exists($filename)) { + return Promise\reject(new \InvalidArgumentException("The filename for /etc/resolv.conf given does not exist: $filename")); + } + + try { + $deferred = new Deferred(); + + $fd = fopen($filename, 'r'); + stream_set_blocking($fd, 0); + + $contents = ''; + + $stream = new Stream($fd, $this->loop); + $stream->on('data', function ($data) use (&$contents) { + $contents .= $data; + }); + $stream->on('end', function () use (&$contents, $deferred) { + $deferred->resolve($contents); + }); + $stream->on('error', function ($error) use ($deferred) { + $deferred->reject($error); + }); + + return $deferred->promise(); + } catch (\Exception $e) { + return Promise\reject($e); + } + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Model/HeaderBag.php b/app/libs/vendor/react/react/src/Dns/Model/HeaderBag.php index 8ff244a8..193e65cd 100644 --- a/app/libs/vendor/react/react/src/Dns/Model/HeaderBag.php +++ b/app/libs/vendor/react/react/src/Dns/Model/HeaderBag.php @@ -1,56 +1,56 @@ - 0, - 'anCount' => 0, - 'nsCount' => 0, - 'arCount' => 0, - 'qr' => 0, - 'opcode' => Message::OPCODE_QUERY, - 'aa' => 0, - 'tc' => 0, - 'rd' => 0, - 'ra' => 0, - 'z' => 0, - 'rcode' => Message::RCODE_OK, - ); - - public function get($name) - { - return isset($this->attributes[$name]) ? $this->attributes[$name] : null; - } - - public function set($name, $value) - { - $this->attributes[$name] = $value; - } - - public function isQuery() - { - return 0 === $this->attributes['qr']; - } - - public function isResponse() - { - return 1 === $this->attributes['qr']; - } - - public function isTruncated() - { - return 1 === $this->attributes['tc']; - } - - public function populateCounts(Message $message) - { - $this->attributes['qdCount'] = count($message->questions); - $this->attributes['anCount'] = count($message->answers); - $this->attributes['nsCount'] = count($message->authority); - $this->attributes['arCount'] = count($message->additional); - } -} + 0, + 'anCount' => 0, + 'nsCount' => 0, + 'arCount' => 0, + 'qr' => 0, + 'opcode' => Message::OPCODE_QUERY, + 'aa' => 0, + 'tc' => 0, + 'rd' => 0, + 'ra' => 0, + 'z' => 0, + 'rcode' => Message::RCODE_OK, + ); + + public function get($name) + { + return isset($this->attributes[$name]) ? $this->attributes[$name] : null; + } + + public function set($name, $value) + { + $this->attributes[$name] = $value; + } + + public function isQuery() + { + return 0 === $this->attributes['qr']; + } + + public function isResponse() + { + return 1 === $this->attributes['qr']; + } + + public function isTruncated() + { + return 1 === $this->attributes['tc']; + } + + public function populateCounts(Message $message) + { + $this->attributes['qdCount'] = count($message->questions); + $this->attributes['anCount'] = count($message->answers); + $this->attributes['nsCount'] = count($message->authority); + $this->attributes['arCount'] = count($message->additional); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Model/Message.php b/app/libs/vendor/react/react/src/Dns/Model/Message.php index f6d2a627..a3ced691 100644 --- a/app/libs/vendor/react/react/src/Dns/Model/Message.php +++ b/app/libs/vendor/react/react/src/Dns/Model/Message.php @@ -1,47 +1,47 @@ -header = new HeaderBag(); - } - - public function prepare() - { - $this->header->populateCounts($this); - } -} +header = new HeaderBag(); + } + + public function prepare() + { + $this->header->populateCounts($this); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Model/Record.php b/app/libs/vendor/react/react/src/Dns/Model/Record.php index e7953bc6..029d2324 100644 --- a/app/libs/vendor/react/react/src/Dns/Model/Record.php +++ b/app/libs/vendor/react/react/src/Dns/Model/Record.php @@ -1,21 +1,21 @@ -name = $name; - $this->type = $type; - $this->class = $class; - $this->ttl = $ttl; - $this->data = $data; - } -} +name = $name; + $this->type = $type; + $this->class = $class; + $this->ttl = $ttl; + $this->data = $data; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Protocol/BinaryDumper.php b/app/libs/vendor/react/react/src/Dns/Protocol/BinaryDumper.php index 6b8919fd..35d6ae60 100644 --- a/app/libs/vendor/react/react/src/Dns/Protocol/BinaryDumper.php +++ b/app/libs/vendor/react/react/src/Dns/Protocol/BinaryDumper.php @@ -1,62 +1,62 @@ -headerToBinary($message->header); - $data .= $this->questionToBinary($message->questions); - - return $data; - } - - private function headerToBinary(HeaderBag $header) - { - $data = ''; - - $data .= pack('n', $header->get('id')); - - $flags = 0x00; - $flags = ($flags << 1) | $header->get('qr'); - $flags = ($flags << 4) | $header->get('opcode'); - $flags = ($flags << 1) | $header->get('aa'); - $flags = ($flags << 1) | $header->get('tc'); - $flags = ($flags << 1) | $header->get('rd'); - $flags = ($flags << 1) | $header->get('ra'); - $flags = ($flags << 3) | $header->get('z'); - $flags = ($flags << 4) | $header->get('rcode'); - - $data .= pack('n', $flags); - - $data .= pack('n', $header->get('qdCount')); - $data .= pack('n', $header->get('anCount')); - $data .= pack('n', $header->get('nsCount')); - $data .= pack('n', $header->get('arCount')); - - return $data; - } - - private function questionToBinary(array $questions) - { - $data = ''; - - foreach ($questions as $question) { - $labels = explode('.', $question['name']); - foreach ($labels as $label) { - $data .= chr(strlen($label)).$label; - } - $data .= "\x00"; - - $data .= pack('n*', $question['type'], $question['class']); - } - - return $data; - } -} +headerToBinary($message->header); + $data .= $this->questionToBinary($message->questions); + + return $data; + } + + private function headerToBinary(HeaderBag $header) + { + $data = ''; + + $data .= pack('n', $header->get('id')); + + $flags = 0x00; + $flags = ($flags << 1) | $header->get('qr'); + $flags = ($flags << 4) | $header->get('opcode'); + $flags = ($flags << 1) | $header->get('aa'); + $flags = ($flags << 1) | $header->get('tc'); + $flags = ($flags << 1) | $header->get('rd'); + $flags = ($flags << 1) | $header->get('ra'); + $flags = ($flags << 3) | $header->get('z'); + $flags = ($flags << 4) | $header->get('rcode'); + + $data .= pack('n', $flags); + + $data .= pack('n', $header->get('qdCount')); + $data .= pack('n', $header->get('anCount')); + $data .= pack('n', $header->get('nsCount')); + $data .= pack('n', $header->get('arCount')); + + return $data; + } + + private function questionToBinary(array $questions) + { + $data = ''; + + foreach ($questions as $question) { + $labels = explode('.', $question['name']); + foreach ($labels as $label) { + $data .= chr(strlen($label)).$label; + } + $data .= "\x00"; + + $data .= pack('n*', $question['type'], $question['class']); + } + + return $data; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Protocol/Parser.php b/app/libs/vendor/react/react/src/Dns/Protocol/Parser.php index 1aa6509b..1099328a 100644 --- a/app/libs/vendor/react/react/src/Dns/Protocol/Parser.php +++ b/app/libs/vendor/react/react/src/Dns/Protocol/Parser.php @@ -1,228 +1,228 @@ -data .= $data; - - if (!$message->header->get('id')) { - if (!$this->parseHeader($message)) { - return; - } - } - - if ($message->header->get('qdCount') != count($message->questions)) { - if (!$this->parseQuestion($message)) { - return; - } - } - - if ($message->header->get('anCount') != count($message->answers)) { - if (!$this->parseAnswer($message)) { - return; - } - } - - return $message; - } - - public function parseHeader(Message $message) - { - if (strlen($message->data) < 12) { - return; - } - - $header = substr($message->data, 0, 12); - $message->consumed += 12; - - list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_values(unpack('n*', $header)); - - $rcode = $fields & bindec('1111'); - $z = ($fields >> 4) & bindec('111'); - $ra = ($fields >> 7) & 1; - $rd = ($fields >> 8) & 1; - $tc = ($fields >> 9) & 1; - $aa = ($fields >> 10) & 1; - $opcode = ($fields >> 11) & bindec('1111'); - $qr = ($fields >> 15) & 1; - - $vars = compact('id', 'qdCount', 'anCount', 'nsCount', 'arCount', - 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z', 'rcode'); - - - foreach ($vars as $name => $value) { - $message->header->set($name, $value); - } - - return $message; - } - - public function parseQuestion(Message $message) - { - if (strlen($message->data) < 2) { - return; - } - - $consumed = $message->consumed; - - list($labels, $consumed) = $this->readLabels($message->data, $consumed); - - if (null === $labels) { - return; - } - - if (strlen($message->data) - $consumed < 4) { - return; - } - - list($type, $class) = array_values(unpack('n*', substr($message->data, $consumed, 4))); - $consumed += 4; - - $message->consumed = $consumed; - - $message->questions[] = array( - 'name' => implode('.', $labels), - 'type' => $type, - 'class' => $class, - ); - - if ($message->header->get('qdCount') != count($message->questions)) { - return $this->parseQuestion($message); - } - - return $message; - } - - public function parseAnswer(Message $message) - { - if (strlen($message->data) < 2) { - return; - } - - $consumed = $message->consumed; - - list($labels, $consumed) = $this->readLabels($message->data, $consumed); - - if (null === $labels) { - return; - } - - if (strlen($message->data) - $consumed < 10) { - return; - } - - list($type, $class) = array_values(unpack('n*', substr($message->data, $consumed, 4))); - $consumed += 4; - - list($ttl) = array_values(unpack('N', substr($message->data, $consumed, 4))); - $consumed += 4; - - list($rdLength) = array_values(unpack('n', substr($message->data, $consumed, 2))); - $consumed += 2; - - $rdata = null; - - if (Message::TYPE_A === $type) { - $ip = substr($message->data, $consumed, $rdLength); - $consumed += $rdLength; - - $rdata = inet_ntop($ip); - } - - if (Message::TYPE_CNAME === $type) { - list($bodyLabels, $consumed) = $this->readLabels($message->data, $consumed); - - $rdata = implode('.', $bodyLabels); - } - - $message->consumed = $consumed; - - $name = implode('.', $labels); - $ttl = $this->signedLongToUnsignedLong($ttl); - $record = new Record($name, $type, $class, $ttl, $rdata); - - $message->answers[] = $record; - - if ($message->header->get('anCount') != count($message->answers)) { - return $this->parseAnswer($message); - } - - return $message; - } - - private function readLabels($data, $consumed) - { - $labels = array(); - - while (true) { - if ($this->isEndOfLabels($data, $consumed)) { - $consumed += 1; - break; - } - - if ($this->isCompressedLabel($data, $consumed)) { - list($newLabels, $consumed) = $this->getCompressedLabel($data, $consumed); - $labels = array_merge($labels, $newLabels); - break; - } - - $length = ord(substr($data, $consumed, 1)); - $consumed += 1; - - if (strlen($data) - $consumed < $length) { - return array(null, null); - } - - $labels[] = substr($data, $consumed, $length); - $consumed += $length; - } - - return array($labels, $consumed); - } - - public function isEndOfLabels($data, $consumed) - { - $length = ord(substr($data, $consumed, 1)); - return 0 === $length; - } - - public function getCompressedLabel($data, $consumed) - { - list($nameOffset, $consumed) = $this->getCompressedLabelOffset($data, $consumed); - list($labels) = $this->readLabels($data, $nameOffset); - - return array($labels, $consumed); - } - - public function isCompressedLabel($data, $consumed) - { - $mask = 0xc000; // 1100000000000000 - list($peek) = array_values(unpack('n', substr($data, $consumed, 2))); - - return (bool) ($peek & $mask); - } - - public function getCompressedLabelOffset($data, $consumed) - { - $mask = 0x3fff; // 0011111111111111 - list($peek) = array_values(unpack('n', substr($data, $consumed, 2))); - - return array($peek & $mask, $consumed + 2); - } - - public function signedLongToUnsignedLong($i) - { - return $i & 0x80000000 ? $i - 0xffffffff : $i; - } -} +data .= $data; + + if (!$message->header->get('id')) { + if (!$this->parseHeader($message)) { + return; + } + } + + if ($message->header->get('qdCount') != count($message->questions)) { + if (!$this->parseQuestion($message)) { + return; + } + } + + if ($message->header->get('anCount') != count($message->answers)) { + if (!$this->parseAnswer($message)) { + return; + } + } + + return $message; + } + + public function parseHeader(Message $message) + { + if (strlen($message->data) < 12) { + return; + } + + $header = substr($message->data, 0, 12); + $message->consumed += 12; + + list($id, $fields, $qdCount, $anCount, $nsCount, $arCount) = array_values(unpack('n*', $header)); + + $rcode = $fields & bindec('1111'); + $z = ($fields >> 4) & bindec('111'); + $ra = ($fields >> 7) & 1; + $rd = ($fields >> 8) & 1; + $tc = ($fields >> 9) & 1; + $aa = ($fields >> 10) & 1; + $opcode = ($fields >> 11) & bindec('1111'); + $qr = ($fields >> 15) & 1; + + $vars = compact('id', 'qdCount', 'anCount', 'nsCount', 'arCount', + 'qr', 'opcode', 'aa', 'tc', 'rd', 'ra', 'z', 'rcode'); + + + foreach ($vars as $name => $value) { + $message->header->set($name, $value); + } + + return $message; + } + + public function parseQuestion(Message $message) + { + if (strlen($message->data) < 2) { + return; + } + + $consumed = $message->consumed; + + list($labels, $consumed) = $this->readLabels($message->data, $consumed); + + if (null === $labels) { + return; + } + + if (strlen($message->data) - $consumed < 4) { + return; + } + + list($type, $class) = array_values(unpack('n*', substr($message->data, $consumed, 4))); + $consumed += 4; + + $message->consumed = $consumed; + + $message->questions[] = array( + 'name' => implode('.', $labels), + 'type' => $type, + 'class' => $class, + ); + + if ($message->header->get('qdCount') != count($message->questions)) { + return $this->parseQuestion($message); + } + + return $message; + } + + public function parseAnswer(Message $message) + { + if (strlen($message->data) < 2) { + return; + } + + $consumed = $message->consumed; + + list($labels, $consumed) = $this->readLabels($message->data, $consumed); + + if (null === $labels) { + return; + } + + if (strlen($message->data) - $consumed < 10) { + return; + } + + list($type, $class) = array_values(unpack('n*', substr($message->data, $consumed, 4))); + $consumed += 4; + + list($ttl) = array_values(unpack('N', substr($message->data, $consumed, 4))); + $consumed += 4; + + list($rdLength) = array_values(unpack('n', substr($message->data, $consumed, 2))); + $consumed += 2; + + $rdata = null; + + if (Message::TYPE_A === $type) { + $ip = substr($message->data, $consumed, $rdLength); + $consumed += $rdLength; + + $rdata = inet_ntop($ip); + } + + if (Message::TYPE_CNAME === $type) { + list($bodyLabels, $consumed) = $this->readLabels($message->data, $consumed); + + $rdata = implode('.', $bodyLabels); + } + + $message->consumed = $consumed; + + $name = implode('.', $labels); + $ttl = $this->signedLongToUnsignedLong($ttl); + $record = new Record($name, $type, $class, $ttl, $rdata); + + $message->answers[] = $record; + + if ($message->header->get('anCount') != count($message->answers)) { + return $this->parseAnswer($message); + } + + return $message; + } + + private function readLabels($data, $consumed) + { + $labels = array(); + + while (true) { + if ($this->isEndOfLabels($data, $consumed)) { + $consumed += 1; + break; + } + + if ($this->isCompressedLabel($data, $consumed)) { + list($newLabels, $consumed) = $this->getCompressedLabel($data, $consumed); + $labels = array_merge($labels, $newLabels); + break; + } + + $length = ord(substr($data, $consumed, 1)); + $consumed += 1; + + if (strlen($data) - $consumed < $length) { + return array(null, null); + } + + $labels[] = substr($data, $consumed, $length); + $consumed += $length; + } + + return array($labels, $consumed); + } + + public function isEndOfLabels($data, $consumed) + { + $length = ord(substr($data, $consumed, 1)); + return 0 === $length; + } + + public function getCompressedLabel($data, $consumed) + { + list($nameOffset, $consumed) = $this->getCompressedLabelOffset($data, $consumed); + list($labels) = $this->readLabels($data, $nameOffset); + + return array($labels, $consumed); + } + + public function isCompressedLabel($data, $consumed) + { + $mask = 0xc000; // 1100000000000000 + list($peek) = array_values(unpack('n', substr($data, $consumed, 2))); + + return (bool) ($peek & $mask); + } + + public function getCompressedLabelOffset($data, $consumed) + { + $mask = 0x3fff; // 0011111111111111 + list($peek) = array_values(unpack('n', substr($data, $consumed, 2))); + + return array($peek & $mask, $consumed + 2); + } + + public function signedLongToUnsignedLong($i) + { + return $i & 0x80000000 ? $i - 0xffffffff : $i; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/CachedExecutor.php b/app/libs/vendor/react/react/src/Dns/Query/CachedExecutor.php index 2b072eb6..78a51bc8 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/CachedExecutor.php +++ b/app/libs/vendor/react/react/src/Dns/Query/CachedExecutor.php @@ -1,66 +1,66 @@ -executor = $executor; - $this->cache = $cache; - } - - public function query($nameserver, Query $query) - { - $executor = $this->executor; - $cache = $this->cache; - - return $this->cache - ->lookup($query) - ->then( - function ($cachedRecords) use ($query) { - return $this->buildResponse($query, $cachedRecords); - }, - function () use ($executor, $cache, $nameserver, $query) { - return $executor - ->query($nameserver, $query) - ->then(function ($response) use ($cache, $query) { - $cache->storeResponseMessage($query->currentTime, $response); - return $response; - }); - } - ); - } - - public function buildResponse(Query $query, array $cachedRecords) - { - $response = new Message(); - - $response->header->set('id', $this->generateId()); - $response->header->set('qr', 1); - $response->header->set('opcode', Message::OPCODE_QUERY); - $response->header->set('rd', 1); - $response->header->set('rcode', Message::RCODE_OK); - - $response->questions[] = new Record($query->name, $query->type, $query->class); - - foreach ($cachedRecords as $record) { - $response->answers[] = $record; - } - - $response->prepare(); - - return $response; - } - - protected function generateId() - { - return mt_rand(0, 0xffff); - } -} +executor = $executor; + $this->cache = $cache; + } + + public function query($nameserver, Query $query) + { + $executor = $this->executor; + $cache = $this->cache; + + return $this->cache + ->lookup($query) + ->then( + function ($cachedRecords) use ($query) { + return $this->buildResponse($query, $cachedRecords); + }, + function () use ($executor, $cache, $nameserver, $query) { + return $executor + ->query($nameserver, $query) + ->then(function ($response) use ($cache, $query) { + $cache->storeResponseMessage($query->currentTime, $response); + return $response; + }); + } + ); + } + + public function buildResponse(Query $query, array $cachedRecords) + { + $response = new Message(); + + $response->header->set('id', $this->generateId()); + $response->header->set('qr', 1); + $response->header->set('opcode', Message::OPCODE_QUERY); + $response->header->set('rd', 1); + $response->header->set('rcode', Message::RCODE_OK); + + $response->questions[] = new Record($query->name, $query->type, $query->class); + + foreach ($cachedRecords as $record) { + $response->answers[] = $record; + } + + $response->prepare(); + + return $response; + } + + protected function generateId() + { + return mt_rand(0, 0xffff); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/Executor.php b/app/libs/vendor/react/react/src/Dns/Query/Executor.php index fdd2f2ce..25e5ba8f 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/Executor.php +++ b/app/libs/vendor/react/react/src/Dns/Query/Executor.php @@ -1,107 +1,107 @@ -loop = $loop; - $this->parser = $parser; - $this->dumper = $dumper; - $this->timeout = $timeout; - } - - public function query($nameserver, Query $query) - { - $request = $this->prepareRequest($query); - - $queryData = $this->dumper->toBinary($request); - $transport = strlen($queryData) > 512 ? 'tcp' : 'udp'; - - return $this->doQuery($nameserver, $transport, $queryData, $query->name); - } - - public function prepareRequest(Query $query) - { - $request = new Message(); - $request->header->set('id', $this->generateId()); - $request->header->set('rd', 1); - $request->questions[] = (array) $query; - $request->prepare(); - - return $request; - } - - public function doQuery($nameserver, $transport, $queryData, $name) - { - $parser = $this->parser; - $loop = $this->loop; - - $response = new Message(); - $deferred = new Deferred(); - - $retryWithTcp = function () use ($nameserver, $queryData, $name) { - return $this->doQuery($nameserver, 'tcp', $queryData, $name); - }; - - $timer = $this->loop->addTimer($this->timeout, function () use (&$conn, $name, $deferred) { - $conn->close(); - $deferred->reject(new TimeoutException(sprintf("DNS query for %s timed out", $name))); - }); - - $conn = $this->createConnection($nameserver, $transport); - $conn->on('data', function ($data) use ($retryWithTcp, $conn, $parser, $response, $transport, $deferred, $timer) { - $responseReady = $parser->parseChunk($data, $response); - - if (!$responseReady) { - return; - } - - $timer->cancel(); - - if ($response->header->isTruncated()) { - if ('tcp' === $transport) { - $deferred->reject(new BadServerException('The server set the truncated bit although we issued a TCP request')); - } else { - $conn->end(); - $deferred->resolve($retryWithTcp()); - } - - return; - } - - $conn->end(); - $deferred->resolve($response); - }); - $conn->write($queryData); - - return $deferred->promise(); - } - - protected function generateId() - { - return mt_rand(0, 0xffff); - } - - protected function createConnection($nameserver, $transport) - { - $fd = stream_socket_client("$transport://$nameserver"); - $conn = new Connection($fd, $this->loop); - - return $conn; - } -} +loop = $loop; + $this->parser = $parser; + $this->dumper = $dumper; + $this->timeout = $timeout; + } + + public function query($nameserver, Query $query) + { + $request = $this->prepareRequest($query); + + $queryData = $this->dumper->toBinary($request); + $transport = strlen($queryData) > 512 ? 'tcp' : 'udp'; + + return $this->doQuery($nameserver, $transport, $queryData, $query->name); + } + + public function prepareRequest(Query $query) + { + $request = new Message(); + $request->header->set('id', $this->generateId()); + $request->header->set('rd', 1); + $request->questions[] = (array) $query; + $request->prepare(); + + return $request; + } + + public function doQuery($nameserver, $transport, $queryData, $name) + { + $parser = $this->parser; + $loop = $this->loop; + + $response = new Message(); + $deferred = new Deferred(); + + $retryWithTcp = function () use ($nameserver, $queryData, $name) { + return $this->doQuery($nameserver, 'tcp', $queryData, $name); + }; + + $timer = $this->loop->addTimer($this->timeout, function () use (&$conn, $name, $deferred) { + $conn->close(); + $deferred->reject(new TimeoutException(sprintf("DNS query for %s timed out", $name))); + }); + + $conn = $this->createConnection($nameserver, $transport); + $conn->on('data', function ($data) use ($retryWithTcp, $conn, $parser, $response, $transport, $deferred, $timer) { + $responseReady = $parser->parseChunk($data, $response); + + if (!$responseReady) { + return; + } + + $timer->cancel(); + + if ($response->header->isTruncated()) { + if ('tcp' === $transport) { + $deferred->reject(new BadServerException('The server set the truncated bit although we issued a TCP request')); + } else { + $conn->end(); + $deferred->resolve($retryWithTcp()); + } + + return; + } + + $conn->end(); + $deferred->resolve($response); + }); + $conn->write($queryData); + + return $deferred->promise(); + } + + protected function generateId() + { + return mt_rand(0, 0xffff); + } + + protected function createConnection($nameserver, $transport) + { + $fd = stream_socket_client("$transport://$nameserver"); + $conn = new Connection($fd, $this->loop); + + return $conn; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/ExecutorInterface.php b/app/libs/vendor/react/react/src/Dns/Query/ExecutorInterface.php index 449ece9c..2f7a6359 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/ExecutorInterface.php +++ b/app/libs/vendor/react/react/src/Dns/Query/ExecutorInterface.php @@ -1,8 +1,8 @@ -name = $name; - $this->type = $type; - $this->class = $class; - $this->currentTime = $currentTime; - } -} +name = $name; + $this->type = $type; + $this->class = $class; + $this->currentTime = $currentTime; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/RecordBag.php b/app/libs/vendor/react/react/src/Dns/Query/RecordBag.php index ca073b7b..358cf5da 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/RecordBag.php +++ b/app/libs/vendor/react/react/src/Dns/Query/RecordBag.php @@ -1,27 +1,27 @@ -records[$record->data] = array($currentTime + $record->ttl, $record); - } - - public function all() - { - return array_values(array_map( - function ($value) { - list($expiresAt, $record) = $value; - return $record; - }, - $this->records - )); - } -} +records[$record->data] = array($currentTime + $record->ttl, $record); + } + + public function all() + { + return array_values(array_map( + function ($value) { + list($expiresAt, $record) = $value; + return $record; + }, + $this->records + )); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/RecordCache.php b/app/libs/vendor/react/react/src/Dns/Query/RecordCache.php index fe2cd46d..b8142d3d 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/RecordCache.php +++ b/app/libs/vendor/react/react/src/Dns/Query/RecordCache.php @@ -1,82 +1,82 @@ -cache = $cache; - } - - public function lookup(Query $query) - { - $id = $this->serializeQueryToIdentity($query); - - $expiredAt = $this->expiredAt; - - return $this->cache - ->get($id) - ->then(function ($value) use ($query, $expiredAt) { - $recordBag = unserialize($value); - - if (null !== $expiredAt && $expiredAt <= $query->currentTime) { - return Promise\reject(); - } - - return $recordBag->all(); - }); - } - - public function storeResponseMessage($currentTime, Message $message) - { - foreach ($message->answers as $record) { - $this->storeRecord($currentTime, $record); - } - } - - public function storeRecord($currentTime, Record $record) - { - $id = $this->serializeRecordToIdentity($record); - - $cache = $this->cache; - - $this->cache - ->get($id) - ->then( - function ($value) { - return unserialize($value); - }, - function ($e) { - return new RecordBag(); - } - ) - ->then(function ($recordBag) use ($id, $currentTime, $record, $cache) { - $recordBag->set($currentTime, $record); - $cache->set($id, serialize($recordBag)); - }); - } - - public function expire($currentTime) - { - $this->expiredAt = $currentTime; - } - - public function serializeQueryToIdentity(Query $query) - { - return sprintf('%s:%s:%s', $query->name, $query->type, $query->class); - } - - public function serializeRecordToIdentity(Record $record) - { - return sprintf('%s:%s:%s', $record->name, $record->type, $record->class); - } -} +cache = $cache; + } + + public function lookup(Query $query) + { + $id = $this->serializeQueryToIdentity($query); + + $expiredAt = $this->expiredAt; + + return $this->cache + ->get($id) + ->then(function ($value) use ($query, $expiredAt) { + $recordBag = unserialize($value); + + if (null !== $expiredAt && $expiredAt <= $query->currentTime) { + return Promise\reject(); + } + + return $recordBag->all(); + }); + } + + public function storeResponseMessage($currentTime, Message $message) + { + foreach ($message->answers as $record) { + $this->storeRecord($currentTime, $record); + } + } + + public function storeRecord($currentTime, Record $record) + { + $id = $this->serializeRecordToIdentity($record); + + $cache = $this->cache; + + $this->cache + ->get($id) + ->then( + function ($value) { + return unserialize($value); + }, + function ($e) { + return new RecordBag(); + } + ) + ->then(function ($recordBag) use ($id, $currentTime, $record, $cache) { + $recordBag->set($currentTime, $record); + $cache->set($id, serialize($recordBag)); + }); + } + + public function expire($currentTime) + { + $this->expiredAt = $currentTime; + } + + public function serializeQueryToIdentity(Query $query) + { + return sprintf('%s:%s:%s', $query->name, $query->type, $query->class); + } + + public function serializeRecordToIdentity(Record $record) + { + return sprintf('%s:%s:%s', $record->name, $record->type, $record->class); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/RetryExecutor.php b/app/libs/vendor/react/react/src/Dns/Query/RetryExecutor.php index 1d351d54..ca2a508e 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/RetryExecutor.php +++ b/app/libs/vendor/react/react/src/Dns/Query/RetryExecutor.php @@ -1,50 +1,50 @@ -executor = $executor; - $this->retries = $retries; - } - - public function query($nameserver, Query $query) - { - $deferred = new Deferred(); - - $this->tryQuery($nameserver, $query, $this->retries, $deferred); - - return $deferred->promise(); - } - - public function tryQuery($nameserver, Query $query, $retries, $deferred) - { - $errorback = function ($error) use ($nameserver, $query, $retries, $deferred) { - if (!$error instanceof TimeoutException) { - $deferred->reject($error); - return; - } - if (0 >= $retries) { - $error = new \RuntimeException( - sprintf("DNS query for %s failed: too many retries", $query->name), - 0, - $error - ); - $deferred->reject($error); - return; - } - $this->tryQuery($nameserver, $query, $retries-1, $deferred); - }; - - $this->executor - ->query($nameserver, $query) - ->then(array($deferred, 'resolve'), $errorback); - } -} +executor = $executor; + $this->retries = $retries; + } + + public function query($nameserver, Query $query) + { + $deferred = new Deferred(); + + $this->tryQuery($nameserver, $query, $this->retries, $deferred); + + return $deferred->promise(); + } + + public function tryQuery($nameserver, Query $query, $retries, $deferred) + { + $errorback = function ($error) use ($nameserver, $query, $retries, $deferred) { + if (!$error instanceof TimeoutException) { + $deferred->reject($error); + return; + } + if (0 >= $retries) { + $error = new \RuntimeException( + sprintf("DNS query for %s failed: too many retries", $query->name), + 0, + $error + ); + $deferred->reject($error); + return; + } + $this->tryQuery($nameserver, $query, $retries-1, $deferred); + }; + + $this->executor + ->query($nameserver, $query) + ->then(array($deferred, 'resolve'), $errorback); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Query/TimeoutException.php b/app/libs/vendor/react/react/src/Dns/Query/TimeoutException.php index 567acd6f..90bf806b 100644 --- a/app/libs/vendor/react/react/src/Dns/Query/TimeoutException.php +++ b/app/libs/vendor/react/react/src/Dns/Query/TimeoutException.php @@ -1,7 +1,7 @@ -create('8.8.8.8', $loop); - - $dns->resolve('igor.io')->then(function ($ip) { - echo "Host: $ip\n"; - }); - -But there's more. - -## Caching - -You can cache results by configuring the resolver to use a `CachedExecutor`: - - $loop = React\EventLoop\Factory::create(); - $factory = new React\Dns\Resolver\Factory(); - $dns = $factory->createCached('8.8.8.8', $loop); - - $dns->resolve('igor.io')->then(function ($ip) { - echo "Host: $ip\n"; - }); - - ... - - $dns->resolve('igor.io')->then(function ($ip) { - echo "Host: $ip\n"; - }); - -If the first call returns before the second, only one query will be executed. -The second result will be served from cache. - -## Todo - -* Implement message body parsing for types other than A and CNAME: NS, SOA, PTR, MX, TXT, AAAA -* Implement `authority` and `additional` message parts -* Respect /etc/hosts - -# References - -* [RFC1034](http://tools.ietf.org/html/rfc1034) Domain Names - Concepts and Facilities -* [RFC1035](http://tools.ietf.org/html/rfc1035) Domain Names - Implementation and Specification +# Dns Component + +Async DNS resolver. + +The main point of the DNS component is to provide async DNS resolution. +However, it is really a toolkit for working with DNS messages, and could +easily be used to create a DNS server. + +## Basic usage + +The most basic usage is to just create a resolver through the resolver +factory. All you need to give it is a nameserver, then you can start resolving +names, baby! + + $loop = React\EventLoop\Factory::create(); + $factory = new React\Dns\Resolver\Factory(); + $dns = $factory->create('8.8.8.8', $loop); + + $dns->resolve('igor.io')->then(function ($ip) { + echo "Host: $ip\n"; + }); + +But there's more. + +## Caching + +You can cache results by configuring the resolver to use a `CachedExecutor`: + + $loop = React\EventLoop\Factory::create(); + $factory = new React\Dns\Resolver\Factory(); + $dns = $factory->createCached('8.8.8.8', $loop); + + $dns->resolve('igor.io')->then(function ($ip) { + echo "Host: $ip\n"; + }); + + ... + + $dns->resolve('igor.io')->then(function ($ip) { + echo "Host: $ip\n"; + }); + +If the first call returns before the second, only one query will be executed. +The second result will be served from cache. + +## Todo + +* Implement message body parsing for types other than A and CNAME: NS, SOA, PTR, MX, TXT, AAAA +* Implement `authority` and `additional` message parts +* Respect /etc/hosts + +# References + +* [RFC1034](http://tools.ietf.org/html/rfc1034) Domain Names - Concepts and Facilities +* [RFC1035](http://tools.ietf.org/html/rfc1035) Domain Names - Implementation and Specification diff --git a/app/libs/vendor/react/react/src/Dns/RecordNotFoundException.php b/app/libs/vendor/react/react/src/Dns/RecordNotFoundException.php index 84495796..0028413d 100644 --- a/app/libs/vendor/react/react/src/Dns/RecordNotFoundException.php +++ b/app/libs/vendor/react/react/src/Dns/RecordNotFoundException.php @@ -1,7 +1,7 @@ -addPortToServerIfMissing($nameserver); - $executor = $this->createRetryExecutor($loop); - - return new Resolver($nameserver, $executor); - } - - public function createCached($nameserver, LoopInterface $loop) - { - $nameserver = $this->addPortToServerIfMissing($nameserver); - $executor = $this->createCachedExecutor($loop); - - return new Resolver($nameserver, $executor); - } - - protected function createExecutor(LoopInterface $loop) - { - return new Executor($loop, new Parser(), new BinaryDumper()); - } - - protected function createRetryExecutor(LoopInterface $loop) - { - return new RetryExecutor($this->createExecutor($loop)); - } - - protected function createCachedExecutor(LoopInterface $loop) - { - return new CachedExecutor($this->createRetryExecutor($loop), new RecordCache(new ArrayCache())); - } - - protected function addPortToServerIfMissing($nameserver) - { - if (strpos($nameserver, '[') === false && substr_count($nameserver, ':') >= 2) { - // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets - $nameserver = '[' . $nameserver . ']'; - } - // assume a dummy scheme when checking for the port, otherwise parse_url() fails - if (parse_url('dummy://' . $nameserver, PHP_URL_PORT) === null) { - $nameserver .= ':53'; - } - - return $nameserver; - } -} +addPortToServerIfMissing($nameserver); + $executor = $this->createRetryExecutor($loop); + + return new Resolver($nameserver, $executor); + } + + public function createCached($nameserver, LoopInterface $loop) + { + $nameserver = $this->addPortToServerIfMissing($nameserver); + $executor = $this->createCachedExecutor($loop); + + return new Resolver($nameserver, $executor); + } + + protected function createExecutor(LoopInterface $loop) + { + return new Executor($loop, new Parser(), new BinaryDumper()); + } + + protected function createRetryExecutor(LoopInterface $loop) + { + return new RetryExecutor($this->createExecutor($loop)); + } + + protected function createCachedExecutor(LoopInterface $loop) + { + return new CachedExecutor($this->createRetryExecutor($loop), new RecordCache(new ArrayCache())); + } + + protected function addPortToServerIfMissing($nameserver) + { + if (strpos($nameserver, '[') === false && substr_count($nameserver, ':') >= 2) { + // several colons, but not enclosed in square brackets => enclose IPv6 address in square brackets + $nameserver = '[' . $nameserver . ']'; + } + // assume a dummy scheme when checking for the port, otherwise parse_url() fails + if (parse_url('dummy://' . $nameserver, PHP_URL_PORT) === null) { + $nameserver .= ':53'; + } + + return $nameserver; + } +} diff --git a/app/libs/vendor/react/react/src/Dns/Resolver/Resolver.php b/app/libs/vendor/react/react/src/Dns/Resolver/Resolver.php index 79a8d12f..73546325 100644 --- a/app/libs/vendor/react/react/src/Dns/Resolver/Resolver.php +++ b/app/libs/vendor/react/react/src/Dns/Resolver/Resolver.php @@ -1,98 +1,98 @@ -nameserver = $nameserver; - $this->executor = $executor; - } - - public function resolve($domain) - { - $query = new Query($domain, Message::TYPE_A, Message::CLASS_IN, time()); - - return $this->executor - ->query($this->nameserver, $query) - ->then(function (Message $response) use ($query) { - return $this->extractAddress($query, $response); - }); - } - - public function extractAddress(Query $query, Message $response) - { - $answers = $response->answers; - - $addresses = $this->resolveAliases($answers, $query->name); - - if (0 === count($addresses)) { - $message = 'DNS Request did not return valid answer.'; - throw new RecordNotFoundException($message); - } - - $address = $addresses[array_rand($addresses)]; - return $address; - } - - public function resolveAliases(array $answers, $name) - { - $named = $this->filterByName($answers, $name); - $aRecords = $this->filterByType($named, Message::TYPE_A); - $cnameRecords = $this->filterByType($named, Message::TYPE_CNAME); - - if ($aRecords) { - return $this->mapRecordData($aRecords); - } - - if ($cnameRecords) { - $aRecords = array(); - - $cnames = $this->mapRecordData($cnameRecords); - foreach ($cnames as $cname) { - $targets = $this->filterByName($answers, $cname); - $aRecords = array_merge( - $aRecords, - $this->resolveAliases($answers, $cname) - ); - } - - return $aRecords; - } - - return array(); - } - - private function filterByName(array $answers, $name) - { - return $this->filterByField($answers, 'name', $name); - } - - private function filterByType(array $answers, $type) - { - return $this->filterByField($answers, 'type', $type); - } - - private function filterByField(array $answers, $field, $value) - { - return array_filter($answers, function ($answer) use ($field, $value) { - return $value === $answer->$field; - }); - } - - private function mapRecordData(array $records) - { - return array_map(function ($record) { - return $record->data; - }, $records); - } -} +nameserver = $nameserver; + $this->executor = $executor; + } + + public function resolve($domain) + { + $query = new Query($domain, Message::TYPE_A, Message::CLASS_IN, time()); + + return $this->executor + ->query($this->nameserver, $query) + ->then(function (Message $response) use ($query) { + return $this->extractAddress($query, $response); + }); + } + + public function extractAddress(Query $query, Message $response) + { + $answers = $response->answers; + + $addresses = $this->resolveAliases($answers, $query->name); + + if (0 === count($addresses)) { + $message = 'DNS Request did not return valid answer.'; + throw new RecordNotFoundException($message); + } + + $address = $addresses[array_rand($addresses)]; + return $address; + } + + public function resolveAliases(array $answers, $name) + { + $named = $this->filterByName($answers, $name); + $aRecords = $this->filterByType($named, Message::TYPE_A); + $cnameRecords = $this->filterByType($named, Message::TYPE_CNAME); + + if ($aRecords) { + return $this->mapRecordData($aRecords); + } + + if ($cnameRecords) { + $aRecords = array(); + + $cnames = $this->mapRecordData($cnameRecords); + foreach ($cnames as $cname) { + $targets = $this->filterByName($answers, $cname); + $aRecords = array_merge( + $aRecords, + $this->resolveAliases($answers, $cname) + ); + } + + return $aRecords; + } + + return array(); + } + + private function filterByName(array $answers, $name) + { + return $this->filterByField($answers, 'name', $name); + } + + private function filterByType(array $answers, $type) + { + return $this->filterByField($answers, 'type', $type); + } + + private function filterByField(array $answers, $field, $value) + { + return array_filter($answers, function ($answer) use ($field, $value) { + return $value === $answer->$field; + }); + } + + private function mapRecordData(array $records) + { + return array_map(function ($record) { + return $record->data; + }, $records); + } +} diff --git a/app/libs/vendor/react/react/src/Dns/composer.json b/app/libs/vendor/react/react/src/Dns/composer.json index aae53c99..5929809d 100644 --- a/app/libs/vendor/react/react/src/Dns/composer.json +++ b/app/libs/vendor/react/react/src/Dns/composer.json @@ -1,20 +1,20 @@ -{ - "name": "react/dns", - "description": "Async DNS resolver.", - "keywords": ["dns", "dns-resolver"], - "license": "MIT", - "require": { - "php": ">=5.4.0", - "react/cache": "0.4.*", - "react/socket": "0.4.*", - "react/promise": "~2.0" - }, - "autoload": { - "psr-4": { "React\\Dns\\": "" } - }, - "extra": { - "branch-alias": { - "dev-master": "0.4-dev" - } - } -} +{ + "name": "react/dns", + "description": "Async DNS resolver.", + "keywords": ["dns", "dns-resolver"], + "license": "MIT", + "require": { + "php": ">=5.4.0", + "react/cache": "0.4.*", + "react/socket": "0.4.*", + "react/promise": "~2.0" + }, + "autoload": { + "psr-4": { "React\\Dns\\": "" } + }, + "extra": { + "branch-alias": { + "dev-master": "0.4-dev" + } + } +} diff --git a/app/libs/vendor/react/react/src/Dns/doc/rfc1034.txt b/app/libs/vendor/react/react/src/Dns/doc/rfc1034.txt index 8e1a41a8..55cdb21f 100644 --- a/app/libs/vendor/react/react/src/Dns/doc/rfc1034.txt +++ b/app/libs/vendor/react/react/src/Dns/doc/rfc1034.txt @@ -1,3077 +1,3077 @@ -Network Working Group P. Mockapetris -Request for Comments: 1034 ISI -Obsoletes: RFCs 882, 883, 973 November 1987 - - - DOMAIN NAMES - CONCEPTS AND FACILITIES - - - -1. STATUS OF THIS MEMO - -This RFC is an introduction to the Domain Name System (DNS), and omits -many details which can be found in a companion RFC, "Domain Names - -Implementation and Specification" [RFC-1035]. That RFC assumes that the -reader is familiar with the concepts discussed in this memo. - -A subset of DNS functions and data types constitute an official -protocol. The official protocol includes standard queries and their -responses and most of the Internet class data formats (e.g., host -addresses). - -However, the domain system is intentionally extensible. Researchers are -continuously proposing, implementing and experimenting with new data -types, query types, classes, functions, etc. Thus while the components -of the official protocol are expected to stay essentially unchanged and -operate as a production service, experimental behavior should always be -expected in extensions beyond the official protocol. Experimental or -obsolete features are clearly marked in these RFCs, and such information -should be used with caution. - -The reader is especially cautioned not to depend on the values which -appear in examples to be current or complete, since their purpose is -primarily pedagogical. Distribution of this memo is unlimited. - -2. INTRODUCTION - -This RFC introduces domain style names, their use for Internet mail and -host address support, and the protocols and servers used to implement -domain name facilities. - -2.1. The history of domain names - -The impetus for the development of the domain system was growth in the -Internet: - - - Host name to address mappings were maintained by the Network - Information Center (NIC) in a single file (HOSTS.TXT) which - was FTPed by all hosts [RFC-952, RFC-953]. The total network - - - -Mockapetris [Page 1] - -RFC 1034 Domain Concepts and Facilities November 1987 - - - bandwidth consumed in distributing a new version by this - scheme is proportional to the square of the number of hosts in - the network, and even when multiple levels of FTP are used, - the outgoing FTP load on the NIC host is considerable. - Explosive growth in the number of hosts didn't bode well for - the future. - - - The network population was also changing in character. The - timeshared hosts that made up the original ARPANET were being - replaced with local networks of workstations. Local - organizations were administering their own names and - addresses, but had to wait for the NIC to change HOSTS.TXT to - make changes visible to the Internet at large. Organizations - also wanted some local structure on the name space. - - - The applications on the Internet were getting more - sophisticated and creating a need for general purpose name - service. - - -The result was several ideas about name spaces and their management -[IEN-116, RFC-799, RFC-819, RFC-830]. The proposals varied, but a -common thread was the idea of a hierarchical name space, with the -hierarchy roughly corresponding to organizational structure, and names -using "." as the character to mark the boundary between hierarchy -levels. A design using a distributed database and generalized resources -was described in [RFC-882, RFC-883]. Based on experience with several -implementations, the system evolved into the scheme described in this -memo. - -The terms "domain" or "domain name" are used in many contexts beyond the -DNS described here. Very often, the term domain name is used to refer -to a name with structure indicated by dots, but no relation to the DNS. -This is particularly true in mail addressing [Quarterman 86]. - -2.2. DNS design goals - -The design goals of the DNS influence its structure. They are: - - - The primary goal is a consistent name space which will be used - for referring to resources. In order to avoid the problems - caused by ad hoc encodings, names should not be required to - contain network identifiers, addresses, routes, or similar - information as part of the name. - - - The sheer size of the database and frequency of updates - suggest that it must be maintained in a distributed manner, - with local caching to improve performance. Approaches that - - - -Mockapetris [Page 2] - -RFC 1034 Domain Concepts and Facilities November 1987 - - - attempt to collect a consistent copy of the entire database - will become more and more expensive and difficult, and hence - should be avoided. The same principle holds for the structure - of the name space, and in particular mechanisms for creating - and deleting names; these should also be distributed. - - - Where there tradeoffs between the cost of acquiring data, the - speed of updates, and the accuracy of caches, the source of - the data should control the tradeoff. - - - The costs of implementing such a facility dictate that it be - generally useful, and not restricted to a single application. - We should be able to use names to retrieve host addresses, - mailbox data, and other as yet undetermined information. All - data associated with a name is tagged with a type, and queries - can be limited to a single type. - - - Because we want the name space to be useful in dissimilar - networks and applications, we provide the ability to use the - same name space with different protocol families or - management. For example, host address formats differ between - protocols, though all protocols have the notion of address. - The DNS tags all data with a class as well as the type, so - that we can allow parallel use of different formats for data - of type address. - - - We want name server transactions to be independent of the - communications system that carries them. Some systems may - wish to use datagrams for queries and responses, and only - establish virtual circuits for transactions that need the - reliability (e.g., database updates, long transactions); other - systems will use virtual circuits exclusively. - - - The system should be useful across a wide spectrum of host - capabilities. Both personal computers and large timeshared - hosts should be able to use the system, though perhaps in - different ways. - -2.3. Assumptions about usage - -The organization of the domain system derives from some assumptions -about the needs and usage patterns of its user community and is designed -to avoid many of the the complicated problems found in general purpose -database systems. - -The assumptions are: - - - The size of the total database will initially be proportional - - - -Mockapetris [Page 3] - -RFC 1034 Domain Concepts and Facilities November 1987 - - - to the number of hosts using the system, but will eventually - grow to be proportional to the number of users on those hosts - as mailboxes and other information are added to the domain - system. - - - Most of the data in the system will change very slowly (e.g., - mailbox bindings, host addresses), but that the system should - be able to deal with subsets that change more rapidly (on the - order of seconds or minutes). - - - The administrative boundaries used to distribute - responsibility for the database will usually correspond to - organizations that have one or more hosts. Each organization - that has responsibility for a particular set of domains will - provide redundant name servers, either on the organization's - own hosts or other hosts that the organization arranges to - use. - - - Clients of the domain system should be able to identify - trusted name servers they prefer to use before accepting - referrals to name servers outside of this "trusted" set. - - - Access to information is more critical than instantaneous - updates or guarantees of consistency. Hence the update - process allows updates to percolate out through the users of - the domain system rather than guaranteeing that all copies are - simultaneously updated. When updates are unavailable due to - network or host failure, the usual course is to believe old - information while continuing efforts to update it. The - general model is that copies are distributed with timeouts for - refreshing. The distributor sets the timeout value and the - recipient of the distribution is responsible for performing - the refresh. In special situations, very short intervals can - be specified, or the owner can prohibit copies. - - - In any system that has a distributed database, a particular - name server may be presented with a query that can only be - answered by some other server. The two general approaches to - dealing with this problem are "recursive", in which the first - server pursues the query for the client at another server, and - "iterative", in which the server refers the client to another - server and lets the client pursue the query. Both approaches - have advantages and disadvantages, but the iterative approach - is preferred for the datagram style of access. The domain - system requires implementation of the iterative approach, but - allows the recursive approach as an option. - - - - - -Mockapetris [Page 4] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -The domain system assumes that all data originates in master files -scattered through the hosts that use the domain system. These master -files are updated by local system administrators. Master files are text -files that are read by a local name server, and hence become available -through the name servers to users of the domain system. The user -programs access name servers through standard programs called resolvers. - -The standard format of master files allows them to be exchanged between -hosts (via FTP, mail, or some other mechanism); this facility is useful -when an organization wants a domain, but doesn't want to support a name -server. The organization can maintain the master files locally using a -text editor, transfer them to a foreign host which runs a name server, -and then arrange with the system administrator of the name server to get -the files loaded. - -Each host's name servers and resolvers are configured by a local system -administrator [RFC-1033]. For a name server, this configuration data -includes the identity of local master files and instructions on which -non-local master files are to be loaded from foreign servers. The name -server uses the master files or copies to load its zones. For -resolvers, the configuration data identifies the name servers which -should be the primary sources of information. - -The domain system defines procedures for accessing the data and for -referrals to other name servers. The domain system also defines -procedures for caching retrieved data and for periodic refreshing of -data defined by the system administrator. - -The system administrators provide: - - - The definition of zone boundaries. - - - Master files of data. - - - Updates to master files. - - - Statements of the refresh policies desired. - -The domain system provides: - - - Standard formats for resource data. - - - Standard methods for querying the database. - - - Standard methods for name servers to refresh local data from - foreign name servers. - - - - - -Mockapetris [Page 5] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -2.4. Elements of the DNS - -The DNS has three major components: - - - The DOMAIN NAME SPACE and RESOURCE RECORDS, which are - specifications for a tree structured name space and data - associated with the names. Conceptually, each node and leaf - of the domain name space tree names a set of information, and - query operations are attempts to extract specific types of - information from a particular set. A query names the domain - name of interest and describes the type of resource - information that is desired. For example, the Internet - uses some of its domain names to identify hosts; queries for - address resources return Internet host addresses. - - - NAME SERVERS are server programs which hold information about - the domain tree's structure and set information. A name - server may cache structure or set information about any part - of the domain tree, but in general a particular name server - has complete information about a subset of the domain space, - and pointers to other name servers that can be used to lead to - information from any part of the domain tree. Name servers - know the parts of the domain tree for which they have complete - information; a name server is said to be an AUTHORITY for - these parts of the name space. Authoritative information is - organized into units called ZONEs, and these zones can be - automatically distributed to the name servers which provide - redundant service for the data in a zone. - - - RESOLVERS are programs that extract information from name - servers in response to client requests. Resolvers must be - able to access at least one name server and use that name - server's information to answer a query directly, or pursue the - query using referrals to other name servers. A resolver will - typically be a system routine that is directly accessible to - user programs; hence no protocol is necessary between the - resolver and the user program. - -These three components roughly correspond to the three layers or views -of the domain system: - - - From the user's point of view, the domain system is accessed - through a simple procedure or OS call to a local resolver. - The domain space consists of a single tree and the user can - request information from any section of the tree. - - - From the resolver's point of view, the domain system is - composed of an unknown number of name servers. Each name - - - -Mockapetris [Page 6] - -RFC 1034 Domain Concepts and Facilities November 1987 - - - server has one or more pieces of the whole domain tree's data, - but the resolver views each of these databases as essentially - static. - - - From a name server's point of view, the domain system consists - of separate sets of local information called zones. The name - server has local copies of some of the zones. The name server - must periodically refresh its zones from master copies in - local files or foreign name servers. The name server must - concurrently process queries that arrive from resolvers. - -In the interests of performance, implementations may couple these -functions. For example, a resolver on the same machine as a name server -might share a database consisting of the the zones managed by the name -server and the cache managed by the resolver. - -3. DOMAIN NAME SPACE and RESOURCE RECORDS - -3.1. Name space specifications and terminology - -The domain name space is a tree structure. Each node and leaf on the -tree corresponds to a resource set (which may be empty). The domain -system makes no distinctions between the uses of the interior nodes and -leaves, and this memo uses the term "node" to refer to both. - -Each node has a label, which is zero to 63 octets in length. Brother -nodes may not have the same label, although the same label can be used -for nodes which are not brothers. One label is reserved, and that is -the null (i.e., zero length) label used for the root. - -The domain name of a node is the list of the labels on the path from the -node to the root of the tree. By convention, the labels that compose a -domain name are printed or read left to right, from the most specific -(lowest, farthest from the root) to the least specific (highest, closest -to the root). - -Internally, programs that manipulate domain names should represent them -as sequences of labels, where each label is a length octet followed by -an octet string. Because all domain names end at the root, which has a -null string for a label, these internal representations can use a length -byte of zero to terminate a domain name. - -By convention, domain names can be stored with arbitrary case, but -domain name comparisons for all present domain functions are done in a -case-insensitive manner, assuming an ASCII character set, and a high -order zero bit. This means that you are free to create a node with -label "A" or a node with label "a", but not both as brothers; you could -refer to either using "a" or "A". When you receive a domain name or - - - -Mockapetris [Page 7] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -label, you should preserve its case. The rationale for this choice is -that we may someday need to add full binary domain names for new -services; existing services would not be changed. - -When a user needs to type a domain name, the length of each label is -omitted and the labels are separated by dots ("."). Since a complete -domain name ends with the root label, this leads to a printed form which -ends in a dot. We use this property to distinguish between: - - - a character string which represents a complete domain name - (often called "absolute"). For example, "poneria.ISI.EDU." - - - a character string that represents the starting labels of a - domain name which is incomplete, and should be completed by - local software using knowledge of the local domain (often - called "relative"). For example, "poneria" used in the - ISI.EDU domain. - -Relative names are either taken relative to a well known origin, or to a -list of domains used as a search list. Relative names appear mostly at -the user interface, where their interpretation varies from -implementation to implementation, and in master files, where they are -relative to a single origin domain name. The most common interpretation -uses the root "." as either the single origin or as one of the members -of the search list, so a multi-label relative name is often one where -the trailing dot has been omitted to save typing. - -To simplify implementations, the total number of octets that represent a -domain name (i.e., the sum of all label octets and label lengths) is -limited to 255. - -A domain is identified by a domain name, and consists of that part of -the domain name space that is at or below the domain name which -specifies the domain. A domain is a subdomain of another domain if it -is contained within that domain. This relationship can be tested by -seeing if the subdomain's name ends with the containing domain's name. -For example, A.B.C.D is a subdomain of B.C.D, C.D, D, and " ". - -3.2. Administrative guidelines on use - -As a matter of policy, the DNS technical specifications do not mandate a -particular tree structure or rules for selecting labels; its goal is to -be as general as possible, so that it can be used to build arbitrary -applications. In particular, the system was designed so that the name -space did not have to be organized along the lines of network -boundaries, name servers, etc. The rationale for this is not that the -name space should have no implied semantics, but rather that the choice -of implied semantics should be left open to be used for the problem at - - - -Mockapetris [Page 8] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -hand, and that different parts of the tree can have different implied -semantics. For example, the IN-ADDR.ARPA domain is organized and -distributed by network and host address because its role is to translate -from network or host numbers to names; NetBIOS domains [RFC-1001, RFC- -1002] are flat because that is appropriate for that application. - -However, there are some guidelines that apply to the "normal" parts of -the name space used for hosts, mailboxes, etc., that will make the name -space more uniform, provide for growth, and minimize problems as -software is converted from the older host table. The political -decisions about the top levels of the tree originated in RFC-920. -Current policy for the top levels is discussed in [RFC-1032]. MILNET -conversion issues are covered in [RFC-1031]. - -Lower domains which will eventually be broken into multiple zones should -provide branching at the top of the domain so that the eventual -decomposition can be done without renaming. Node labels which use -special characters, leading digits, etc., are likely to break older -software which depends on more restrictive choices. - -3.3. Technical guidelines on use - -Before the DNS can be used to hold naming information for some kind of -object, two needs must be met: - - - A convention for mapping between object names and domain - names. This describes how information about an object is - accessed. - - - RR types and data formats for describing the object. - -These rules can be quite simple or fairly complex. Very often, the -designer must take into account existing formats and plan for upward -compatibility for existing usage. Multiple mappings or levels of -mapping may be required. - -For hosts, the mapping depends on the existing syntax for host names -which is a subset of the usual text representation for domain names, -together with RR formats for describing host addresses, etc. Because we -need a reliable inverse mapping from address to host name, a special -mapping for addresses into the IN-ADDR.ARPA domain is also defined. - -For mailboxes, the mapping is slightly more complex. The usual mail -address @ is mapped into a domain name by -converting into a single label (regardles of dots it -contains), converting into a domain name using the usual -text format for domain names (dots denote label breaks), and -concatenating the two to form a single domain name. Thus the mailbox - - - -Mockapetris [Page 9] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -HOSTMASTER@SRI-NIC.ARPA is represented as a domain name by -HOSTMASTER.SRI-NIC.ARPA. An appreciation for the reasons behind this -design also must take into account the scheme for mail exchanges [RFC- -974]. - -The typical user is not concerned with defining these rules, but should -understand that they usually are the result of numerous compromises -between desires for upward compatibility with old usage, interactions -between different object definitions, and the inevitable urge to add new -features when defining the rules. The way the DNS is used to support -some object is often more crucial than the restrictions inherent in the -DNS. - -3.4. Example name space - -The following figure shows a part of the current domain name space, and -is used in many examples in this RFC. Note that the tree is a very -small subset of the actual name space. - - | - | - +---------------------+------------------+ - | | | - MIL EDU ARPA - | | | - | | | - +-----+-----+ | +------+-----+-----+ - | | | | | | | - BRL NOSC DARPA | IN-ADDR SRI-NIC ACC - | - +--------+------------------+---------------+--------+ - | | | | | - UCI MIT | UDEL YALE - | ISI - | | - +---+---+ | - | | | - LCS ACHILLES +--+-----+-----+--------+ - | | | | | | - XX A C VAXA VENERA Mockapetris - -In this example, the root domain has three immediate subdomains: MIL, -EDU, and ARPA. The LCS.MIT.EDU domain has one immediate subdomain named -XX.LCS.MIT.EDU. All of the leaves are also domains. - -3.5. Preferred name syntax - -The DNS specifications attempt to be as general as possible in the rules - - - -Mockapetris [Page 10] - -RFC 1034 Domain Concepts and Facilities November 1987 - - -for constructing domain names. The idea is that the name of any -existing object can be expressed as a domain name with minimal changes. -However, when assigning a domain name for an object, the prudent user -will select a name which satisfies both the rules of the domain system -and any existing rules for the object, whether these rules are published -or implied by existing programs. - -For example, when naming a mail domain, the user should satisfy both the -rules of this memo and those in RFC-822. When creating a new host name, -the old rules for HOSTS.TXT should be followed. This avoids problems -when old software is converted to use domain names. - -The following syntax will result in fewer problems with many -applications that use domain names (e.g., mail, TELNET). - - ::= | " " - - ::=
    diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index e9b3fb62..729c19ac 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -77,6 +77,10 @@ if ($arch_db !== $arch) { // reset playerID if architectureID not match. This condition "fire" another first-run process $playerid_db = ''; } +// check git branch +$gitbranch = sysCmd("git branch | grep \"*\" | cut -d ' ' -f 2"); +runelog('GIT BRANCH: ', $gitbranch[0]); +$redis->hSet('git', 'branch', $gitbranch[0]); if ($playerid_db === '') { // RUNEAUDIO FIRST RUN PROCESS --- // runelog('>>>>>>RUNEAUDIO FIRST RUN PROCESS ---'); From bf295247637c37179cf8bc9b4c5eb55338064e73 Mon Sep 17 00:00:00 2001 From: Orion1 Date: Sat, 13 Dec 2014 17:42:36 +0100 Subject: [PATCH 17/80] fix on MPD Advanced Mode and MPD reset config functions --- app/libs/runeaudio.php | 32 +++++++++++++++++++++++++------- command/rune_SY_wrk | 3 ++- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/app/libs/runeaudio.php b/app/libs/runeaudio.php index 473f57a9..1e4b1f60 100755 --- a/app/libs/runeaudio.php +++ b/app/libs/runeaudio.php @@ -1951,6 +1951,13 @@ function wrk_kernelswitch($redis, $args) function wrk_mpdconf($redis, $action, $args = null, $jobID = null) { +// check if we are in "advanced mode" (manual edit mode) +if ($action === 'reset') { + $redis->set('mpdconf_advanced', 0); + $mpdconf_advanced = 0; +} else { + $mpdconf_advanced = $redis->get('mpdconf_advanced'); +} // set mpd.conf file header $header = "###################################\n"; $header .= "# Auto generated mpd.conf file\n"; @@ -2141,13 +2148,24 @@ function wrk_mpdconf($redis, $action, $args = null, $jobID = null) } $output .="\n"; // debug - runelog('raw mpd.conf', $output, __FUNCTION__); - // write mpd.conf file - $fh = fopen('/etc/mpd.conf', 'w'); - fwrite($fh, $output); - fclose($fh); - // update hash - $redis->set('mpdconfhash', md5_file('/etc/mpd.conf')); + // runelog('raw mpd.conf', $output, __FUNCTION__); + // check if mpd.conf was modified outside RuneUI (advanced mode) + runelog('mpd.conf advanced state', $mpdconf_advanced); + if ($mpdconf_advanced !== '1' OR $mpdconf_advanced === '') { + if ($mpdconf_advanced !== '') { + runelog('mpd.conf advanced mode OFF'); + } else { + runelog('mpd.conf advanced mode RESET STATE'); + } + // write mpd.conf file + $fh = fopen('/etc/mpd.conf', 'w'); + fwrite($fh, $output); + fclose($fh); + // update hash + $redis->set('mpdconfhash', md5_file('/etc/mpd.conf')); + } else { + runelog('mpd.conf advanced mode ON'); + } break; case 'update': foreach ($args as $param => $value) { diff --git a/command/rune_SY_wrk b/command/rune_SY_wrk index 729c19ac..98dc3251 100755 --- a/command/rune_SY_wrk +++ b/command/rune_SY_wrk @@ -485,6 +485,7 @@ $redis->pconnect('/tmp/redis.sock'); } if ($job->action === 'reset') { wrk_mpdconf($redis, 'reset'); + wrk_mpdconf($redis, 'restart'); } if ($job->action === 'switchao') { wrk_mpdconf($redis, 'switchao', $job->args, $jobID); @@ -500,7 +501,7 @@ $redis->pconnect('/tmp/redis.sock'); wrk_mpdconf($redis, 'stop'); // write mpd.conf file $fh = fopen('/etc/mpd.conf', 'w'); - fwrite($fh, $job['args']); + fwrite($fh, $job->args); fclose($fh); wrk_mpdconf($redis, 'start'); $redis->sRem('w_lock', $jobID); From 3003d8113eef27d4efaba294c143400ea95848ae Mon Sep 17 00:00:00 2001 From: ACXgit Date: Sat, 13 Dec 2014 18:32:28 +0100 Subject: [PATCH 18/80] Better queue buffering and centering --- app/templates/playback.php | 8 ++-- assets/css/runeui.css | 2 +- assets/js/runeui.js | 78 ++++++++++++++++++++++------------ assets/js/runeui.min.js | 4 +- assets/less/runeui-custom.less | 5 ++- 5 files changed, 60 insertions(+), 37 deletions(-) diff --git a/app/templates/playback.php b/app/templates/playback.php index 100928dd..0ae52849 100755 --- a/app/templates/playback.php +++ b/app/templates/playback.php @@ -92,11 +92,9 @@ 2143 entries
    -
    -
      - -
    -
    + + +
    diff --git a/assets/css/runeui.css b/assets/css/runeui.css index bc931693..9ba5bb18 100644 --- a/assets/css/runeui.css +++ b/assets/css/runeui.css @@ -7,4 +7,4 @@ * * Copyright 2013 bootstrap-select * Licensed under the MIT license - */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:49px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file + */.bootstrap-select.btn-group,.bootstrap-select.btn-group[class*="span"]{float:none;display:inline-block;margin-bottom:10px;margin-left:0}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:0}.bootstrap-select.form-control{padding:0;border:none}.bootstrap-select.btn-group .pull-right,.row-fluid .bootstrap-select.btn-group .pull-right,.bootstrap-select.btn-group[class*="span"] .pull-right,.row-fluid .bootstrap-select.btn-group[class*="span"] .pull-right{float:right}.input-append .bootstrap-select.btn-group{margin-left:-1px}.input-prepend .bootstrap-select.btn-group{margin-right:-1px}.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]){width:250px}.bootstrap-select{width:220px\0}.bootstrap-select.form-control:not([class*="span"]){width:100%}.bootstrap-select>.btn{width:100%}.error .bootstrap-select .btn{border:1px solid #b94a48}.dropdown-menu{z-index:2000}.bootstrap-select.show-menu-arrow.open>.btn{z-index:2051}.bootstrap-select .btn:focus{outline:thin dotted #333333 !important;outline:5px auto -webkit-focus-ring-color !important;outline-offset:-2px}.bootstrap-select.btn-group .btn .filter-option{overflow:hidden;position:absolute;left:12px;right:25px;text-align:left}.bootstrap-select.btn-group .btn .caret{position:absolute;top:50%;right:12px;margin-top:-2px;vertical-align:middle}.bootstrap-select.btn-group>.disabled,.bootstrap-select.btn-group .dropdown-menu li.disabled>a{cursor:not-allowed}.bootstrap-select.btn-group>.disabled:focus{outline:none !important}.bootstrap-select.btn-group[class*="span"] .btn{width:100%}.bootstrap-select.btn-group .dropdown-menu{min-width:100%;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.bootstrap-select.btn-group .dropdown-menu.inner{position:static;border:0;padding:0;margin:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none}.bootstrap-select.btn-group .dropdown-menu dt{display:block;padding:3px 20px;cursor:default}.bootstrap-select.btn-group .div-contain{overflow:hidden}.bootstrap-select.btn-group .dropdown-menu li{position:relative}.bootstrap-select.btn-group .dropdown-menu li>a.opt{position:relative;padding-left:35px}.bootstrap-select.btn-group .dropdown-menu li>a{cursor:pointer}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark{display:inline-block;position:absolute;right:15px;margin-top:2.5px}.bootstrap-select.btn-group .dropdown-menu li a i.check-mark{display:none}.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text{margin-right:34px}.bootstrap-select.btn-group .dropdown-menu li small{padding-left:0.5em}.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:hover small,.bootstrap-select.btn-group .dropdown-menu li:not(.disabled)>a:focus small{color:#64b1d8;color:rgba(255,255,255,0.4)}.bootstrap-select.btn-group .dropdown-menu li>dt small{font-weight:normal}.bootstrap-select.show-menu-arrow .dropdown-toggle:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #CCC;border-bottom-color:rgba(0,0,0,0.2);position:absolute;bottom:-4px;left:9px;display:none}.bootstrap-select.show-menu-arrow .dropdown-toggle:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid white;position:absolute;bottom:-4px;left:10px;display:none}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before{bottom:auto;top:-3px;border-top:7px solid #ccc;border-bottom:0;border-top-color:rgba(0,0,0,0.2)}.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after{bottom:auto;top:-3px;border-top:6px solid #ffffff;border-bottom:0}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before{right:12px;left:auto}.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after{right:13px;left:auto}.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:before,.bootstrap-select.show-menu-arrow.open>.dropdown-toggle:after{display:block}.mobile-device{position:absolute;top:0;left:0;display:block !important;width:100%;height:100% !important;opacity:0}.bootstrap-select.fit-width{width:auto !important}.bootstrap-select.btn-group.fit-width .btn .filter-option{position:static}.bootstrap-select.btn-group.fit-width .btn .caret{position:static;top:auto;margin-top:-1px}.control-group.error .bootstrap-select .dropdown-toggle{border-color:#b94a48}.bootstrap-select-searchbox{padding:4px 8px}.switch-toggle a,.switch-light span span{display:none}@media only screen{.switch-light{display:block;max-width:120px;height:40px;position:relative;overflow:visible;padding:0;background:#34495e;border-radius:6px}.switch-light:hover{cursor:pointer}.switch-light *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.switch-light a{display:block;-webkit-transition:all .2s ease-out;-moz-transition:all .2s ease-out;transition:all .2s ease-out}.switch-light label,.switch-light>span{line-height:40px;vertical-align:middle}.switch-light input:focus~a,.switch-light input:focus+label{outline:1px dotted #888888}.switch-light label{position:relative;top:static;right:static;left:static;display:block;width:100%;z-index:3}.switch-light input{position:absolute;top:static;right:static;left:static;display:inherit;width:auto;z-index:5;opacity:0}.switch-light input:checked~a{right:0%}.switch-light>span{position:absolute;top:static;right:static;left:-100px;display:inherit;width:100%;z-index:auto;margin:0;padding-right:100px;text-align:left}.switch-light>span span{position:absolute;top:0;right:static;left:0;display:block;width:50%;z-index:5;margin-left:100px;text-align:center}.switch-light>span span:last-child{left:50%}.switch-light a{position:absolute;top:0;right:50%;left:static;display:block;width:50%;z-index:4;height:100%;padding:0}}@media only screen and (-webkit-max-device-pixel-ratio:2) and (max-device-width:1280px){.switch-light,.switch-toggle{-webkit-animation:webkitSiblingBugfix infinite 1s}}@-webkit-keyframes webkitSiblingBugfix{from{-webkit-transform:translate3d(0, 0, 0)}to{-webkit-transform:translate3d(0, 0, 0)}}.csspinner:before{content:none;z-index:1;position:absolute;top:0;left:0;display:none;height:100%;width:100%;opacity:0.6}.csspinner:after{z-index:2;content:"";height:50px;width:50px;position:absolute;top:50%;left:50%;margin:-25px 0 0 -25px;transition:all .75s ease 0s;-webkit-transition:all .75s ease 0s;border-radius:100%;border-top:6px solid #555;animation:standard .75s infinite linear;-webkit-animation:standard .75s infinite linear}@-webkit-keyframes standard{from{-webkit-transform:rotate(0deg)}to{-webkit-transform:rotate(360deg)}}@keyframes standard{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}.csspinner.double-up:after{border-right:6px solid #e74c3c;border-top:6px double #e74c3c;border-left:6px double #e74c3c;border-bottom:6px double #e74c3c}.csspinner.duo:after{border-right:6px solid #e0e7ee;border-left:6px solid #34495e;border-top:6px solid #34495e;border-bottom:6px solid #34495e}html,body{height:100%}#wrap{margin:0 auto -180px;min-height:100%;height:auto !important;height:100%}#section-index .container{padding-top:40px;padding-bottom:40px}.push,#footer{height:180px;overflow:hidden}.container{padding-top:60px;padding-bottom:60px}#container{height:100%}.txtsx{text-align:left}.rbg{background:#ff0000}.rel{position:relative}.txtdx{text-align:right}.floatdx{float:right}.red{color:#f00}.bbg{background:#0000ff}.uppercase{text-transform:uppercase}.mid{margin-bottom:-3px}.txtmid{text-align:center}.justified{text-align:justify}.clear{clear:both}.green{color:#0f0}.gbg{background:#00ff00}.floatsx{float:left}.logo{display:none}#menu-top{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;top:0}#menu-top .dropdown{display:block;float:right;height:40px;line-height:40px;margin:0 20px 0 0}#menu-top .dropdown .dropdown-menu i{display:inline-block;width:1.28571em;line-height:16px;margin:0 10px 0 5px;font-size:14px;text-align:center}#menu-top .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;right:-20px;min-width:160px;top:100%;z-index:1000}#menu-top .home{padding:0 20px;line-height:40px;font-weight:bold}#menu-top a{text-decoration:none;color:#e0e7ee}#menu-top a:hover,#menu-top a:focus{text-decoration:none;outline:none;color:#e0e7ee}#menu-top .dropdown-menu >li:first-child >a,#context-menus .dropdown-menu >li:first-child >a{border-top:1px solid #222f3d}#menu-top .dropdown-menu >li >a,#context-menus .dropdown-menu >li >a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #222f3d}#menu-top .dropdown-menu >li >a:hover,#menu-top .dropdown-menu >li >a:focus,#menu-top .dropdown-menu >li.active >a,#context-menus .dropdown-menu >li >a:hover,#context-menus .dropdown-menu >li.active >a{background:#0095d8}#menu-settings{display:block;height:40px;line-height:40px;margin:0 -30px 0 0;padding:0 30px}#context-menus .dropdown-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0;padding-right:20px;min-width:160px}#context-menus .dropdown-menu>li>a{border-left:1px solid #222f3d;border-right:1px solid #222f3d}#context-menus .dropdown-menu a{text-decoration:none;color:#e0e7ee}#context-menus .dropdown-menu a:hover,#context-menus .dropdown-menu a:focus{text-decoration:none;outline:none;color:#e0e7ee}#context-menus i{display:inline-block;width:16px;text-align:center}.right-floating-menu{float:right;position:absolute;left:auto;background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;padding:0}.fixed-menu{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000}#menu-bottom{position:fixed;left:0;right:0;height:40px;line-height:40px;background:#34495e;color:#e0e7ee;z-index:1000;bottom:0}#menu-bottom a{display:block;float:left;width:33.333%;line-height:40px;margin:0;padding:0;background:#34495e;font-size:14px;text-decoration:none;text-align:center;color:#e0e7ee}#menu-bottom ul{display:block;margin:0 auto;padding:0}#menu-bottom li.active a{background:#0095d8}#menu-bottom li{display:block;margin:0;padding:0}#menu-bottom i{width:14px;line-height:16px;margin-right:5px;font-size:14px}#menu-bottom a:hover,#menu-bottom a:focus{text-decoration:none;outline:none;color:#e0e7ee}#open-playback a{background:#2b3c4e}#playback{padding:40px 0}#playback .container-fluid{max-width:1140px;padding-top:20px;padding-bottom:20px;text-align:center}#currentartist,#currentsong,#currentalbum,#format-bitrate,#elapsed,#countdown-display{display:block}#currentsong{font-size:30px;font-weight:bold;color:#0095d8;line-height:34px}#currentsong .notag{color:#34495e}#currentartist,#currentalbum{font-size:18px}#currentartist .notag,#currentalbum .notag{color:#34495e}#currentalbum{margin-bottom:20px}#overlay-playsource-open{display:inline-block;margin:0 auto}#overlay-playsource-open:hover{cursor:pointer}#overlay-playsource-open:hover button{background-color:#222f3d}#playlist-position,#format-bitrate{color:#587ca0}#playlist-position button{margin:-2px 5px 2px 0}.knobs{margin-top:30px}#time-knob,#volume-knob{position:relative;text-align:center}#time-knob>div:first-child,#volume-knob>div:first-child{margin:10px auto 20px}#time-knob>div:first-child:hover,#volume-knob>div:first-child:hover,#time-knob>div:first-child:focus,#volume-knob>div:first-child:focus{cursor:pointer}#time-knob{margin-bottom:30px}#volume-knob{margin-top:30px}#countdown-display{position:absolute;top:115px;left:50%;width:150px;margin:-19px 0 0 -75px;line-height:38px;font-size:38px;font-weight:bold;text-align:center}#total{position:absolute;top:115px;left:50%;width:100px;margin:23.4px 0 0 -50px;line-height:14px;font-size:14px;font-family:"Lucida Grande",Tahoma,Verdana,Arial,sans-serif;font-weight:normal;text-align:center}#time,#volume{background:#000;border:none;color:#000}.volume .btn-toolbar{margin-top:20px}.volume .btn.disabled,.volume .btn[disabled]{margin:0}.volume.nomixer{padding-top:0}#volume{font-family:inherit !important}#volume:hover,#volume:focus{cursor:default}.playback-controls{display:block;position:absolute;top:0;left:0;width:180px;margin:0;text-align:center}.countdown_holding span{color:#888}.countdown_row{clear:both;width:100%;padding:0px 2px;text-align:center}#cover-art{display:block;position:relative;width:100%;max-width:250px;height:auto;margin:10px auto 11px;background:#111 url(../img/cover-default.png) no-repeat center center;background-size:100% 100%;border:2px solid #34495e;border-radius:6px}.btn-cmd:focus{outline:none}#db-level-up,#db-search-results,#pl-filter-results{height:40px;margin:0 0 0 -10px;padding:7px 12px 5px;font-size:16px;font-weight:normal;cursor:pointer;border-radius:0;color:#e0e7ee}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:active,#db-search-results:active,#pl-filter-results:active,#db-level-up[disabled],#db-search-results[disabled],#pl-filter-results[disabled],fieldset[disabled] #db-level-up,fieldset[disabled] #db-search-results,fieldset[disabled] #pl-filter-results{background-color:transparent;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}#db-level-up,#db-search-results,#pl-filter-results,#db-level-up:hover,#db-search-results:hover,#pl-filter-results:hover,#db-level-up:focus,#db-search-results:focus,#pl-filter-results:focus,#db-level-up:active,#db-search-results:active,#pl-filter-results:active{border-color:transparent;text-decoration:none;background-color:transparent;color:#e0e7ee}#db-level-up i,#db-search-results i,#pl-filter-results i{margin:0 11px 0 2px}#pl-count{height:40px;line-height:40px;margin:0 0 0 3px;font-size:14px;font-weight:normal;cursor:pointer;border-radius:0;color:#587ca0}.btnlist{position:fixed;left:0;right:0;display:block;width:auto;height:40px;padding:0;background:#172029;-webkit-border-radius:0px;-moz-border-radius:0px;border-radius:0px;z-index:999}.btnlist :focus{outline:none}.btnlist a{font-size:16px;text-decoration:none;color:#e0e7ee}.btnlist a:hover,.btnlist a:focus{text-decoration:none;outline:none;color:#e0e7ee}.btnlist.btnlist-bottom .btn{margin-top:5px;padding:0 10px;font-size:20px}.pl-prevPage,.db-prevPage,.pl-firstPage,.db-firstPage,.btnlist-top{top:40px;padding:0 10px}.pl-nextPage,.db-nextPage,.pl-lastPage,.db-lastPage,.btnlist-bottom{bottom:40px;padding:0 10px}.keyword{color:#0095d8}.list-main{display:block;margin:0;padding:0;list-style:none}.list-li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.list-span{display:block;font-size:12px;font-weight:normal;color:#587ca0}.list-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}.list-active{color:#e0e7ee;background:#0095d8}#database-entries{display:block;margin:0;padding:0;list-style:none}#database-entries .search-results .db-entry{color:#8FA7BF}#database-entries .search-results i{color:#ddd}#database-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries li:before,#database-entries li:after{content:" ";display:table}#database-entries li:after{clear:both}#database-entries .db-icon,#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:none}#database-entries .db-entry{margin-right:70px;height:100%;line-height:19px;padding:5px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#database-entries .active,#database-entries .active:hover,#database-entries .active:focus{color:#e0e7ee;background:#0095d8}#database-entries .active .bl,#database-entries .active:hover .bl,#database-entries .active:focus .bl{color:#34495e}#database-entries .db-folder,#database-entries .db-album,#database-entries .db-artist{line-height:49px}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{display:block;padding-left:10px}#database-entries .db-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#database-entries .sn{display:block;padding:5px 0 0 10px}#database-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#database-entries .sn span.infinite{font-size:28px}#database-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#database-entries #webradio-add,#database-entries #album-add{background:#10161c}#database-entries #webradio-add .sn,#database-entries #album-add .sn{color:#0095d8}#database-entries #webradio-add i,#database-entries #album-add i,#database-entries #webradio-add strong,#database-entries #album-add strong{color:#e0e7ee}#database-entries #webradio-add strong,#database-entries #album-add strong{font-weight:inherit}#playlist-entries{display:block;margin:0;padding:0;list-style:none}#playlist-entries li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li:before,#playlist-entries li:after{content:" ";display:table}#playlist-entries li:after{clear:both}#playlist-entries li .fa-microphone{margin-right:8px}#playlist-entries .active,#playlist-entries .active:hover,#playlist-entries .active:focus{color:#e0e7ee;background:#0095d8}#playlist-entries .active .bl,#playlist-entries .active:hover .bl,#playlist-entries .active:focus .bl{color:#34495e}#playlist-entries .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#playlist-entries span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#playlist-entries .sn{display:block;padding:5px 0 0 10px}#playlist-entries .sn span{padding-left:10px;font-size:14px;font-style:normal;color:#34495e}#playlist-entries .sn span.infinite{font-size:28px}#playlist-entries .bl{display:block;padding:0 50px 0 10px;font-size:12px;color:#587ca0}#playlist-entries-container{position:relative}#pl-editor{display:block;margin:0;padding:0;list-style:none}#pl-editor li{display:block;height:50px;line-height:19px;border-bottom:1px solid #172029;font-size:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor li:before,#pl-editor li:after{content:" ";display:table}#pl-editor li:after{clear:both}#pl-editor .active,#pl-editor .active:hover,#pl-editor .active:focus{color:#e0e7ee;background:#0095d8}#pl-editor .pl-folder{line-height:49px}#pl-editor .pl-folder span{display:block;padding-left:10px}#pl-editor .fa-list-ol{display:none}#pl-editor .pl-action{float:right;display:block;position:relative;width:50px;height:49px;line-height:49px;font-size:18px;font-weight:normal;text-align:center;color:#e0e7ee;text-decoration:none}#pl-editor span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#db-browse{margin:0;width:200px}#db-browse .dropdown{display:block;height:40px;line-height:40px;margin:0 20px 0 0}#db-browse .dropdown-menu{background:transparent;border:none;border-radius:0px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);list-style:none outside none;margin:0;min-width:100px;padding:0;border-top:1px solid #000;border-left:1px solid #000;border-right:1px solid #000;position:absolute;top:100%;z-index:1000}#db-browse .dropdown-menu>li>a{line-height:40px;margin:0;padding:0 10px;background:#34495e;border-bottom:1px solid #000;color:#e0e7ee}#browse-mode{display:none}#panel-sx .btn.disabled,#panel-dx .btn.disabled,#panel-sx .btn[disabled],#panel-dx .btn[disabled]{background-color:#34495e;color:white}#db-controls,#pl-controls{float:right}#pl-manage.pl-manage-spotify #pl-manage-list,#pl-manage.pl-manage-spotify #pl-manage-save{display:none}#db-currentpath,#pl-currentpath{line-height:40px}#db-currentpath i,#pl-currentpath i{margin:0 3px 0 2px}#db-browse .dropdown-menu >li >a:hover,#db-browse .dropdown-menu >li >a:focus,#db-browse .dropdown-menu >li.active >a{background:#0095d8}#db-search,#pl-search{display:block;white-space:nowrap;float:right;max-width:180px;margin:4px 0 0 20px;z-index:1001}#db-search input,#pl-search input{display:inline-block;height:32px;margin:0;border-bottom-right-radius:0;border-top-right-radius:0}#playlist,#database{padding:80px 0}.sortable-ghost{background:#222f3d}#home-blocks{margin:0 0 20px}.home-block,.empty-block{display:block;position:relative;margin:10px 0;padding:20px 30px;background:#10161c;border-radius:6px;color:#587ca0;text-align:center}.home-block i,.empty-block i{display:inline-block;width:40px;height:40px;line-height:40px;font-size:40px;text-align:center;color:#587ca0}.home-block h3,.empty-block h3{margin-top:10px;color:#e0e7ee;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.home-block .home-action,.empty-block .home-action{display:block;position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px}.home-block:hover,.home-block:focus{cursor:pointer;background:#222f3d;text-decoration:none;outline:none;color:#587ca0}.home-block .home-block-remove{position:absolute;top:0;bottom:0;left:0;right:0;width:100%;height:100%;background:rgba(0,0,0,0.5)}.home-block .home-block-remove span{position:absolute;top:0;right:0;width:40px;height:40px;line-height:40px;background:#34495e;border-radius:6px;color:#e0e7ee;font-size:30px;font-weight:bold}.boxed{padding:15px 20px;background:#19232d;border-radius:6px}.boxed-group{margin:0 -15px 15px;padding:10px 15px 5px;background:#19232d}.boxed-group .form-group:last-child{margin-bottom:0}.form-actions{padding:10px 0 20px}.manual-edit-confirm{margin-bottom:20px}.optional{position:relative}.disabler{display:block;position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;background:#000;opacity:.7;filter:alpha(opacity=70);z-index:999}.disabler:hover{cursor:not-allowed}.disabled .disabled .disabler{background:transparent}.button-list .btn{overflow:hidden;text-overflow:ellipsis}.button-list .btn span{font-size:13px}.button-list .btn strong{font-weight:normal;text-transform:uppercase}.info-table{width:100%}.info-table th,.info-table td{line-height:30px;vertical-align:top}.info-table th{padding-right:30px;font-weight:normal;text-align:right;color:#587ca0}.info-table td{font-size:16px}#mpdconf{max-width:100%;background:#1a1a1a;font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:15px;color:#7795b4}.fa.fa-wifi{display:inline-block;width:30px;height:1px;-o-transform:rotate(-45deg);-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-ms-filter:"progid:DXImageTransform.Microsoft.Matrix(SizingMethod='auto expand', M11=-0.7071067811865476, M12=0.7071067811865475, M21=0.7071067811865475, M22=0.7071067811865476)"}.fa.fa-wifi.sx{margin-right:15px}#wifi-signal-strength{margin:6px 0}#modal-sysinfo p{color:#587ca0}.container.help,.container.credits{font-size:16px;line-height:24px}.container.help .help-block,.container.credits .help-block{display:inline}#release-version{font-size:20px}#license{line-height:20px;font-size:13px;color:#587ca0}#form-paypal{text-align:center}.social-buttons{text-align:center}.social-buttons a{margin:0 2px 6px;padding:8px 10px}.social-buttons a i{display:inline-block;width:26px;font-size:26px}#loader{position:fixed;top:0;left:0;margin:0;padding:0;text-align:center;width:100%;height:100%;z-index:99999}#loadercontent{position:absolute;top:50%;left:50%;margin:-70px 0 0 -50px;width:100px;height:120px;line-height:40px;text-align:center;text-transform:uppercase;color:#999}#loadercontent i{display:block;line-height:100px;font-size:100px}#loaderbg{position:absolute;top:0;left:0;margin:0;padding:0;text-align:center;background:rgba(0,0,0,0.8);width:100%;height:100%}.ui-pnotify{position:absolute;height:auto;z-index:9999}.ui-pnotify .alert{background:#0095d8;border:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert h4{margin:0 0 2px;font-size:16px;font-weight:bold;text-transform:uppercase;color:#e0e7ee;text-shadow:none}.ui-pnotify .alert span{margin-top:2px}.ui-pnotify .alert .ui-pnotify-sticker{margin-right:3px}.ui-pnotify .alert,.ui-pnotify .alert h4{color:#e0e7ee;text-shadow:none}.ui-pnotify .ui-pnotify-shadow{-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.ui-pnotify .ui-pnotify-container{background-position:0 0;padding:10px 15px 8px;height:100%;margin:0}html>body>.ui-pnotify{position:fixed}.ui-pnotify-sharp{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0}.ui-pnotify-closer,.ui-pnotify-sticker{float:right;margin-left:.2em}.ui-pnotify-title{display:block;margin-bottom:.4em}.ui-pnotify-text{display:block}.ui-pnotify-icon,.ui-pnotify-icon span{display:block;float:left;margin-right:.2em}select.selectpicker{height:43px;margin-bottom:10px}.form-search .bootstrap-select.btn-group,.form-inline .bootstrap-select.btn-group,.form-horizontal .bootstrap-select.btn-group{margin-bottom:10px}.bootstrap-select .dropdown-menu{background:#34495e}.bootstrap-select .dropdown-menu>li>a{padding:8px 20px;color:#e0e7ee}.bootstrap-select .dropdown-menu>li>a:hover,.bootstrap-select .dropdown-menu>li>a:focus{background-color:#0095d8;color:#e0e7ee}.bootstrap-select .dropdown-menu>li.selected>a{background-color:#222f3d;outline:none}.has-switch{border-radius:6px;border:2px solid #34495e;overflow:hidden}.has-switch span.switch-left{border-bottom-left-radius:0;border-top-left-radius:0}.has-switch span.switch-right{color:#e0e7ee;background:#000}.switch-block{max-width:100%}#overlay-social,#overlay-playsource{position:fixed;width:100%;height:100%;top:0;left:0;background:#10161c}#overlay-social nav,#overlay-playsource nav{text-align:center;position:relative;top:50%;height:60%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}#overlay-social ul,#overlay-playsource ul{list-style:none;padding:0;margin:0 auto;display:inline-block;height:340px;position:relative}#overlay-social ul li,#overlay-playsource ul li{display:block;height:60px;line-height:60px;margin:0;padding:0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#overlay-social ul li span,#overlay-playsource ul li span{font-size:30px;font-weight:300}#overlay-social ul li:last-child,#overlay-playsource ul li:last-child{height:20px;line-height:20px}#overlay-social ul li a,#overlay-playsource ul li a{font-size:16px;text-align:right;border:0}#overlay-social ul li a.share-twitter,#overlay-playsource ul li a.share-twitter{background:#55ACEE}#overlay-social ul li a.share-twitter:hover,#overlay-playsource ul li a.share-twitter:hover,#overlay-social ul li a.share-twitter:focus,#overlay-playsource ul li a.share-twitter:focus{background:#2795e9}#overlay-social ul li a.share-facebook,#overlay-playsource ul li a.share-facebook{background:#3B5998}#overlay-social ul li a.share-facebook:hover,#overlay-playsource ul li a.share-facebook:hover,#overlay-social ul li a.share-facebook:focus,#overlay-playsource ul li a.share-facebook:focus{background:#2d4373}#overlay-social ul li a.share-google-plus,#overlay-playsource ul li a.share-google-plus{background:#DD4B39}#overlay-social ul li a.share-google-plus:hover,#overlay-playsource ul li a.share-google-plus:hover,#overlay-social ul li a.share-google-plus:focus,#overlay-playsource ul li a.share-google-plus:focus{background:#c23321}#overlay-social ul li a i,#overlay-playsource ul li a i{display:block;float:left;margin:-1px 20px 0 -5px;font-size:26px;text-align:center}#overlay-social ul li a span,#overlay-playsource ul li a span{padding-right:5px;font-size:12px}#overlay-social ul li a.inactive span,#overlay-playsource ul li a.inactive span{color:#587ca0}.overlay-scale{visibility:hidden;opacity:0;-webkit-transform:scale(.9);transform:scale(.9);-webkit-transition:-webkit-transform .2s,opacity .2s,visibility 0s .2s;transition:transform 0.2s, opacity 0.2s, visibility 0s 0.2s}.overlay-scale.open{visibility:visible;opacity:1;-webkit-transform:scale(1);transform:scale(1);-webkit-transition:-webkit-transform .4s,opacity .4s;transition:transform 0.4s, opacity 0.4s}.overlay-scale .btn-link:hover,.overlay-scale .btn-link:focus{text-decoration:none}#playsource-airplay{background:#666;outline:none}#playsource-airplay:hover,#playsource-airplay:focus{background:#4d4d4d;cursor:default}#playsource-dlna{background:#4CA943;outline:none}#playsource-dlna:hover,#playsource-dlna:focus{background:#3c8435;cursor:default}#playsource-mpd{background:#003D88}#playsource-mpd:hover,#playsource-mpd.inactive:hover,#playsource-mpd:focus{background:#002655}#playsource-spotify{background:#81b900}#playsource-spotify:hover,#playsource-spotify.inactive:hover,#playsource-spotify:focus{background:#5d8600}#playsource-airplay.inactive,#playsource-dlna.inactive,#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive,#playsource-spotify.inactive{opacity:0.5;background:#222f3d}#playsource-mpd.inactive:hover,#playsource-spotify.inactive:hover{opacity:1}#playsource-mpd.inactive:hover span,#playsource-spotify.inactive:hover span{color:#e0e7ee}#player-airplay.inactive:hover,#player-dlna.inactive:hover{cursor:default}#spinner-db,#spinner-pl{position:fixed;top:50%;left:50%;width:50px;height:50px;margin:-20px 0 0 -25px;z-index:1001}.jamendo-cover{float:left;height:33px;margin:8px}#section-sources,#section-network,#section-settings{animation:bugfix infinite 1s;-moz-animation:bugfix infinite 1s;-webkit-animation:bugfix infinite 1s;-o-animation:bugfix infinite 1s;-ms-animation:bugfix infinite 1s}@keyframes bugfix{from{padding:0}to{padding:0}}@-moz-keyframes bugfix{from{padding:0}to{padding:0}}@-webkit-keyframes bugfix{from{padding:0}to{padding:0}}@-o-keyframes bugfix{from{padding:0}to{padding:0}}@-ms-keyframes bugfix{from{padding:0}to{padding:0}}.guru{border:2px solid #c00;padding:1em;color:#c00;text-align:center;font-family:courier, monospace;font-size:18px;overflow:hidden;margin:50px 0;animation:guru 2s steps(1, end) infinite;-webkit-animation:guru 2s steps(2, end) infinite}@keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}@-webkit-keyframes guru{0%{border:2px solid transparent}50%{border:2px solid #c00}100%{border:2px solid transparent}}.no-selectable{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}h1,h2{font-weight:300;text-transform:uppercase}.fa.sx{width:16px;margin-right:10px}.fa.dx{width:16px;margin-left:10px}.btn{border:medium none}.btn-primary{text-transform:uppercase}.btn-lg,.btn-group-lg>.btn{padding:11px 19px;font-size:16px;line-height:1.33;border-radius:6px}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{background:#222f3d}label{font-weight:normal}.form-control{border:2px solid #34495e;border-radius:6px;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#000}.help-block,.help-inline{color:#587ca0;font-size:13px}.help-block strong,.help-inline strong{color:#7795b4}.modal-content{border:5px solid #2b3c4e;border:5px solid #34495e;-webkit-box-shadow:none;box-shadow:none;-webkit-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);-moz-box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0);box-shadow:none,0 0 0 rgba(0,0,0,0),0 0 0 rgba(0,0,0,0)}.modal-backdrop.in{opacity:.8;filter:alpha(opacity=80)}.modal-header .close{font-size:35px;color:#34495e;text-shadow:none;opacity:1;filter:alpha(opacity=100)}.modal-header .close:hover,.modal-header .close:focus{color:#e0e7ee;opacity:1;filter:alpha(opacity=100)}.dropdown-menu{font-size:15px}select{visibility:hidden}fieldset{margin-bottom:20px}input.parsley-success,textarea.parsley-success,select.parsley-success{color:#468847 !important;border-color:#468847 !important}input.parsley-error,textarea.parsley-error,select.parsley-error{color:#B94A48 !important;border-color:#B94A48 !important}ul.parsley-error-list{font-size:11px;margin:2px;list-style-type:none}ul.parsley-error-list li{line-height:16px}@media (min-width:480px){.logo{display:inline;margin:-2px 5px 0 -5px}#menu-top .playback-controls{left:50%;width:180px;margin:0 0 0 -90px}#menu-bottom li a{font-size:16px}#menu-bottom li a i{margin-right:10px}#database-entries li{font-size:18px}#database-entries li:hover{cursor:pointer;background:#10161c}#database-entries .db-icon{display:block;float:left;width:24px;height:44px;margin-left:8px;padding-top:9px;color:#34495e;text-align:center}#database-entries .fa-folder-open,#database-entries .fa-hdd-o,#database-entries .fa-dot-circle-o,#database-entries .fa-user,#database-entries .fa-tags{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#database-entries .icon-root{color:#e0e7ee}#database-entries .db-folder span,#database-entries .db-album span,#database-entries .db-artist span{padding:0}#database-entries .db-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#database-entries .active .db-action:hover{color:#e0e7ee}#playlist-entries li{font-size:18px}#playlist-entries li:hover{cursor:pointer;background:#10161c}#playlist-entries li:before{display:block;float:left;width:24px;height:42px;margin:9px 0 0 8px;text-align:center;content:"\f001";font-family:"FontAwesome";color:#34495e;font-size:18px}#playlist-entries.playlist-spotify li:before{content:"\f1bc"}#playlist-entries li.active:before{color:#e0e7ee}#playlist-entries li.sortable-ghost:before{line-height:46px;margin-top:0;content:"\f07d";font-family:"FontAwesome";color:#e0e7ee;text-align:left}#playlist-entries .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}#playlist-entries .active .pl-action:hover{color:#e0e7ee}#pl-editor li{font-size:18px}#pl-editor li:hover{cursor:default;background:#10161c}#pl-editor .fa-list-ol{display:inline-block;width:24px;margin-left:12px;margin-right:8px;color:#34495e;text-align:center}#pl-editor .pl-folder span{padding:0}#pl-editor .pl-action:hover{cursor:pointer;font-size:24px;color:#0095d8}.form-control{max-width:400px}}@media (max-width:768px){.form-group{margin-bottom:0}}@media (min-width:768px){.boxed-group{margin:0 0 15px;padding:10px 0 0;border-radius:6px}.form-actions{padding:0}#time-knob{margin-bottom:0}#volume-knob{margin-top:0}#countdown-display,#total{top:125px}}@media (min-width:992px){#playback .container{padding-top:60px;padding-bottom:40px}.info-table th{width:176px}} \ No newline at end of file diff --git a/assets/js/runeui.js b/assets/js/runeui.js index bd684f25..927b79ae 100755 --- a/assets/js/runeui.js +++ b/assets/js/runeui.js @@ -61,6 +61,8 @@ var GUI = { volume: null }; var queueTracks = []; +var isCustomScroll = false; +var listEntryHeight = 50; @@ -230,28 +232,25 @@ function setQueuePos() { // custom scrolling function customScroll(list, destination, speed) { + isCustomScroll = true; // console.log('list = ' + list + ', destination = ' + destination + ', speed = ' + speed); if (typeof(speed) === 'undefined') { speed = 500; } - var entryheight = 49; + var entryheight = 50; var centerheight = parseInt($(window).height()/2); var scrolltop = $(window).scrollTop(); var scrollcalc = 0; var scrolloffset = 0; if (list === 'db') { - scrollcalc = parseInt((destination)*entryheight - centerheight); + scrollcalc = parseInt((destination)*listEntryHeight - centerheight); scrolloffset = scrollcalc; } else if (list === 'pl') { if (queueTracks.length !== 0) { - //var scrolloffset = parseInt((destination + 2)*entryheight - centerheight); - scrollcalc = parseInt((destination + 2)*entryheight - centerheight); + //var scrolloffset = parseInt((destination + 2)*listEntryHeight - centerheight); + scrollcalc = parseInt((destination + 2)*listEntryHeight - centerheight); scrolloffset = Math.abs(scrollcalc - scrolltop); scrolloffset = (scrollcalc > scrolltop ? '+':'-') + '=' + scrolloffset + 'px'; - // $('[data-queuepos="' + destination + '"]').addClass('active'); - // queueTracks[destination].current = true; - console.log(queueTracks[destination].current); - console.log(GUI.currentqueuepos); } } // debug @@ -260,7 +259,8 @@ function customScroll(list, destination, speed) { // console.log('scrolltop = ', scrolltop); // console.log('scrollcalc = ', scrollcalc); // console.log('scrolloffset = ', scrolloffset); - $.scrollTo( (scrollcalc >0? scrolloffset:0), speed); + $.scrollTo((scrollcalc >0? scrolloffset:0), speed); + isCustomScroll = false; } // [!] scrolling debug purpose only @@ -604,7 +604,6 @@ function updateGUI() { // console.log('A = ', GUI.json.currentsong); console.log('B = ', GUI.currentsong); if (GUI.currentsong !== GUI.json.currentsong) { setQueuePos(); - console.log('607 currentqueuepos = ', GUI.currentqueuepos); countdownRestart(0); if ($('#panel-dx').hasClass('active')) { var current = parseInt(GUI.json.song); @@ -789,6 +788,7 @@ function getPlaylistCmd(){ // console.time('getPlaylistPlain timer'); queueTracks = parseQueue(data); // console.timeEnd('getPlaylistPlain timer'); + $('#playlist').height(queueTracks.length * listEntryHeight); setQueuePos(); // console.log('793 currentqueuepos = ', GUI.currentqueuepos); if ($('#open-panel-dx').hasClass('active') && GUI.currentsong !== GUI.json.currentsong) { @@ -2333,12 +2333,12 @@ if ($('#section-index').length) { }); $('#pl-prevPage').click(function(){ var scrollTop = $(window).scrollTop(); - var scrolloffset = scrollTop - $(window).height(); + var scrolloffset = scrollTop - $(window).height() - 160; $.scrollTo(scrolloffset , 500); }); $('#pl-nextPage').click(function(){ var scrollTop = $(window).scrollTop(); - var scrolloffset = scrollTop + $(window).height(); + var scrolloffset = scrollTop + $(window).height() - 160; $.scrollTo(scrolloffset , 500); }); $('#pl-lastPage').click(function(){ @@ -2703,25 +2703,43 @@ if ($('#section-index').length) { // QUEUE RENDERING VIA MITHRIL // ---------------------------------------------------------------------------------------------------- -var queueEntryHeight = 49; -var pageY = 0, pageHeight = 0; +var pageY = 0, + pageHeight = window.innerHeight - 160, + visibleEntries = (Math.floor(pageHeight / listEntryHeight || 0 + 2)), // max number of visible entries on screen + pageOldY = 0; +window.resize = function() { + pageHeight = window.innerHeight - 160; + visibleEntries = (Math.floor(pageHeight / listEntryHeight || 0 + 2)); +}; window.onscroll = function(e) { - pageY = Math.max(e.pageY || window.pageYOffset, 0); - pageHeight = window.innerHeight; - m.redraw(); + pageY = Math.max(window.pageYOffset, 0); // the pixels the current document has been scrolled from the upper left corner of the window + var diff = Math.abs(pageOldY - (pageY - pageHeight)); + // console.log('pageY=' + pageY + ', pageOldY=' + pageOldY + ', diff=' + diff + ', pageHeight=' + pageHeight); + if (diff > pageHeight) { + pageOldY = pageY; + m.redraw(); + } }; -$(window).trigger('scroll'); +// $(window).trigger('scroll'); -m.module(document.getElementById('playlist-entries-container'), { +m.module(document.getElementById('playlist'), { controller: function() {}, view: function() { - var begin = Math.ceil(pageY / queueEntryHeight) || 0; - var end = begin + (pageHeight / queueEntryHeight || 0 + 2); - var offset = pageY % queueEntryHeight; - m('#pl-count', queueTracks.length); // [TODO] check this - return m('div', {style: 'height:' + (queueTracks.length * queueEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ - m('ul#playlist-entries.playlist', {style: 'position:relative;top:' + pageY + 'px'}, [ - (queueTracks)?queueTracks.slice(begin, end).map(function(song, idx) { + var begin = Math.floor(pageY / listEntryHeight) || 0; // first visible entry + var end = begin + visibleEntries; // last visible entry + var offset = pageY % listEntryHeight; + var buffer = 2; // amount of preceeding and following blocks to load + var start = Math.max(begin - visibleEntries * buffer, 0); // index of the first block + var finish = Math.min(end + visibleEntries * buffer, Math.max(queueTracks.length - 1, 0)); // index of the last block + // var offsetUL = pageY - (listEntryHeight * (begin - start)); + var offsetUL = start * listEntryHeight; + // console.log('visibleEntries=' + visibleEntries + ', next=' + next + ', previous=' + previous); + console.log('visible:' + begin + '->' + end + '(' + visibleEntries + '), loaded:' + start + '->' + finish + '(' + parseInt(finish - start) + ') of ' + queueTracks.length + ', offset:' + offset + ', offsetUL:' + offsetUL + 'px'); + + // return m('#queue-entries-container', {style: 'height:' + (queueTracks.length * listEntryHeight) + 'px;position:relative;top:' + (-offset) + 'px'}, [ + return m('#queue-entries-container', [ + m('ul#playlist-entries', {style: 'position:relative;top:' + offsetUL + 'px'}, [ + (queueTracks)?queueTracks.slice(start, finish).map(function(song, idx) { var icon = null; var bottom = null; if (song.webradio) { @@ -2730,9 +2748,13 @@ m.module(document.getElementById('playlist-entries-container'), { } else if (song.artist) { bottom = song.artist + ' - ' + song.album; } else { - bottom = 'path: ' + song.filename.split('/').pop(); + if (song.file) { + bottom = 'path: ' + song.file.split('/').pop(); + } else { + console.log(song); + } } - return m('li', {id: 'pl-' + song.id, 'data-queuepos': begin + idx, 'class': song.current ? 'active' : ''}, [ + return m('li', {id: 'pl-' + song.id, 'data-queuepos': start + idx, 'class': song.current ? 'active' : ''}, [ m('i.fa.fa-times-circle.pl-action[title="Remove song from playlist"]'), m('span.sn', [ song.title, diff --git a/assets/js/runeui.min.js b/assets/js/runeui.min.js index 5dfcf40a..ff56046c 100644 --- a/assets/js/runeui.min.js +++ b/assets/js/runeui.min.js @@ -1,2 +1,2 @@ -function sendCmd(a){var b=new XMLHttpRequest;b.open("GET","/command/?cmd="+a,!0),b.onreadystatechange=function(){4===this.readyState&&this.status>=200&&this.status<400},b.send(),b=null}function checkWebSocket(){return window.WebSocket?"websocket":"longpolling"}function checkWorkers(){return window.Worker&&window.Blob||Modernizr.webworkers&&Modernizr.blobconstructor?!0:!1}function parsePath(a){var b=a&&a.length?a.lastIndexOf("/"):0,c="";return b&&-1!==b&&(c=a.slice(0,b)),c}function refreshTimer(a,b,c){var d=$("#countdown-display");d.countdown("destroy"),d.countdown({since:"stop"!==c||void 0!==c?-a:0,compact:!0,format:"MS"}),"play"!==c&&d.countdown("pause")}function refreshKnob(){window.clearInterval(GUI.currentKnob);var a=10*parseInt(GUI.json.song_percent),b=parseInt(GUI.json.time),c=parseInt(1e3/b),d=$("#time");d.val(a,!1).trigger("update"),"play"===GUI.state&&(GUI.currentKnob=setInterval(function(){a+="visible"!==GUI.visibility?c:1,d.val(a,!1).trigger("update")},b))}function timeConvert(a){var b=Math.floor(a/60);a-=60*b;var c=10>b?"0"+b:b,d=10>a?"0"+a:a;return c+":"+d}function timeConvert2(a){var b=Math.floor(a/3600),c=Math.floor((a-3600*b)/60);return a=Math.floor(a-3600*b-60*c),b>0?(10>b&&(b="0"+b),b+=":"):b="",10>c&&(c="0"+c),10>a&&(a="0"+a),b+c+":"+a}function countdownRestart(a){var b=$("#countdown-display").countdown("destroy");b.countdown({since:-a,compact:!0,format:"MS"})}function setvol(a){$("#volume").val(a,!1).trigger("update"),GUI.volume=a,$("#volumemute").removeClass("btn-primary"),sendCmd("setvol "+a)}function volumeStepCalc(a){var b=0;GUI.volume=parseInt($("#volume").val());var c=function(){b++,"up"===a?GUI.stepVolumeDelta=parseInt(GUI.volume)+b:"dn"===a&&(GUI.stepVolumeDelta=parseInt(GUI.volume)-b),$("#volume").val(GUI.stepVolumeDelta).trigger("change")};c(),GUI.stepVolumeInt=window.setInterval(function(){c()},200)}function volumeStepSet(){window.clearInterval(GUI.stepVolumeInt),setvol(GUI.stepVolumeDelta)}function setQueuePos(){0!==queueTracks.length&&GUI.currentqueuepos!==parseInt(GUI.json.song)&&(queueTracks[GUI.currentqueuepos].current=!1,GUI.currentqueuepos=parseInt(GUI.json.song),queueTracks[GUI.currentqueuepos].current=!0)}function customScroll(a,b,c){"undefined"==typeof c&&(c=500);var d=49,e=parseInt($(window).height()/2),f=$(window).scrollTop(),g=0,h=0;"db"===a?(g=parseInt(b*d-e),h=g):"pl"===a&&0!==queueTracks.length&&(g=parseInt((b+2)*d-e),h=Math.abs(g-f),h=(g>f?"+":"-")+"="+h+"px",console.log(queueTracks[b].current),console.log(GUI.currentqueuepos)),$.scrollTo(g>0?h:0,c)}function randomScrollPL(){var a=$(".playlist li").size(),b=1+Math.floor(Math.random()*a);customScroll("pl",b)}function randomScrollDB(){var a=$(".database li").size(),b=1+Math.floor(Math.random()*a);customScroll("db",b)}function toggleLoader(a){"close"===a?$("#loader").addClass("hide"):$("#section-dev").length?($("#loader").addClass("hide"),new PNotify({title:"Warning",text:"The loading layer (spinning arrows) points to a socket error",icon:"fa fa-exclamation-circle"})):$("#loader").removeClass("hide")}function customNotify(a){"kernelswitch"===a.custom&&(void 0!==GUI.noticeUI.kernelswitch&&GUI.noticeUI.kernelswitch.remove(),GUI.noticeUI.kernelswitch=new PNotify({title:"title"in a?a.title:"[missing title]",text:"text"in a?a.text:"[missing text]",icon:"fa fa-refresh",hide:!1,confirm:{confirm:!0,buttons:[{text:a.btntext,addClass:"btn-default btn-block uppercase",click:function(){$.post("/settings/",{syscmd:"reboot"}),toggleLoader()}},{text:"Cancel",addClass:"hide"}]},buttons:{closer:!1,sticker:!1}}))}function renderMSG(a){var b=a[0];if("custom"in b&&null!==b.custom)return void customNotify(b);var c={title:"title"in b?b.title:"[missing title]",text:"text"in b?b.text:"[missing text]",icon:void 0===b.icon?"fa fa-check":b.icon,opacity:void 0===b.opacity?.9:b.opacity,hide:void 0===b.hide&&void 0===b.permanotice,buttons:{closer:void 0===b.permanotice,sticker:void 0===b.permanotice},delay:void 0===b.delay?8e3:b.delay,mouse_reset:!1};"permanotice"in b?void 0===GUI.noticeUI[b.permanotice]?GUI.noticeUI[b.permanotice]=new PNotify(c):"permaremove"in b?(GUI.noticeUI[b.permanotice].remove(),GUI.noticeUI[b.permanotice]=void 0):GUI.noticeUI[b.permanotice].open():new PNotify(c)}function sortOrder(a){var b=$("#"+a).index();a=parseInt(a.replace("pl-","")),sendCmd("moveid "+a+" "+b)}function loadingSpinner(a,b){"hide"===b?("db"===a&&$("#spinner-db").addClass("hide"),"pl"===a&&$("#spinner-pl").addClass("hide")):("db"===a&&$("#spinner-db").removeClass("hide"),"pl"===a&&$("#spinner-pl").removeClass("hide"))}function setPlaybackSource(){var a=GUI.libraryhome.ActivePlayer;$("#overlay-playsource-open button").text(a),$("#overlay-playsource a").addClass("inactive");var b=a.toLowerCase();$("#playsource-"+b).removeClass("inactive"),"Spotify"===a||"Airplay"===a?($("#volume").trigger("configure",{readOnly:!0,fgColor:"#1A242F"}).css({color:"#1A242F"}),$(".volume button").prop("disabled",!0),$("#single").addClass("disabled")):($("#volume").trigger("configure",{readOnly:!1,fgColor:"#0095D8"}).css({color:"#0095D8"}),$(".volume button").prop("disabled",!1),$("#single").removeClass("disabled")),$("#playlist-entries").removeClass(function(a,b){return(b.match(/(^|\s)playlist-\S+/g)||[]).join(" ")}).addClass("playlist-"+b),$("#pl-manage").removeClass(function(a,b){return(b.match(/(^|\s)pl-manage-\S+/g)||[]).join(" ")}).addClass("pl-manage-"+b)}function chkKey(a){return void 0!==a&&""!==a}function renderLibraryHome(){loadingSpinner("db"),$("#database-entries").addClass("hide"),$("#db-level-up").addClass("hide"),$("#db-homeSetup").removeClass("hide").removeClass("btn-primary").addClass("btn-default"),$("#home-blocks").removeClass("hide");var a=GUI.libraryhome,b=0,c="",d='
    ',e="
    ",f="",g="",h="Spotify"===a.ActivePlayer||"Airplay"===a.ActivePlayer;for(c='

    Browse your library

    ',setPlaybackSource(),h&&(f=" inactive"),b=0;bookmark=a.bookmarks[b];b+=1)c+=d+'

    '+bookmark.name+"

    bookmark
    "+e;chkKey(a.networkMounts)&&(c+=0===a.networkMounts?h?d+'

    Network mounts (0)

    network attached storages
    '+e:d+'

    Network mounts (0)

    click to add some
    '+e:d+'

    Network mounts ('+a.networkMounts+")

    network attached storages
    "+e),chkKey(a.localStorages)&&(c+=0===a.localStorages?"":d+'

    LocalStorage ('+a.localStorages+")

    locally stored music
    "+e),chkKey(a.USBMounts)&&(c+=0===a.USBMounts?h?d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage (0)

    no USB storage plugged
    '+e:d+'

    USB storage ('+a.USBMounts+")

    USB attached drives
    "+e),chkKey(a.webradio)&&(c+=0===a.webradio?h?d+'

    My Webradios (0)

    webradio local playlists
    '+e:d+'

    My Webradios (0)

    click to add some
    '+e:d+'

    My Webradios ('+a.webradio+")

    webradio local playlists
    "+e),chkKey(a.Spotify)&&(c+="0"===a.Spotify?d+'

    Spotify

    click to configure
    '+e:"Spotify"!==a.ActivePlayer?d+'

    Spotify

    click to switch renderer
    '+e:d+'

    Spotify

    music for everyone
    '+e),chkKey(a.Dirble)&&(c+=d+'

    Dirble ('+a.Dirble+")

    radio stations open directory
    "+e),c+=d+'

    Jamendo

    world\'s largest platform for free music
    '+e,c+=d+'

    Albums

    browse MPD database by album
    '+e,c+=d+'

    Artists

    browse MPD database by artist
    '+e,c+=d+'

    Genres

    browse MPD database by genre
    '+e,c+="
    ",document.getElementById("home-blocks").innerHTML=c,loadingSpinner("db","hide"),$("span","#db-currentpath").html("")}function refreshState(){var a=GUI.state;if("play"===a?($("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").removeClass("btn-primary")):"pause"===a?($("#playlist-position span").html("Not playing"),$("#play").addClass("btn-primary"),$("i","#play").removeClass("fa fa-play").addClass("fa fa-pause"),$("#stop").removeClass("btn-primary")):"stop"===a&&($("#play").removeClass("btn-primary"),$("i","#play").removeClass("fa fa-pause").addClass("fa fa-play"),$("#stop").addClass("btn-primary"),$("#section-index").length&&$("#countdown-display").countdown("destroy"),$("#total").html("radio"===GUI.stream?"":"00:00"),$("#time").val(0,!1).trigger("update"),$("#format-bitrate").html(" "),$("li","#playlist-entries").removeClass("active")),"stop"!==a){$("#total").html("radio"===GUI.stream?"":void 0!==GUI.json.time?timeConvert(GUI.json.time):"00:00");var b=GUI.json.audio_channels&&GUI.json.audio_sample_depth&&GUI.json.audio_sample_rate?GUI.json.audio_channels+", "+GUI.json.audio_sample_depth+" bit, "+GUI.json.audio_sample_rate+" kHz, "+GUI.json.bitrate+" kbps":" ";$("#format-bitrate").html(b),$("li","#playlist-entries").removeClass("active");var c=parseInt(GUI.json.song);$("#playlist-entries").find("li").eq(c).addClass("active")}$("#playlist-position span").html(GUI.json.playlistlength&&"0"!==GUI.json.playlistlength?GUI.json.song?"Playlist position "+(parseInt(GUI.json.song)+1)+"/"+GUI.json.playlistlength:"Playlist position 1/"+GUI.json.playlistlength:"Empty queue, add some music!"),$("a","#open-panel-sx").html(void 0!==GUI.json.updating_db?' Updating':' Library')}function updateGUI(){var a=GUI.json.volume,b=GUI.json.radioname,c=GUI.json.currentartist,d=GUI.json.currentsong,e=GUI.json.currentalbum;if(GUI.stream=null!==b&&void 0!==b&&""!==b?"radio":"",refreshState(),$("#section-index").length){if(GUI.currentsong!==GUI.json.currentsong&&(setQueuePos(),console.log("607 currentqueuepos = ",GUI.currentqueuepos),countdownRestart(0),$("#panel-dx").hasClass("active"))){var f=parseInt(GUI.json.song);customScroll("pl",f)}$("#volume").val("-1"===a?100:a,!1).trigger("update"),"radio"!==GUI.stream?($("#currentartist").html(null===c||void 0===c||""===c?'[no artist]':c),$("#currentsong").html(null===d||void 0===d||""===d?'[no title]':d),$("#currentalbum").html(null===e||void 0===e||""===e?'[no album]':e)):($("#currentartist").html(null===c||void 0===c||""===c?b:c),$("#currentsong").html(null===d||void 0===d||""===d?b:d),$("#currentalbum").html('streaming')),"1"===GUI.json.repeat?$("#repeat").addClass("btn-primary"):$("#repeat").removeClass("btn-primary"),"1"===GUI.json.random?$("#random").addClass("btn-primary"):$("#random").removeClass("btn-primary"),"1"===GUI.json.consume?$("#consume").addClass("btn-primary"):$("#consume").removeClass("btn-primary"),"1"===GUI.json.single?$("#single").addClass("btn-primary"):$("#single").removeClass("btn-primary"),GUI.currentsong=d;var g=c+" - "+e;if(GUI.currentalbum!==g)if(null===b||void 0===b||""===b){var h=Math.floor(1001*Math.random());$("#cover-art").css("background-image",'url("/coverart/?v='+h+'")')}else $("#cover-art").css("background-image",'url("assets/img/cover-radio.jpg")');GUI.currentalbum=g}}function getPlaylistPlain(a){var b,c,d=parseInt(GUI.json.song)+1,e=GUI.json.state,f="",g="",h="",i="",j="",k="",l="",m="",n="",o="",p="",q="",r=0,s=a.split("\n"),t=[];for(b=0;c=s[b];b+=1)t=c.split(": "),"Time"===t[0]?g=parseInt(t[1]):"Artist"===t[0]?h=t[1]:"Title"===t[0]?j=t[1]:"Name"===t[0]?k=t[1]:"Album"===t[0]?i=t[1]:"file"===t[0]?l=t[1]:"Id"===t[0]&&(o=t[1],""===j||""===i?(n=parsePath(l),m=l.split("/").pop(),j=m,p=""===h?"path: "+n:h):p=h+" - "+i,""!==k?(j=''+k,p=l,q=""):q=""+timeConvert2(g)+"",r++,f+='
  • '+j+q+''+p+"
  • ",g="",h="",i="",j="",k="");$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide");var u=document.getElementById("playlist-entries");u&&(u.innerHTML=f),$("#pl-filter-results").addClass("hide").html(""),$("#pl-filter").val(""),$("#pl-manage").removeClass("hide"),$("#pl-count").removeClass("hide").html(r+(1!==r?" entries":" entry"))}function parseQueue(a){var b,c,d=(parseInt(GUI.json.song)+1,GUI.json.state,a.split("\n")),e=1,f=[],g={};for(b=0;c=d[b];b+=1){var h=c.split(": ");"file"===h[0]?(g.file=h[1],g.fileExt=h[1].split(".").pop()):"Name"===h[0]?g.name=h[1]:"Last-Modified"===h[0]?g.lastModified=h[1]:"Time"===h[0]?(g.time=parseInt(h[1]),g.timeFormatted=timeConvert(g.time)):"Artist"===h[0]?g.artist=h[1]:"Title"===h[0]?g.title=h[1]:"Album"===h[0]?g.album=h[1]:"Track"===h[0]?g.track=h[1]:"Date"===h[0]?g.date=h[1]:"Genre"===h[0]?g.genre=h[1]:"Id"===h[0]&&(g.id=h[1],g.pos=e++,g.name&&(g.webradio=!0),f.push(g),g={})}return f}function getPlaylistCmd(){loadingSpinner("pl"),$.ajax({url:"/db/?cmd=playlist",success:function(a){a.length>4?($(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),queueTracks=parseQueue(a),setQueuePos(),$("#open-panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",GUI.currentqueuepos,500),m.redraw()):($(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries")),loadingSpinner("pl","hide")}})}function getPlaylist(a){if(data=a[0],data.length>4){$(".playlist").addClass("hide"),$("#playlist-entries").removeClass("hide"),getPlaylistPlain(data);var b=parseInt(GUI.json.song);$("#panel-dx").hasClass("active")&&GUI.currentsong!==GUI.json.currentsong&&customScroll("pl",b,200)}else $(".playlist").addClass("hide"),$("#playlist-warning").removeClass("hide"),$("#pl-filter-results").addClass("hide").html(""),$("#pl-count").removeClass("hide").html("0 entries");loadingSpinner("pl","hide")}function renderUI(a){if(toggleLoader("close"),GUI.json=a[0],GUI.state=GUI.json.state,updateGUI(),$("#section-index").length){var b=""!==GUI.json.elapsed&&void 0!==GUI.json.elapsed?GUI.json.elapsed:0,c=""!==GUI.json.time&&void 0!==GUI.json.time&&null!==GUI.json.time?GUI.json.time:0;refreshTimer(parseInt(b),parseInt(c),GUI.json.state),"radio"!==GUI.stream?refreshKnob():$("#time").val(0,!1).trigger("update"),GUI.json.playlist!==GUI.playlist&&(getPlaylistCmd(),GUI.playlist=GUI.json.playlist)}}function renderPlaylists(a){var b,c,d="",e="",f=a.split("\n"),g=[];for(b=0;c=f[b];b+=1)g=c.split(": "),"playlist"===g[0]&&(e=g[1],d+='
  • '+e+"
  • ",e="");document.getElementById("playlist-entries").innerHTML="",$(".playlist").addClass("hide"),$("#pl-manage").addClass("hide"),$("#pl-count").addClass("hide"),$("#pl-filter-results").removeClass("hide").addClass("back-to-queue").html(' to queue'),$("#pl-currentpath").removeClass("hide"),$("#pl-editor").removeClass("hide"),document.getElementById("pl-editor").innerHTML=d,loadingSpinner("pl","hide")}function getPlaylists(){loadingSpinner("pl"),$.ajax({url:"/command/?cmd=listplaylists",success:function(a){renderPlaylists(a)}})}function parseResponse(a){var b=a.inputArr||"",c=a.respType||"",d=a.i||0,e=a.inpath||"",f=a.querytype||"",g="";switch(c){case"playlist":break;case"db":"file"===GUI.browsemode?(""===e&&void 0!==b.file&&(e=parsePath(b.file)),void 0!==b.file||"Webradio"===e?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album):"Webradio"!==e?(g+=b.file,g+='">',g+=b.file.replace(e+"/","")+" "+timeConvert(b.Time)+"",g+='',g+=" path: ",g+=e):(g+=b.playlist,g+='">',g+=''+b.playlist.replace(e+"/","").replace("."+b.fileext,""),g+='webradio'),g+="
  • "):void 0!==b.playlist?"cue"===b.fileext&&(g='
  • ',g+=b.playlist.replace(e+"/","")+" [CUE file]",g+='',g+=" path: ",g+=e,g+="
  • "):(g='
  • ':'">',g+=b.directory.replace(e+"/",""),g+="
  • ")):"album"===GUI.browsemode||"albumfilter"===GUI.browsemode?void 0!==b.file?(g='
  • ',g+=b.Title+" "+timeConvert(b.Time)+"",g+=' ',g+=b.Artist,g+=" - ",g+=b.Album,g+="
  • "):""!==b.album&&(g='
  • "):"artist"===GUI.browsemode?void 0!==b.album?(g='
  • ',g+=""!==b.album?b.album:"Unknown album",g+="
  • "):""!==b.artist&&(g='
  • ',g+=b.artist,g+="
  • "):"genre"===GUI.browsemode&&(void 0!==b.artist?(g='
  • ',g+=""!==b.artist?b.artist:"Unknown artist",g+="
  • "):""!==b.genre&&(g='
  • ',g+=b.genre,g+="
  • "));break;case"Spotify":""===f?(g='
  • ',g+=""!==b.name?b.name:"Favorites",g+=" (",g+=b.tracks,g+=")
  • "):"tracks"===f&&(g='
  • ',g+=b.title+" "+timeConvert(b.duration/1e3)+"",g+=' ',g+=b.artist,g+=" - ",g+=b.album,g+="
  • ");break;case"Dirble":""===f?(g='
  • ',g+=b.name,g+="
  • "):"stations"===f&&(g='
  • "+b.bitrate+"",g+='',g+=b.website,g+="
  • ");break;case"Jamendo":g='
  • ',g+=b.dispname+"