stupeflix-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NjhmNGM1ZmE1MzBjYTNhYjBjZDM3ZDA4YmEzMjc3ZDdlNjljNzIwMw==
5
+ data.tar.gz: !binary |-
6
+ YzMyMjlmNDk1MjYwMDU1NzAyYTk2OWUzODU2MDg3NDVmMjM5YjczZA==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ NjlkYzY0YjIwNDNhNDk2NTM3M2NmNDRmMzJjNDFmYjU2Mzc0YmI1ZWFkNzVj
10
+ NWYyMzVmNzcxN2ZjYWQzYzQ3ODRhMDcyN2VlYTAwY2E1NDI4ZDY3YWVkYWVj
11
+ NDBmNGJkOTVmOGViNzY5YmM2YjUzY2RiZGIxMzU0M2Y1NWZiOTY=
12
+ data.tar.gz: !binary |-
13
+ MDYyNzhkMzgwYjZiNzQ2NzNmOWFkOTVlZmYwY2IwN2I2ZDczZWNiMzZhNTAw
14
+ NzFiMzk2ZjFjMzNiOWUxYWI2MGY0MTc5NzBlZDFmOTI3OGUyOTBkMWJiZWRi
15
+ ZDFkYzc1Zjc0MjkwZWZjYTBiNDA5MjlkNjM4YzljYjAyYjA2OGY=
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in stupeflix.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Andrea Pavoni
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,36 @@
1
+ # Stupeflix API Ruby client
2
+
3
+ This is a gem-ified version of the [Official Stupeflix API Client](https://github.com/Stupeflix/Stupeflix-API-Client).
4
+ At the moment, I've only took the Ruby code and packed it _as is_ into a gem to get it more usable inside a Ruby/Rails project.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'stupeflix'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install stupeflix
19
+
20
+ ## Usage
21
+
22
+ See the [examples/](https://github.com/apeacox/stupeflix-client/tree/master/examples) folder.
23
+
24
+ ## TODO
25
+
26
+ * add tests (perhaps rspec or minitest/spec would be perfect)
27
+ * refactor code to get closer to the _ruby way_
28
+ * add better builder (I'd use 'builder' gem to keep dependencies simple)
29
+
30
+ ## Contributing
31
+
32
+ 1. Fork it
33
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
34
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
35
+ 4. Push to the branch (`git push origin my-new-feature`)
36
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,223 @@
1
+ require_relative "conf"
2
+ require "stupeflix"
3
+ require "Time"
4
+
5
+ class StupeflixTest
6
+ # including the Stupeflix module here, to avoid to specify namespece
7
+ include Stupeflix
8
+
9
+ def initialize()
10
+ # Create the client to access the API
11
+ # You can safely assume that $stupeflixHost is nil
12
+ @client = StupeflixClient.new($stupeflixAccessKey, $stupeflixSecretKey)
13
+
14
+ # Set the name for the resource to be created
15
+ # These names are alphanumerical, and can be set to whatever you want
16
+ @user = "test"
17
+ @resource = "resource" + $dateString
18
+
19
+ # Configuration for s3 retries
20
+ @s3Retries = 5
21
+ @s3Wait = 1
22
+ # Set this to true if you want to see the status of videos being generated
23
+ @debug = false
24
+ end
25
+
26
+ def uploadsCreate(profileName)
27
+ user = @user
28
+ resource = @resource
29
+ # Array of uploads to be filled in
30
+ uploads = []
31
+
32
+ # Default upload creation : will store to the stupeflix s3 bucket
33
+ # This is not mandatory, just a easy way to store temporarily the result of the video generation.
34
+ uploads += [StupeflixDefaultUpload.new()]
35
+
36
+ # YouTube upload creation, if correct information was entered in conf.rb
37
+ if $youtubeLogin != nil
38
+ # Create sample youtube information
39
+ tags = ["these","are","my","tags"].join(",")
40
+ youtubeInfo = {"title" => "Upload test " + $dateString,
41
+ "description"=> "Upload test description" + $dateString,
42
+ "tags"=>tags,
43
+ "channels"=>"Tech",
44
+ "acl"=>"public",
45
+ "location"=>"49,-3"}
46
+
47
+ youtubeMeta = StupeflixMeta.new(youtubeInfo)
48
+
49
+ # There is no currently notification
50
+ youtubeNotify = nil
51
+ uploads += [StupeflixYoutubeUpload.new($youtubeLogin, $youtubePassword, youtubeMeta, youtubeNotify)]
52
+ end
53
+
54
+ # S3 Upload creation : upload to your own S3 bucket
55
+ if $s3AccessKey != nil
56
+ s3resource = "%s/%s/%s" % [user, resource, "iphone"]
57
+ # Create s3 upload settings
58
+ uploads += [StupeflixS3Upload.new(bucket=$s3Bucket, s3resource, $s3AccessKey, $s3SecretKey)]
59
+ end
60
+
61
+ # HTTP Uploads creation : POST and PUT
62
+ if $httpUploadPrefix != nil
63
+ # Create http POST upload settings
64
+ postURL = $httpUploadPrefix + "post/%s/%s/%s" % [user, resource, profileName]
65
+ uploads += [StupeflixHttpPOSTUpload.new(postURL)]
66
+
67
+ # Create http PUT upload settings
68
+ putURL = $httpUploadPrefix + "put/%s/%s/%s" % [user, resource, profileName]
69
+ uploads += [StupeflixHttpPUTUpload.new(putURL)]
70
+ end
71
+ return uploads
72
+ end
73
+
74
+ def availableKey(rank, suffix = "id")
75
+ return "available-" + rank.to_s() + "-" + suffix
76
+ end
77
+
78
+ # Check that all went fine, until every upoads is finished (or went on error)
79
+ def waitForCompletion(uploadCount)
80
+ error = false
81
+ # Then wait for the generation to complete
82
+ available = false
83
+ status = nil
84
+ error = false
85
+
86
+ while not available and not error
87
+ # Retrieve an array of status for every profiles for user and resource
88
+ status = @client.getStatus(@user, @resource, nil)
89
+ # Variable to test if every profile is available
90
+ for s in status
91
+ if @debug
92
+ puts s
93
+ end
94
+ available = true
95
+ for id in 0..uploadCount - 1
96
+ availableKey = availableKey(id)
97
+ availableType = availableKey(id, "type")
98
+ if not s["status"].has_key?(availableKey)
99
+ if @debug
100
+ puts "upload #" + id.to_s() + " not yet ready for profile " + s["profile"]
101
+ end
102
+ available = false
103
+ break
104
+ else
105
+ if @debug
106
+ puts "upload #" + id.to_s() + " '" + s["status"][availableType] + "' ready for profile " + s["profile"]
107
+ end
108
+ end
109
+ end
110
+ if s["status"]["status"] == "error"
111
+ error = true
112
+ break
113
+ end
114
+ end
115
+ sleep(5)
116
+ end
117
+ # if available if false, that means that an error occurred
118
+ return available, status
119
+ end
120
+
121
+ #Sometimes we have to wait for s3 to make the content available (this is in the Amazon S3 spec). This function is built to do just that.
122
+ def s3WaitLoop()
123
+ s3Wait = @s3Wait
124
+ for i in 0..@s3Retries - 1
125
+ begin
126
+ yield nil
127
+ rescue
128
+ if (i + 1) == @s3Retries
129
+ raise $!
130
+ else
131
+ sleep(s3Wait)
132
+ s3Wait *= 2
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ #This is the main function for creating videos, with main calls to the Stupeflix API.
139
+ def run()
140
+ profileNames = ["iphone"] # You can add profiles there : "flash-small, quicktime, dvd ..."
141
+ profileArray = []
142
+ for profileName in profileNames
143
+ uploads = uploadsCreate(profileName)
144
+ # Create a new profile.
145
+ profileArray += [StupeflixProfile.new(profileName, uploads = uploads)]
146
+ end
147
+
148
+ # Notification is not configured there : this consists in a series of HTTP POST ping requests to your own server.
149
+ # This is much more powerful than polling the API as demonstrated in function waitForCompletion.
150
+ notify = nil
151
+ # Uncomment this line if you want to test notification. StatusRegexp is used to filter notification sent to your server.
152
+ # Here, only final "available message" would be sent
153
+ # notify = StupeflixNotify.new(url = "http://myserver.com/mypath", statusRegexp = "available")
154
+
155
+ # Create the set of profiles to be created
156
+ profiles = StupeflixProfileSet.new(profileArray, meta = nil, notify = notify)
157
+
158
+ # This is only used to give proper names to output files (file names are appended with a proper extension)
159
+ extensions = ["mp4"] # flv ...
160
+
161
+ # Calls to the API start there
162
+
163
+ # First send the movie definition file to the service. (see sample movie.xml in this directory)
164
+ @client.sendDefinition(@user, @resource, $filename)
165
+
166
+ # Then launch the generation, using the configuration we have built earlier
167
+ @client.createProfiles(@user, @resource, profiles)
168
+
169
+ # Poll the API, waiting for completion
170
+ available, status = waitForCompletion(uploadCount = uploads.length)
171
+
172
+ # Check if everything went fine
173
+ if not available
174
+ # Something went bad: at least some part of the task was not complete, but some may still have or even was uploaded.
175
+ # This may happen for example if upload to youtube failed but upload to your own server succeeded.
176
+ # an error occured, the status will give more information
177
+ s = ""
178
+ status.each {|element|
179
+ s += [element["accesskey"], element["user"], element["resource"], element["profile"]].join(",")
180
+ s += ":\n "
181
+ element["status"].sort.each { |key, value|
182
+ s += "#{key} => #{value}, \n "
183
+ }
184
+ s += "\n"
185
+ }
186
+ raise s
187
+ end
188
+
189
+ # Download all profiles
190
+ i = 0
191
+ profileNames.each do |p|
192
+ # Print the profile url were the video can be found
193
+ puts "movie url= " + @client.getProfileUrl(@user, @resource, p)
194
+ movieName = "%smovie.%s" % [p, extensions[i]]
195
+ puts "Download movie to file " + movieName
196
+ s3WaitLoop { |n|
197
+ @client.getProfile(@user, @resource, p, movieName)
198
+ }
199
+
200
+ # Download the profile thumb url
201
+ thumbName = "thumb_%s.jpg" % p
202
+ puts "Download movie thumb to file " + thumbName
203
+ s3WaitLoop { |n|
204
+ @client.getProfileThumb(@user, @resource, p, thumbName)
205
+ }
206
+
207
+ i += 1
208
+ end
209
+
210
+ puts "Test succeeded."
211
+ end
212
+ end
213
+
214
+
215
+ # Test if the keys were set
216
+ if $stupeflixAccessKey == nil
217
+ puts "ERROR : Please fill in key information in conf.rb"
218
+ exit(0)
219
+ end
220
+
221
+ test = StupeflixTest.new()
222
+ test.run()
223
+
@@ -0,0 +1,25 @@
1
+ # required API keys
2
+ $stupeflixAccessKey = ENV["STUPEFLIX_KEY"]
3
+ $stupeflixSecretKey = ENV["STUPEFLIX_SECRET"]
4
+
5
+ # These are optional variables, by default read from the environement variables,
6
+ # but you can too override them with your own credentials directly
7
+
8
+ $youtubeLogin = ENV["YOUTUBE_LOGIN"]
9
+ $youtubePassword = ENV["YOUTUBE_PASSWORD"]
10
+ $s3AccessKey = ENV["S3_ACCESS_KEY"]
11
+ $s3SecretKey = ENV["S3_SECRET_KEY"]
12
+ $s3Bucket = ENV["S3_BUCKET"]
13
+ $httpUploadPrefix = ENV["HTTP_UPLOAD_PREFIX"]
14
+
15
+ if ENV["STUPEFLIX_TEST_TIME"] == nil
16
+ t = Time.now
17
+ $dateString = t.strftime("%Ya%ma%da%Ha%Ma%S")
18
+ else
19
+ $dateString = ENV["STUPEFLIX_TEST_TIME"]
20
+ end
21
+
22
+ $filename = ENV["STUPEFLIX_MOVIE"]
23
+ if $filename == nil
24
+ $filename = "movie.xml"
25
+ end
@@ -0,0 +1,348 @@
1
+ <movie service="craftsman-1.0">
2
+ <body>
3
+ <!-- Top level stack: contains the soundtrack and the video itself-->
4
+ <stack>
5
+ <!-- Add a movie wide soundtrack: duration of the soundtrack is dependant on the up node (stack) using duration =".." -->
6
+ <!-- Silence, L'autre endroit: http://www.jamendo.com/fr/album/830 -->
7
+ <audio filename="http://assets.stupeflix.com/code/ebusinessvideo/soundtracks/Realite.mp3" volume="0.5" fadeout="4.0" duration=".."/>
8
+ <!-- Top level sequence -->
9
+ <sequence>
10
+ <!-- First part: sequence of two background images with a single text overlay -->
11
+ <stack duration="6.0">
12
+ <!-- Sequence of images -->
13
+ <sequence>
14
+ <!-- Classical kenburns effect -->
15
+ <effect type="kenburns" duration="3.5">
16
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/file_11.jpg">
17
+ <!-- Small trick: Add a small white frame with no transparency to the image to reduce it at rendering time => no edit of the image is needed -->
18
+ <filter type="frame" width="0.1" color="#FFFFFFFF"/>
19
+ </image>
20
+ </effect>
21
+ <!-- Transition between the two background images -->
22
+ <transition type="move" duration="1.0"/>
23
+ <!-- Same effect for the second background image -->
24
+ <effect type="kenburns" duration="3.5">
25
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/file_10.jpg">
26
+ <filter type="frame" width="0.1" color="#FFFFFFFF"/>
27
+ </image>
28
+ </effect>
29
+ </sequence>
30
+ <!-- Text overlay with shadow: shadow is currently created duplicating the text in black with some blur added-->
31
+ <!-- NB: newlines are currently ignored at the start and end of text, so this xml is indented to ease the explanations, but you should not add extra newlines in
32
+ your own xml. -->
33
+
34
+ <!-- Text like placement using left, bottom and height. Apply black font color as this is the shadow. -->
35
+ <text type="zone" left="0.09" bottom="0.13" height="0.18" fontcolor="#000000">
36
+ EOS 50D:
37
+ <!-- Animator: grow will slowly increase text size (implemented by moving the text near the camera in 3D)-->
38
+ <animator type="grow" />
39
+ <!-- Make the text appear in 1 second, sliding from the left -->
40
+ <animator type="slide-in" direction="left" duration="1.0"/>
41
+ <!-- Make the text disappear in 1 second, sliding from the left -->
42
+ <animator type="slide-out" direction="left" duration="1.0"/>
43
+ <!-- Make the text slowly move to improve attractiveness -->
44
+ <animator type="slide" direction="left" duration="6.0"/>
45
+ <!-- Text will appear in 1.5s from totally transparent, to totally opaque (in addition to the slide-in effect) -->
46
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
47
+ <!-- Text will disappear in 1.5s from totally opaque, to totally transparent (in addition to the slide-out effect) -->
48
+ <!-- Note the margin-end that will fix the effect to the end of text effect. (just like a CSS property, but for time) -->
49
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
50
+ <!-- Add a blur effect to soften shadow edges -->
51
+ <filter type="blur" diameter="2.0"/>
52
+ </text>
53
+ <!-- Text itself: same xml, with slight variations on position and color-->
54
+ <!-- Text color is almost white -->
55
+ <text type="zone" left="0.1" bottom="0.12" height="0.18" fontcolor="#DDDDDD">
56
+ EOS 50D:
57
+ <animator type="grow" duration="6.0"/>
58
+ <animator type="slide-in" direction="left" duration="1.0"/>
59
+ <animator type="slide-out" direction="left" duration="1.0"/>
60
+ <animator type="slide" direction="left" duration="6.0"/>
61
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
62
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
63
+ </text>
64
+ <!-- Same tricks for the rest of text -->
65
+ <text type="zone" left="0.09" bottom="0.01" height="0.18" fontcolor="#000000">
66
+ Explore photography
67
+ <animator type="grow" duration="6.0"/>
68
+ <animator type="slide-in" direction="right" duration="1.0"/>
69
+ <animator type="slide-out" direction="right" duration="1.0"/>
70
+ <animator type="slide" direction="right" duration="6.0"/>
71
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
72
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
73
+ <filter type="blur" diameter="2.0"/>
74
+ </text>
75
+ <text type="zone" left="0.1" bottom="0.0" height="0.18" fontcolor="#DDDDDD">
76
+ Explore photography
77
+ <animator type="grow" duration="6.0"/>
78
+ <animator type="slide-in" direction="right" duration="1.0"/>
79
+ <animator type="slide-out" direction="right" duration="1.0"/>
80
+ <animator type="slide" direction="right" duration="6.0"/>
81
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
82
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
83
+ </text>
84
+ </stack>
85
+ <!-- Transition -->
86
+ <transition type="cube" duration="1.0"/>
87
+ <!-- Second camera image set: basically same set of effects-->
88
+ <stack duration="6.0">
89
+ <sequence>
90
+ <effect type="kenburns" duration="3.5">
91
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/file_13.jpg">
92
+ <filter type="frame" width="0.1" color="#FFFFFFFF"/>
93
+ </image>
94
+ </effect>
95
+ <transition type="under" duration="1.0"/>
96
+ <effect type="kenburns" duration="3.5">
97
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/file_07.jpg">
98
+ <filter type="frame" width="0.1" color="#FFFFFFFF"/>
99
+ </image>
100
+ </effect>
101
+ </sequence>
102
+ <text type="zone" left="0.09" bottom="0.13" height="0.18" fontcolor="#000000">
103
+ 15.1 Megapixels,
104
+ <animator type="grow" duration="6.0"/>
105
+ <animator type="slide-in" direction="left" duration="1.0"/>
106
+ <animator type="slide-out" direction="left" duration="1.0"/>
107
+ <animator type="slide" direction="left" duration="6.0"/>
108
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
109
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
110
+ <filter type="blur" diameter="2.0"/>
111
+ </text>
112
+ <text type="zone" left="0.1" bottom="0.12" height="0.18" fontcolor="#DDDDDD">
113
+ 15.1 Megapixels,
114
+ <animator type="grow" duration="6.0"/>
115
+ <animator type="slide-in" direction="left" duration="1.0"/>
116
+ <animator type="slide-out" direction="left" duration="1.0"/>
117
+ <animator type="slide" direction="left" duration="6.0"/>
118
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
119
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
120
+ </text>
121
+ <text type="zone" left="0.09" bottom="0.01" height="0.18" fontcolor="#000000">
122
+ Bright 3" LCD
123
+ <animator type="grow" duration="6.0"/>
124
+ <animator type="slide-in" direction="right" duration="1.0"/>
125
+ <animator type="slide-out" direction="right" duration="1.0"/>
126
+ <animator type="slide" direction="right" duration="6.0"/>
127
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
128
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
129
+ <filter type="blur" diameter="2.0"/>
130
+ </text>
131
+ <text type="zone" left="0.1" bottom="0.0" height="0.18" fontcolor="#DDDDDD">
132
+ Bright 3" LCD
133
+ <animator type="grow" duration="6.0"/>
134
+ <animator type="slide-in" direction="right" duration="1.0"/>
135
+ <animator type="slide-out" direction="right" duration="1.0"/>
136
+ <animator type="slide" direction="right" duration="6.0"/>
137
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.5"/>
138
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.5"/>
139
+ </text>
140
+ </stack>
141
+ <transition type="move" duration="1.0"/>
142
+ <!-- Third Image Set : single image with a set of logo added to the right -->
143
+ <stack duration="6.0">
144
+ <stack duration="6.0">
145
+ <sequence>
146
+ <effect type="kenburns" duration="6.0">
147
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/file_12.jpg">
148
+ <filter type="frame" width="0.1" color="#FFFFFFFF"/>
149
+ </image>
150
+ </effect>
151
+ </sequence>
152
+ </stack>
153
+ <!-- Sets of small feature logo on the right: number of megapixels, lcd size, digic logo etc ...-->
154
+ <!-- overlay position is CSS like properties, just like for text: top and right margin + height, in fraction of height / width -->
155
+ <overlay top="0.05" right="0.02" height="0.16">
156
+ <!-- Base Image -->
157
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/megapixels.gif"/>
158
+ <!-- Apparition animation : slide-in, and time margin -->
159
+ <animator duration="1.0" type="slide-in" margin-start="0.0"/>
160
+ <!-- Disparition animation : slide-out, time margin, and direction -->
161
+ <animator duration="1.0" type="slide-out" margin-end="0.8" direction="right" />
162
+ </overlay>
163
+ <overlay top="0.23" right="0.02" height="0.16">
164
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/lcd_size.gif"/>
165
+ <!-- margin-start is increased from an image to the next one, to shift apparition of logos -->
166
+ <animator duration="1.0" type="slide-in" margin-start="0.5"/>
167
+ <!-- margin-end is dereased from an image to the next one, to shift disparition of logos -->
168
+ <animator duration="1.0" type="slide-out" margin-end="0.6" direction="right"/>
169
+ </overlay>
170
+ <!-- So on ... -->
171
+ <overlay top="0.41" right="0.02" height="0.16">
172
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/digic4.gif"/>
173
+ <animator duration="1.0" type="slide-in" margin-start="1.0"/>
174
+ <animator duration="1.0" type="slide-out" margin-end="0.4" direction="right"/>
175
+ </overlay>
176
+ <overlay top="0.59" right="0.02" height="0.16">
177
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/liveview.gif"/>
178
+ <animator duration="1.0" type="slide-in" margin-start="1.5"/>
179
+ <animator duration="1.0" type="slide-out" margin-end="0.2" direction="right" />
180
+ </overlay>
181
+ <overlay top="0.77" right="0.02" height="0.16">
182
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/pictbridge.gif"/>
183
+ <animator duration="1.0" type="slide-in" margin-start="2.0"/>
184
+ <animator duration="1.0" type="slide-out" margin-end="0.0" direction="right"/>
185
+ </overlay>
186
+ </stack>
187
+ <transition type="crossfade" duration="0.3"/>
188
+ <!-- Fourth part: slideshow of photos take with the camera -->
189
+ <stack duration="12.0">
190
+ <!-- Multi image effect : several images on the same scene, with rotation between each couple.-->
191
+ <effect type="rotator" duration="12.0">
192
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/2008-10-14_14-09-18.jpg">
193
+ <filter type="borderBlur" transWidth="0.05" width="0.0"/>
194
+ </image>
195
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/2008-10-10_17-08-27.jpg">
196
+ <filter type="borderBlur" transWidth="0.05" width="0.0"/>
197
+ </image>
198
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/2008-10-10_15-55-14.jpg">
199
+ <filter type="borderBlur" transWidth="0.05" width="0.0"/>
200
+ </image>
201
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/2008-10-10_14-03-50.jpg">
202
+ <filter type="borderBlur" transWidth="0.05" width="0.0"/>
203
+ </image>
204
+ </effect>
205
+ <!-- Same shadow / text effects as previously -->
206
+ <text type="zone" left="0.09" bottom="0.11" height="0.13" fontcolor="#000000">
207
+ Improved noise reduction:
208
+ <animator type="grow" duration="12.0"/>
209
+ <animator type="slide-in" direction="left" duration="2.0"/>
210
+ <animator type="slide-out" direction="left" duration="2.0"/>
211
+ <animator type="slide" direction="left" duration="12.0"/>
212
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="3.0"/>
213
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="3.0"/>
214
+ <filter type="blur" diameter="2.0"/>
215
+ </text>
216
+ <text type="zone" left="0.1" bottom="0.1" height="0.13" fontcolor="#FFFFFF">
217
+ Improved noise reduction:
218
+ <animator type="grow" duration="12.0"/>
219
+ <animator type="slide-in" direction="left" duration="2.0"/>
220
+ <animator type="slide-out" direction="left" duration="2.0"/>
221
+ <animator type="slide" direction="left" duration="12.0"/>
222
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="3.0"/>
223
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="3.0"/>
224
+ </text>
225
+ <text type="zone" left="0.09" bottom="0.03" height="0.13" fontcolor="#000000">
226
+ exceptional image quality
227
+ <animator type="grow" duration="12.0"/>
228
+ <animator type="slide-in" direction="right" duration="2.0"/>
229
+ <animator type="slide-out" direction="right" duration="2.0"/>
230
+ <animator type="slide" direction="right" duration="12.0"/>
231
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="3.0"/>
232
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="3.0"/>
233
+ <filter type="blur" diameter="2.0"/>
234
+ </text>
235
+ <text type="zone" left="0.1" bottom="0.02" height="0.13" fontcolor="#FFFFFF">
236
+ exceptional image quality
237
+ <animator type="grow" duration="12.0"/>
238
+ <animator type="slide-in" direction="right" duration="2.0"/>
239
+ <animator type="slide-out" direction="right" duration="2.0"/>
240
+ <animator type="slide" direction="right" duration="12.0"/>
241
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="3.0"/>
242
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="3.0"/>
243
+ </text>
244
+ </stack>
245
+ <transition type="crossfade" duration="1.0"/>
246
+ <!-- Fifth part : first journalist comment -->
247
+ <stack duration="4.0">
248
+ <text type="zone" left="0.09" bottom="0.53" height="0.18" fontcolor="#000000">
249
+ "High-speed and perfect quality"
250
+ <animator type="grow" duration="4.0"/>
251
+ <animator type="slide-in" direction="left" duration="0.666666666667"/>
252
+ <animator type="slide-out" direction="left" duration="0.666666666667"/>
253
+ <animator type="slide" direction="left" duration="4.0"/>
254
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
255
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
256
+ <filter type="blur" diameter="2.0"/>
257
+ </text>
258
+ <text type="zone" left="0.1" bottom="0.52" height="0.18" fontcolor="#DDDDDD">
259
+ "High-speed and perfect quality"
260
+ <animator type="grow" duration="4.0"/>
261
+ <animator type="slide-in" direction="left" duration="0.666666666667"/>
262
+ <animator type="slide-out" direction="left" duration="0.666666666667"/>
263
+ <animator type="slide" direction="left" duration="4.0"/>
264
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
265
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
266
+ </text>
267
+ <text type="zone" left="0.09" bottom="0.41" height="0.18" fontcolor="#000000">
268
+ The Photographer
269
+ <animator type="grow" duration="4.0"/>
270
+ <animator type="slide-in" direction="right" duration="0.666666666667"/>
271
+ <animator type="slide-out" direction="right" duration="0.666666666667"/>
272
+ <animator type="slide" direction="right" duration="4.0"/>
273
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
274
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
275
+ <filter type="blur" diameter="2.0"/>
276
+ </text>
277
+ <text type="zone" left="0.1" bottom="0.4" height="0.18" fontcolor="#DDDDDD">
278
+ The Photographer
279
+ <animator type="grow" duration="4.0"/>
280
+ <animator type="slide-in" direction="right" duration="0.666666666667"/>
281
+ <animator type="slide-out" direction="right" duration="0.666666666667"/>
282
+ <animator type="slide" direction="right" duration="4.0"/>
283
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
284
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
285
+ </text>
286
+ </stack>
287
+ <transition type="crossfade" duration="1.0"/>
288
+ <!-- Sixth part : second journalist comment -->
289
+ <stack duration="4.0">
290
+ <text type="zone" left="0.09" bottom="0.33" height="0.18" fontcolor="#000000">
291
+ "Feature-packed and affordable."
292
+ <animator type="grow" duration="4.0"/>
293
+ <animator type="slide-in" direction="left" duration="0.666666666667"/>
294
+ <animator type="slide-out" direction="left" duration="0.666666666667"/>
295
+ <animator type="slide" direction="left" duration="4.0"/>
296
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
297
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
298
+ <filter type="blur" diameter="2.0"/>
299
+ </text>
300
+ <text type="zone" left="0.1" bottom="0.32" height="0.18" fontcolor="#DDDDDD">
301
+ "Feature-packed and affordable."
302
+ <animator type="grow" duration="4.0"/>
303
+ <animator type="slide-in" direction="left" duration="0.666666666667"/>
304
+ <animator type="slide-out" direction="left" duration="0.666666666667"/>
305
+ <animator type="slide" direction="left" duration="4.0"/>
306
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
307
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
308
+ </text>
309
+ <text type="zone" left="0.09" bottom="0.21" height="0.18" fontcolor="#000000">
310
+ Camera online
311
+ <animator type="grow" duration="4.0"/>
312
+ <animator type="slide-in" direction="right" duration="0.666666666667"/>
313
+ <animator type="slide-out" direction="right" duration="0.666666666667"/>
314
+ <animator type="slide" direction="right" duration="4.0"/>
315
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
316
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
317
+ <filter type="blur" diameter="2.0"/>
318
+ </text>
319
+ <text type="zone" left="0.1" bottom="0.2" height="0.18" fontcolor="#DDDDDD">
320
+ Camera online
321
+ <animator type="grow" duration="4.0"/>
322
+ <animator type="slide-in" direction="right" duration="0.666666666667"/>
323
+ <animator type="slide-out" direction="right" duration="0.666666666667"/>
324
+ <animator type="slide" direction="right" duration="4.0"/>
325
+ <filter type="alpha" alphaStart="0.0" alphaEnd="1.0" duration="1.0"/>
326
+ <filter type="alpha" margin-end="0.0" alphaStart="1.0" alphaEnd="0.0" duration="1.0"/>
327
+ </text>
328
+ </stack>
329
+ <transition type="crossfade" duration="0.5"/>
330
+ <!-- Finally the Stupeflix end animation -->
331
+ <effect duration="1.6" type="none">
332
+ <!-- A single blank image -->
333
+ <image color="#FFFFFF"/>
334
+ </effect>
335
+ <transition type="move" duration="1" direction="up"/>
336
+ <!-- First logo, without subtitle-->
337
+ <effect duration="2.5" type="none">
338
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/logo1.jpg"/>
339
+ </effect>
340
+ <transition type="circle" duration="1"/>
341
+ <!-- Identical logo, with subtitile => transition will make it appear -->
342
+ <effect duration="3" type="none">
343
+ <image filename="http://assets.stupeflix.com/code/ebusinessvideo/images/logo2.jpg"/>
344
+ </effect>
345
+ </sequence>
346
+ </stack>
347
+ </body>
348
+ </movie>