stupeflix-client 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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>
|