stupeflix-client 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +36 -0
- data/Rakefile +1 -0
- data/examples/cli-example.rb +223 -0
- data/examples/conf.rb +25 -0
- data/examples/movie.xml +348 -0
- data/lib/stupeflix.rb +355 -0
- data/lib/stupeflix/base.rb +274 -0
- data/lib/stupeflix/connection.rb +113 -0
- data/lib/stupeflix/version.rb +3 -0
- data/stupeflix-client.gemspec +23 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -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=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
@@ -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
|
+
|
data/examples/conf.rb
ADDED
@@ -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
|
data/examples/movie.xml
ADDED
@@ -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>
|