Google guitar doodle
I consider this code just a stub. Somebody please pick it up and make it perfect :)
/**
* Copyright makc3d ( http://wonderfl.net/user/makc3d )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rYLV
*/
// forked from wh0's Using proxies without crossdomain.xml
package {
import com.bit101.components.Label;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.system.ApplicationDomain;
import flash.system.LoaderContext;
import flash.ui.Keyboard;
//import flash.net.FileReference;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.Security;
import flash.utils.ByteArray;
import flash.utils.setTimeout;
public class FlashTest extends Sprite {
// Wrap url in proxy parameter.
private function proxy(url:String):String {
return 'http://www.gmodules.com/ig/proxy?url=' + encodeURIComponent(url);
}
public function FlashTest () {
//init (null); return;
// Only the top level movie starts off with stage populated.
if (stage) {
// The top level movie is likely included from wonderfl.net and therefore unproxied.
// All we do in this case is load the proxied version.
// Allow the proxy domain so wee can access stage on lines 45-46.
Security.allowDomain('www.gmodules.com');
var l:Loader = new Loader();
l.load(new URLRequest(proxy(loaderInfo.url)));
addChild(l);
return;
} else {
// Allow Wonderfl to take a screen cap.
Security.allowDomain('swf.wonderfl.net');
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// Now you write your own code.
// Since the inner proxied movie is in the proxy's domain, we can request anything.
var ul:URLLoader = new URLLoader;
ul.dataFormat = 'binary';
ul.addEventListener(Event.COMPLETE, complete);
ul.load (new URLRequest (proxy (
'http://static.googleusercontent.com/external_content/untrusted_dlcp/www.google.com.ua/uk/ua/logos/swf/guitar11.swf'
)));
}
private function complete(e:Event):void {
var ul:URLLoader = URLLoader (e.target);
// unfortunately doodle's playTrack() method is private
// and only exposed through ExternalInterface :((
// therefore we need to patch its bytecode before loading it
var uncompressed:ByteArray = decompress (ul.data);
//new FileReference().save (uncompressed);
if (uncompressed [0x1A361] == 5) {
uncompressed [0x1A361] = 22; // change relevant namespace to public
uncompressed [0x1A362] = 1;
uncompressed [0x1A7AA] = 71; // prevent SecurityError (exit constructor early)
// ok to load it
var loader:Loader = new Loader;
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, gotDoodle);
loader.loadBytes (uncompressed,
new LoaderContext (false, ApplicationDomain.currentDomain)
);
} else {
new Label (this, 10, 10, "sorry, doodle swf was updated, this code was not :(");
}
}
private var doodle:*;
private function gotDoodle (e:Event):void {
doodle = LoaderInfo (e.target).content;
stage.addEventListener (KeyboardEvent.KEY_DOWN, onKeyDown);
// now some presets from twitter
new Label (this, 10, 10, "use same keys as in doodle, or pick one of presets");
new PresetButton (this, 10, 40, "Imperial march", "3,,3,,3,,1,,5,3,,1,,5,3,,,,,,7,,7,,7,,8,,5,3,,1,,5,3", playPreset);
new PresetButton (this, 10, 70, "Godfather theme", convertPreset1 ("dhkjhkhjhfgd"), playPreset);
new PresetButton (this, 10, 100, "Moon river", convertPreset1 ("toiuytrtquytrtqw"), playPreset);
}
private var keyCodes:Object = {
1: Keyboard.NUMBER_1,
2: Keyboard.NUMBER_2,
3: Keyboard.NUMBER_3,
4: Keyboard.NUMBER_4,
5: Keyboard.NUMBER_5,
6: Keyboard.NUMBER_6,
7: Keyboard.NUMBER_7,
8: Keyboard.NUMBER_8,
9: Keyboard.NUMBER_9,
0: Keyboard.NUMBER_0,
q: Keyboard.Q,
w: Keyboard.W,
e: Keyboard.E,
r: Keyboard.R,
t: Keyboard.T,
y: Keyboard.Y,
u: Keyboard.U,
i: Keyboard.I,
o: Keyboard.O,
p: Keyboard.P,
a: Keyboard.A,
s: Keyboard.S,
d: Keyboard.D,
f: Keyboard.F,
g: Keyboard.G,
h: Keyboard.H,
j: Keyboard.J,
k: Keyboard.K,
l: Keyboard.L,
z: Keyboard.Z,
x: Keyboard.X,
c: Keyboard.C,
v: Keyboard.V,
b: Keyboard.B,
n: Keyboard.N,
m: Keyboard.M
}
private function playPreset (event:Event):void {
var preset:String = PresetButton (event.target).preset;
var keys:Array = preset.split (",");
for (var i:int = 0; i < keys.length; i++) {
if (String (keys [i]).length == 1) {
trace ("key", keys [i], "code", keyCodes [keys [i]])
setTimeout (onKeyDown, 250 * (i + 1), { keyCode: keyCodes [keys [i]] });
}
}
}
private function convertPreset1 (str:String):String {
return str.split ("").join (",,");
}
// was exposed via ExternalInterface.addCallback
public function playTrack (trackName:String, channelName:String, volume:Number = 1, pan:Number = 0):void {
doodle.playTrack (trackName, channelName, volume, pan);
}
// was exposed via ExternalInterface.addCallback
public function stopChannel (channelName:String):void {
doodle.stopSound (channelName);
}
// keydown handler ("ra" from js)
public function onKeyDown (e:Object):void {
// it's hard to tell what a hell is going on there as
// the code is obfuscated; this is all just a guess
var Y:Number = fixMap [trackIds [e.keyCode]];
if (Y >= 0 && Y < 12) {
playTrack ("guitar-" + (Y < 10 ? "0" : "") + Y, "" + /*Y*/Math.random ());
}
}
// key mappings ("xa" from js)
public var trackIds:Object = {
49: 2,
50: 6,
51: 3,
52: 0,
53: 7,
54: 1,
55: 8,
56: 4,
57: 9,
48: 5,
81: 2,
87: 6,
69: 3,
82: 0,
84: 7,
89: 1,
85: 8,
73: 4,
79: 9,
80: 5,
65: 2,
83: 6,
68: 3,
70: 0,
71: 7,
72: 1,
74: 8,
75: 4,
76: 9,
186: 5,
90: 2,
88: 6,
67: 3,
86: 0,
66: 7,
78: 1,
77: 8,
188: 4,
190: 9,
191: 5
}
// apparently xa variable values do not correspond to track id directly
public var fixMap:Object = {
2: 0,
6: 1,
3: 2,
0: 3,
7: 4,
1: 5,
8: 6,
4: 7,
9: 8,
5: 9
// 2 more notes?
}
/**
* @author Nikita Leshenko
* @see http://active.tutsplus.com/tutorials/workflow/protect-your-flash-files-from-decompilers-by-using-encryption/
*/
private function decompress (data:ByteArray):ByteArray {
var header:ByteArray = new ByteArray;
var compressed:ByteArray = new ByteArray;
var decompressed:ByteArray = new ByteArray;
header.writeBytes (data, 3, 5); // read the uncompressed header, excluding the signature
compressed.writeBytes (data, 8); // read the rest, compressed
compressed.uncompress ();
decompressed.writeMultiByte ("FWS", "us-ascii"); // mark as uncompressed
decompressed.writeBytes (header); // write the header back
decompressed.writeBytes (compressed); // write the now uncompressed content
return decompressed;
}
}
}
import com.bit101.components.PushButton;
import flash.display.DisplayObjectContainer;
class PresetButton extends PushButton {
public var preset:String;
public function PresetButton (parent:DisplayObjectContainer, xpos:Number, ypos:Number, label:String, preset:String, defaultHandler:Function) {
super (parent, xpos, ypos, label, defaultHandler); this.preset = preset;
}
}