source: trunk/fl5/src/com/longtailvideo/jwplayer/model/PlaylistItem.as @ 2159

Revision 2159, 6.2 KB checked in by pablo, 2 months ago (diff)

Additional fix for 1347, where javascript injection could be done with alternate casing.

Line 
1package com.longtailvideo.jwplayer.model {
2        import com.longtailvideo.jwplayer.utils.Logger;
3        import com.longtailvideo.jwplayer.utils.Strings;
4
5        /**
6         * Playlist item data.  The class is dynamic; any items parsed from the jwplayer XML namespace are added to the item.
7         * 
8         * @author Pablo Schklowsky
9         */
10        public dynamic class PlaylistItem {
11                public var author:String                = "";
12                public var date:String                  = "";
13                public var description:String   = "";
14                public var image:String                 = "";
15                public var link:String                  = "";
16                public var mediaid:String               = "";
17                public var tags:String                  = "";
18                public var title:String                 = "";
19               
20                protected var _duration:Number          = -1;
21                protected var _file:String                      = "";
22                protected var _provider:String          = "";
23                protected var _start:Number                     = 0;
24                protected var _streamer:String          = "";
25               
26                protected var _currentLevel:Number      = -1;
27                protected var _levels:Array                     = [];
28               
29               
30                public function PlaylistItem(obj:Object = null) {
31                        for (var itm:String in obj) {
32                                if (itm == "levels") {
33                                        if (!(obj[itm] is Array)) {
34                                                continue;                                               
35                                        }
36                                        var levels:Array = obj[itm] as Array;
37                                        for each (var level:Object in levels) {
38                                                if (level['file']) {
39                                                        var newLevel:PlaylistItemLevel = new PlaylistItemLevel(level['file'],
40                                                                Number(level['bitrate']),
41                                                                Number(level['width']),
42                                                                level['streamer']);
43                                                        for (var otherProp:String in level) {
44                                                                switch(otherProp) {
45                                                                        case "file":
46                                                                        case "bitrate":
47                                                                        case "width":
48                                                                        case "streamer":
49                                                                                break;
50                                                                        default:
51                                                                                newLevel[otherProp] = level[otherProp];
52                                                                                break;
53                                                                }
54                                                        }
55                                                        addLevel(newLevel);
56                                                }
57                                        }
58                                } else {
59                                        try {
60                                                this[itm] = obj[itm];
61                                        } catch(e:Error) {
62                                                Logger.log("Could not set playlist item property " + itm + " (" + e.message+")");
63                                        }
64                                }
65                        }
66                }
67               
68
69                /** File property is now a getter, to take levels into account **/
70                public function get file():String {
71                        if (_levels.length > 0 && _currentLevel > -1 && _currentLevel < _levels.length) {
72                                var level:PlaylistItemLevel = _levels[_currentLevel] as PlaylistItemLevel;
73                                return level.file ? level.file : _file;
74                        } else {
75                                return _file;
76                        }
77                }
78               
79                /** File setter.  Note, if levels are defined, this will be ignored. **/
80                public function set file(f:String):void {
81                        _file = f;
82                }
83               
84                /** Streamer property is now a getter, to take levels into account **/
85                public function get streamer():String {
86                        if (_levels.length > 0 && _currentLevel > -1 && _currentLevel < _levels.length) {
87                                var level:PlaylistItemLevel = _levels[_currentLevel] as PlaylistItemLevel;
88                                return level.streamer ? level.streamer : _streamer;
89                        } else {
90                                return _streamer;
91                        }
92                }
93               
94                /** Streamer setter.  Note, if levels are defined, this will be ignored. **/
95                public function set streamer(s:String):void {
96                        _streamer = s;
97                }
98               
99                /** The quality levels associated with this playlist item **/
100                public function get levels():Array {
101                        return _levels;
102                }
103               
104                /** Insert an additional bitrate level, keeping the array sorted from highest to lowest. **/
105                public function addLevel(newLevel:PlaylistItemLevel):void {
106                        if (validExtension(newLevel.file)) {
107                                if (_currentLevel < 0) _currentLevel = 0;
108                                for (var i:Number = 0; i < _levels.length; i++) {
109                                        var level:PlaylistItemLevel = _levels[i] as PlaylistItemLevel;
110                                        if (newLevel.bitrate > level.bitrate) {
111                                                _levels.splice(i, 0, newLevel);
112                                                return;
113                                        } else if ( (isNaN(newLevel.bitrate) || newLevel.bitrate == level.bitrate) && newLevel.width > level.width) {
114                                                _levels.splice(i, 0, newLevel);
115                                                return;
116                                        }
117                                }
118                                _levels.push(newLevel);
119                        }
120                }
121
122
123        /** Levels need to be cleared e.g. for reloading a multibitrate SMIL. **/
124        public function clearLevels():void {
125            _levels = new Array();
126        };
127
128
129                /** Blacklist a level from usage (e.g. if it cannot be played or drops too many frames). **/
130                public function blacklistLevel(level:Number,state:Boolean=true):void {
131                        if(levels[level]) {
132                                levels[level].blacklisted = state;
133                        }
134                };
135
136
137                /**
138                 * Determines whether this file extension can be played in the Flash player.  If not, ignore the level.
139                 * This is useful for unified HTML5 / Flash failover setups.
140                 **/
141                protected function validExtension(filename:String):Boolean {
142                        switch(Strings.extension(filename)) {
143                                case "ogv":
144                                case "ogg":
145                                case "webm":
146                                        return false;
147                                default:
148                                        return true;
149                        }
150                }
151
152                public function get currentLevel():Number {
153                        return _currentLevel;
154                }
155               
156                public function getLevel(bitrate:Number, width:Number):Number {
157                        for (var i:Number=0; i < _levels.length; i++) {
158                                var level:PlaylistItemLevel = _levels[i] as PlaylistItemLevel;
159                                if ((isNaN(level.bitrate) || bitrate >= level.bitrate * 1.5) && (isNaN(level.width) || width >= level.width * 0.67) && !level.blacklisted) {
160                                        return i;
161                                }
162                        }
163                        return _levels.length - 1;
164                }
165               
166                /** Set this PlaylistItem's level to match the given bitrate and height. **/
167                public function setLevel(newLevel:Number):void {
168                        if (newLevel >= 0 && newLevel < _levels.length) {
169                                _currentLevel = newLevel;
170                        } else {
171                                throw(new Error("Level index out of bounds"));
172                        }
173                }
174               
175                public function toString():String {
176                        return "[PlaylistItem" +
177                                (this.file ? " file=" + this.file : "") +
178                                (this.streamer ? " streamer=" + this.streamer : "") +
179                                (this.provider ? " provider=" + this.provider : "") +
180                                (this.levels.length ? " level=" + this.currentLevel.toString() : "") +
181                                "]";
182                       
183                }
184               
185               
186                public function get start():Number { return _start; }
187                public function set start(s:*):void {
188                        _start = Strings.seconds(String(s));
189                        if (_start > _duration && _duration > 0) {
190                                _duration += _start;
191                        }
192                }
193
194                public function get duration():Number { return _duration; }
195                public function set duration(d:*):void {
196                        _duration = Strings.seconds(String(d));
197                        if (_start > _duration && _duration > 0) {
198                                _duration += _start;
199                        }
200                }
201
202                public function get provider():String { return _provider; }
203                public function set provider(p:*):void {
204                        _provider = (p == "audio") ? "sound" : p;
205                }
206               
207                // For backwards compatibility
208                public function get type():String { return _provider; }
209                public function set type(t:String):void { provider = t; }
210               
211        }
212}
Note: See TracBrowser for help on using the repository browser.