~jstys-z/helioviewer.org/client5

« back to all changes in this revision

Viewing changes to src/js/Media/MovieManager.js

Preparing to merge in my branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/**
2
 
 * MovieManager class definition
3
 
 * @author <a href="mailto:jeff.stys@nasa.gov">Jeff Stys</a>
4
 
 * @author <a href="mailto:keith.hughitt@nasa.gov">Keith Hughitt</a>
5
 
 *
6
 
 * TODO 2011/03/14: Choose a reasonable limit for the number of entries based on whether or not
7
 
 * localStorage is supported: if supported limit can be large (e.g. 100), otherwise should be
8
 
 * closer to 3 entries.
9
 
 *
10
 
 * Movie Status:
11
 
 *  0 QUEUED
12
 
 *  1 PROCESSING
13
 
 *  2 COMPLETED
14
 
 *  3 ERROR
15
 
 *
16
 
 */
17
 
/*jslint browser: true, white: true, onevar: true, undef: true, nomen: false, eqeqeq: true, plusplus: true,
18
 
bitwise: true, regexp: false, strict: true, newcap: true, immed: true, maxlen: 120, sub: true */
19
 
/*global Helioviewer, MediaManager, $, setTimeout */
20
 
"use strict";
21
 
var MovieManager = MediaManager.extend(
22
 
    /** @lends MovieManager.prototype */
23
 
    {
24
 
    /**
25
 
     * @constructs
26
 
     * Creates a new MovieManager instance
27
 
     */
28
 
    init: function (movies) {
29
 
        this._super(movies);
30
 
        this.format   = $.support.vp8 ? "webm" : "mp4";
31
 
 
32
 
        // Check status of any previously unfinished movie requests
33
 
        var self = this;
34
 
        $.each(movies, function (i, movie) {
35
 
            if (movie.status < 2) {
36
 
                self._monitorQueuedMovie(movie.id, Date.parseUTCDate(movie.dateRequested), 0);
37
 
            }
38
 
        });
39
 
    },
40
 
 
41
 
    /**
42
 
     * Adds a new movie
43
 
     *
44
 
     * @param {Int}     id            Movie id
45
 
     * @param {Float}   duration      Movie duration in seconds
46
 
     * @param {Float}   imageScale    Image scale for the movie
47
 
     * @param {String}  layers        Layers in the movie serialized as a string
48
 
     * @param {String}  dateRequested Date string for when the movie was requested
49
 
     * @param {String}  startDate     Observation date associated with the first movie frame
50
 
     * @param {String}  endDate       Observation date associated with the last movie frame
51
 
     * @param {Float}   frameRate     Movie frame-rate in frames/sec
52
 
     * @param {Int}     numFrames     Total number of frames in the movie
53
 
     * @param {Float}   x1            Top-left corner x-coordinate
54
 
     * @param {Float}   y1            Top-left corner y-coordinate
55
 
     * @param {Float}   x2            Bottom-right corner x-coordinate
56
 
     * @param {Float}   y2            Bottom-right corner y-coordinate
57
 
     * @param {Int}     width         Movie width
58
 
     * @param {Int}     height        Movie height
59
 
     *
60
 
     * @return {Movie} A Movie object
61
 
     */
62
 
    add: function (
63
 
            id, duration, imageScale, layers, events, eventsLabels, scale,
64
 
            scaleType, scaleX, scaleY, dateRequested, startDate, endDate,
65
 
            frameRate, numFrames, x1, x2, y1, y2, width, height, thumbnail, url
66
 
    ) {
67
 
        var movie = {
68
 
            "id"            : id,
69
 
            "duration"      : duration,
70
 
            "imageScale"    : imageScale,
71
 
            "layers"        : layers,
72
 
            "events"        : events,
73
 
            "eventsLabels"  : eventsLabels,
74
 
            "scale"         : scale,
75
 
            "scaleType"     : scaleType,
76
 
            "scaleX"        : scaleX,
77
 
            "scaleY"        : scaleY,
78
 
            "dateRequested" : dateRequested,
79
 
            "startDate"     : startDate,
80
 
            "endDate"       : endDate,
81
 
            "frameRate"     : frameRate,
82
 
            "numFrames"     : numFrames,
83
 
            "x1"            : x1,
84
 
            "x2"            : x2,
85
 
            "y1"            : y1,
86
 
            "y2"            : y2,
87
 
            "width"         : width,
88
 
            "height"        : height,
89
 
            "ready"         : true,
90
 
            "name"          : this._getName(layers),
91
 
            "status"        : 2,
92
 
            "thumbnail"     : thumbnail,
93
 
            "url"           : url
94
 
        };
95
 
        this._super(movie);
96
 
 
97
 
        return movie;
98
 
    },
99
 
 
100
 
    /**
101
 
     * Adds a movie that is currently being processed
102
 
     *
103
 
     * @param {Int}     id            Movie id
104
 
     * @param {Int}     eta           Estimated time in seconds before movie is ready
105
 
     * @param {String}  token         Resque token for tracking status in queue
106
 
     * @param {Float}   imageScale    Image scale for the movie
107
 
     * @param {String}  layers        Layers in the movie serialized as a string
108
 
     * @param {String}  dateRequested Date string for when the movie was requested
109
 
     * @param {String}  startDate     Observation date associated with the first movie frame
110
 
     * @param {String}  endDate       Observation date associated with the last movie frame
111
 
     * @param {Float}   x1            Top-left corner x-coordinate
112
 
     * @param {Float}   y1            Top-left corner y-coordinate
113
 
     * @param {Float}   x2            Bottom-right corner x-coordinate
114
 
     * @param {Float}   y2            Bottom-right corner y-coordinate
115
 
     *
116
 
     * @return {Movie} A Movie object
117
 
     */
118
 
    queue: function (id, eta, token, imageScale, layers, events, eventsLabels,
119
 
                scale, scaleType, scaleX, scaleY, dateRequested, startDate,
120
 
                endDate, x1, x2, y1, y2) {
121
 
 
122
 
        var movie = {
123
 
            "id"            : id,
124
 
            "imageScale"    : imageScale,
125
 
            "layers"        : layers,
126
 
            "events"        : events,
127
 
            "eventsLabels"  : eventsLabels,
128
 
            "scale"         : scale,
129
 
            "scaleType"     : scaleType,
130
 
            "scaleX"        : scaleX,
131
 
            "scaleY"        : scaleY,
132
 
            "dateRequested" : dateRequested,
133
 
            "startDate"     : startDate,
134
 
            "endDate"       : endDate,
135
 
            "x1"            : x1,
136
 
            "x2"            : x2,
137
 
            "y1"            : y1,
138
 
            "y2"            : y2,
139
 
            "status"        : 0,
140
 
            "token"         : token,
141
 
            "name"          : this._getName(layers)
142
 
        };
143
 
 
144
 
        if (this._history.unshift(movie) > this._historyLimit) {
145
 
            this._history = this._history.slice(0, this._historyLimit);
146
 
        }
147
 
 
148
 
        this._monitorQueuedMovie(id, Date.parseUTCDate(dateRequested), token, eta);
149
 
 
150
 
        this._save();
151
 
        return movie;
152
 
    },
153
 
 
154
 
    /**
155
 
     * Updates stored information for a given movie and notify user that movie is available
156
 
     *
157
 
     * @param {Int}     id            Movie id
158
 
     * @param {Float}   frameRate     Movie frame-rate in frames/sec
159
 
     * @param {Int}     numFrames     Total number of frames in the movie
160
 
     * @param {String}  startDate     The actual movie start date
161
 
     * @param {String}  endDate       The actual movie end date
162
 
     * @param {Int}     width         Movie width
163
 
     * @param {Int}     height        Movie height
164
 
     */
165
 
    update: function (id, frameRate, numFrames, startDate, endDate, width,
166
 
        height, thumbnails, url) {
167
 
 
168
 
        var movie = this.get(id);
169
 
 
170
 
        // Add the new values
171
 
        $.extend(movie, {
172
 
            "frameRate" : frameRate,
173
 
            "numFrames" : numFrames,
174
 
            "startDate" : startDate,
175
 
            "endDate"   : endDate,
176
 
            "width"     : width,
177
 
            "height"    : height,
178
 
            "status"    : 2,
179
 
            "thumbnail" : thumbnails.small,
180
 
            "url"       : url
181
 
        });
182
 
 
183
 
        // Delete resque token
184
 
        delete movie.token;
185
 
 
186
 
        this._save();
187
 
 
188
 
        // Update preview tooltip
189
 
        $(document).trigger("movie-ready", [movie]);
190
 
 
191
 
        // Notify user
192
 
        this._displayDownloadNotification(movie);
193
 
    },
194
 
 
195
 
    /**
196
 
     * Displays a jGrowl notification to the user informing them that their
197
 
     * download has completed
198
 
     */
199
 
    _displayDownloadNotification: function (movie) {
200
 
        var jGrowlOpts, message, self = this;
201
 
 
202
 
        // Options for the jGrowl notification
203
 
        jGrowlOpts = {
204
 
            sticky: true,
205
 
            header: "Just now",
206
 
            open:    function (msg) {
207
 
                msg.find(".message-console-movie-ready").data("movie", movie);
208
 
            }
209
 
        };
210
 
        message = "<span class='message-console-movie-ready'>" +
211
 
                  "Your " + movie.name + " movie is ready! " +
212
 
                  "Click here to watch or download it.</span>";
213
 
 
214
 
        // Create the jGrowl notification.
215
 
        $(document).trigger("message-console-log",
216
 
                            [message, jGrowlOpts, true, true]);
217
 
    },
218
 
 
219
 
    /**
220
 
     * Monitors a queued movie and notifies the user when it becomes available
221
 
     */
222
 
    _monitorQueuedMovie: function (id, dateRequested, token, eta)
223
 
    {
224
 
        var queryMovieStatus, self = this;
225
 
 
226
 
        queryMovieStatus = function () {
227
 
            var params, callback;
228
 
 
229
 
            callback = function (response) {
230
 
                // If the user has removed the movie from history, stop monitoring
231
 
                if (!self.has(id)) {
232
 
                    return;
233
 
                }
234
 
 
235
 
                // Check status
236
 
                if (response.status < 2) {
237
 
                    // If more than 24 hours has elapsed, set status to ERROR
238
 
                    if ((Date.now() - dateRequested) / 1000 > (24 * 60 * 60)) {
239
 
                        self._abort(id);
240
 
                    }
241
 
                    // Otherwise continue to monitor
242
 
                    self._monitorQueuedMovie(id, dateRequested, token, 60);
243
 
                } else if (response.error) {
244
 
                    self._abort(id);
245
 
                }  else {
246
 
                    self.update(id, response.frameRate, response.numFrames,
247
 
                                response.startDate, response.endDate,
248
 
                                response.width, response.height,
249
 
                                response.thumbnails, response.url);
250
 
                }
251
 
            };
252
 
 
253
 
            params = {
254
 
                "action" : "getMovieStatus",
255
 
                "id"     : id,
256
 
                "token"  : token,
257
 
                "format" : self.format
258
 
            };
259
 
            $.get(Helioviewer.api, params, callback, Helioviewer.dataType);
260
 
        };
261
 
        setTimeout(queryMovieStatus, Math.max(eta, 5) * 1000);
262
 
    },
263
 
 
264
 
    /**
265
 
     * Aborts a failed movie request
266
 
     */
267
 
    _abort: function (id) {
268
 
        var error, movie = this.get(id);
269
 
 
270
 
        // Mark as failed
271
 
        movie["status"] = 3;
272
 
        this._save();
273
 
 
274
 
        // Notify user
275
 
        error = "Sorry, we were unable to create the movie you requested. " +
276
 
                "This usually means that there are not enough images for the " +
277
 
                "time range requested. Please try adjusting the observation " +
278
 
                "date or movie duration and try creating a new movie.";
279
 
 
280
 
        $(document).trigger("message-console-error", [error, {"sticky": true}]);
281
 
    },
282
 
 
283
 
    /**
284
 
     * Saves the current list of movies
285
 
     */
286
 
    _save: function () {
287
 
        Helioviewer.userSettings.set("history.movies", this._history);
288
 
    }
289
 
});