JW Player 5.2 Autostart BUG: Ticket #928

Posted on July 17th, 2010 by admin  No Comments »

Hi there,

My awesome twin brother and I recently re-launched our super-cool-oh-my-gosh-this-rocks website www.3am.co.za

With the relaunch we changed frameworks and our old Flash media player no longer could do the job.
I looked into using the awesome Flowplayer but was suggested by my good friend Bruno
(balexandre #magento) to use JW player from Longtail.

I built the flash JW Player into my Magento website and started plugging in my samples.
The JW Player is quite cool, and it took me a couple of days to get to grips with the framework and how it functions. When all was setup I noticed that my Autostart function doesn’t work. This was bad because of the following.

- When a user click on a song to play, it would start the autoplay, and downloading the song, but no sound would come through
- The user then had to click Pause and then Play for the song to start playing.

So 3 clicks made a play.

I then decided to look into it and came across this BUG post.

The fix there was stated by Pablo as

This issue can probably be tracked down to the following line: trunk/fl5/src/com/longtailvideo/jwplayer/media/SoundMediaProvider.as#L150

Replace

if (_sound.isBuffering == true && _sound.bytesTotal > _sound.bytesLoaded) {

with

if (_sound.isBuffering == true && _sound.bytesTotal > _sound.bytesLoaded > 0) {

So I decided to give it a try, nevermind the fact that I have never in my life compiled Actionscript. But hey..more on that later. See my blog Post on How to Compile Actionscript and JW Player 5.2

This change did not make a huge difference so I went back into the code this morning and came up with this:
In the file:
/trac/browser/trunk/fl5/src/com/longtailvideo/jwplayer/media/SoundMediaProvider.as#L150″>trunk/fl5/src/com/longtailvideo/jwplayer/media/SoundMediaProvider.as

I changed this protected function positionHandler(progressEvent:ProgressEvent=null):void function

For sake of clarity I’m just going to paste the whole file. Look for my changes around Line 141, Line 144, Line 155 and Line 157. Let me just tell you now, that I have NEVER in my whole entire life written even one line of ActionScript. This code is not the prettiest, but as you can see on this page it does work :)

/**
 * Wrapper for playback of mp3 sounds.
 **/
package com.longtailvideo.jwplayer.media {
 import com.jeroenwijering.events.*;
 import com.longtailvideo.jwplayer.events.MediaEvent;
 import com.longtailvideo.jwplayer.model.PlayerConfig;
 import com.longtailvideo.jwplayer.model.PlaylistItem;
 import com.longtailvideo.jwplayer.player.PlayerState;

 import flash.events.*;
 import flash.media.*;
 import flash.net.URLRequest;
 import flash.utils.*;

 public class SoundMediaProvider extends MediaProvider {
 /** _sound object to be instantiated. **/
 private var _sound:Sound;
 /** Sound control object. **/
 private var _transformer:SoundTransform;
 /** Sound _channel object. **/
 private var _channel:SoundChannel;
 /** Sound _context object. **/
 private var _context:SoundLoaderContext;
 /** ID for the position interval. **/
 protected var _positionInterval:Number;
 /** Whether the buffer has filled **/
 private var _bufferFull:Boolean;
 /** Whether the enitre video has been buffered **/
 private var _bufferingComplete:Boolean;
 /** User-defined item duration **/
 private var _userDuration:Number = -1;

 /** Constructor; sets up the connection and display. **/
 public function SoundMediaProvider() {
 super('_sound');

 }

 public override function initializeMediaProvider(cfg:PlayerConfig):void {
 super.initializeMediaProvider(cfg);
 _transformer = new SoundTransform();
 _context = new SoundLoaderContext(config.bufferlength * 1000, true);
 }

 /** Sound completed; send event. **/
 private function completeHandler(evt:Event):void {
 complete();
 }

 /** Catch errors. **/
 private function errorHandler(evt:ErrorEvent):void {
 stop();
 error(evt.text);
 }

 /** Forward ID3 data from the _sound. **/
 private function id3Handler(evt:Event):void {
 try {
 var id3:ID3Info = _sound.id3;
 var obj:Object = {type: 'id3', album: id3.album,
 artist: id3.artist, comment: id3.comment,
 genre: id3.genre, name: id3.songName, track: id3.track,
 year: id3.year}
 sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_META, {metadata:obj});
 } catch (err:Error) {
 }
 }

 /** Load the _sound. **/
 override public function load(itm:PlaylistItem):void {
 _position = 0;
 _bufferFull = false;
 _bufferingComplete = false;
 _userDuration = itm.duration > 0 ? itm.duration : -1;
 if (!_item || _item.file != itm.file) {
 _item = itm;
 _sound = new Sound();
 _sound.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);
 _sound.addEventListener(Event.ID3, id3Handler);
 _sound.addEventListener(ProgressEvent.PROGRESS, positionHandler);
 _sound.load(new URLRequest(encodeURI(_item.file)), _context);
 }
 if (!_positionInterval) {
 _positionInterval = setInterval(positionHandler, 100);
 }

 sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_LOADED);
 setState(PlayerState.BUFFERING);
 sendBufferEvent(0);
 streamVolume(config.mute ? 0 : config.volume);
 }

 /** Pause the _sound. **/
 override public function pause():void {
 if (_positionInterval){
 clearInterval(_positionInterval);
 _positionInterval = undefined;
 }
 if (_channel) {
 _channel.stop();
 }
 super.pause();
 }

 /** Play the _sound. **/
 override public function play():void {
 if (position == 0 && _item.start > 0) {
 seek(item.start);
 return;
 }
 if (!_positionInterval) {
 _positionInterval = setInterval(positionHandler, 100);
 }
 if (_channel){
 _channel.stop();
 _channel = null;
 }
 _channel = _sound.play(_position * 1000, 0, _transformer);
 _channel.addEventListener(Event.SOUND_COMPLETE, completeHandler);
 super.play();
 }

 /** Interval for the _position progress **/
 protected function positionHandler(progressEvent:ProgressEvent=null):void {
 var bufferPercent:Number;

 if (_sound.bytesTotal > 0 && _sound.bytesLoaded / _sound.bytesTotal > 0.1 && (_item.duration <= 0 || _userDuration < 0)) {
 _item.duration = _sound.length / 1000 / _sound.bytesLoaded * _sound.bytesTotal;
 }

 if (_channel && _sound && _sound.bytesTotal > 0) {
 _position = Math.round(_channel.position / 100) / 10;
 bufferPercent = Math.floor(_sound.bytesLoaded / _sound.bytesTotal * 100);
 } else if (!_channel && progressEvent && progressEvent.bytesTotal > 0) {
 bufferPercent = Math.floor(progressEvent.bytesLoaded / progressEvent.bytesTotal * 100);
 } else {
 bufferPercent = 0;
 }

 //if (_sound.isBuffering == true && _sound.bytesTotal > _sound.bytesLoaded) {
 if (_sound.isBuffering == true && _sound.bytesTotal > _sound.bytesLoaded > 0) {
 if (state != PlayerState.BUFFERING) {
 //_bufferFull = false;
 _bufferFull = true;
 if (_channel) {
 _channel.stop();
 play();
 }
 if (!progressEvent) {
 setState(PlayerState.BUFFERING);
 }
 }
 } else if (state == PlayerState.BUFFERING && _sound.bytesLoaded > 0 && !_bufferFull) {
 //_bufferFull = true;
 _bufferFull = false;
 //sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_BUFFER_FULL);
 play();
 }

 if (!isNaN(bufferPercent) && !_bufferingComplete){
 if (bufferPercent == 100 && _bufferingComplete == false) {
 _bufferingComplete = true;
 }
 sendBufferEvent(bufferPercent, 0, {loaded:_sound.bytesLoaded, total:_sound.bytesTotal});
 }

 if (state != PlayerState.PLAYING) {
 return;
 }

 if (_position < _item.duration) {
 sendMediaEvent(MediaEvent.JWPLAYER_MEDIA_TIME, {position: _position, duration: _item.duration});
 } else if (_item.duration > 0) {
 complete();
 }
 }

 /** Seek in the _sound. **/
 override public function seek(pos:Number):void {
 if (_sound && _sound.bytesTotal > 0 && (pos < (_sound.bytesLoaded / _sound.bytesTotal) * item.duration) || item.start) {
 clearInterval(_positionInterval);
 _positionInterval = undefined;
 if (_channel) {
 _channel.stop();
 }
 _position = pos;
 play();
 }
 }

 /** Destroy the _sound. **/
 override public function stop():void {
 clearInterval(_positionInterval);
 _positionInterval = undefined;
 super.stop();
 if (_channel) {
 _channel.stop();
 _channel = null;
 }
 try {
 _sound.close();
 } catch (err:Error) {
 }
 }

 /** Set the volume level. **/
 override public function setVolume(vol:Number):void {
 streamVolume(vol);
 super.setVolume(vol);
 }

 /** Set the stream's volume, without sending a volume event **/
 protected function streamVolume(level:Number):void {
 _transformer.volume = level / 100;
 if (_channel) {
 _channel.soundTransform = _transformer;
 }
 }
 }
}

Okay, so now we have that covered. I’ll submit my changes to the Longtail forums and then maybe a pro can make some changes – and then we have opensource going – and then we can all go and drink some beer at the Pub *YAY!*

I hope this helps you in any way,

Winston

Magento Contact Us – Unable to submit your request. Please, try again later error

Posted on May 8th, 2010 by star  No Comments »

I had an issue with Magento CE Version 1.4.0.1 where an email would not be sent when a visitor used the contact us page, I found the fix using Google, on ScreencastWorld

In WEBROOT/app/design/frontend/base/default/template/contacts/form.phtml
Look for

<div class="buttons-set">

It should look like this, the important part is the input file name=”hideit”

<div class="buttons-set">
        <p class="required"><?php echo Mage::helper('contacts')->__('* Required Fields') ?></p>
        <input type="text" name="hideit" id="hideit" value="" style="display:none !important;" />
        <button type="submit" title="<?php echo Mage::helper('contacts')->__('Submit') ?>" class="button"><span><span><?php echo Mage::helper('contacts')->__('Submit') ?></span></span></button>
</div>

Good luck !

Add All products in Cart to Wishlist

Posted on April 6th, 2010 by admin  No Comments »

Want to add all the products in your cart to your Wishlist, in one click?
I’ll show you how to do it here ;) This procedure will take you 5 Minutes

We will begin to override the Wishlist Controller.
We do this by creating a folder called Mycompany in your webroot /app/code/local/ and inside it, we’ll add the folder: Addcwl

Inside this folder we will create two extra folders:

etc
controllers

Now, we are ready to begin:

In WEBROOT/app/code/local/Mycompany/Addcwl/etc/ create the file config.xml
Inside this file put the following,

<?xml version="1.0" encoding="utf-8" ?>
<config>
   <!-- snip -->
   <frontend>
      <routers>
         <wishlist>
            <args>
               <modules>
                  <Mycompany_Addcwl before="Mage_Wishlist">
                            Mycompany_Addcwl
                 </Mycompany_Addcwl>
               </modules>
            </args>
         </wishlist>
      </routers>
   </frontend>
</config>

The above code allows you to override the Wishlist controller :)

Now, in WEBROOT/app/code/local/Mycompany/Addcwl/controllers/ create the file

IndexController.php

Inside this file put the following:

<?php

 * @category   BUYX
 * @package
 * @copyright  Copyright (c)
 * @license    http://opensource.org/licenses/osl-3.0.php  Open Software License (OSL 3.0)
 */

/**
 * Wishlist front controller
 *
 * @category   BUYX
 * @package
 * @author     Winston nolan <winston@buyxonline.com>
 */

include_once("Mage/Wishlist/controllers/IndexController.php");

class Mycompany_Addcwl_IndexController extends Mage_Wishlist_IndexController
{
	//we test our controller override with this
	/*
	public function indexAction()
	    {
	        # Just to make sure
	        error_log('Yes, I did it!');
	        parent::indexAction();
	    }
	*/

    /**
     * Adding new item
     */

    public function addcartAction()
    {
        $session = Mage::getSingleton('customer/session');
        $wishlist = $this->_getWishlist();
        if (!$wishlist) {
            $this->_redirect('*/');
            return;
        }
        // We store the id's of our products in the cart, in our core session
        $ids = Mage::getSingleton('core/session')->getWishListIds();
        // Here we explode our id's
        $ids = explode('-', $ids);
                        //do a foreach on them
        		foreach ($ids as $productId) {

        $product = Mage::getModel('catalog/product')->load($productId);

        try {

            $wishlist->addNewItem($productId);
            Mage::dispatchEvent('wishlist_addcart_product', array('wishlist'=>$wishlist, 'product'=>$product));

            //unset wishlist id's in session
	    Mage::getSingleton('core/session')->unsWishListIds();

            if ($referer = $session->getBeforeWishlistUrl()) {
                $session->setBeforeWishlistUrl(null);
            }
            else {
                $referer = $this->_getRefererUrl();
            }
            $message = $this->__('%1$s was successfully added to your wishlist. Click <a href="%2$s">here</a> to continue shopping', $product->getName(), $referer);
            $session->addSuccess($message);
        	}
        	catch (Mage_Core_Exception $e) {
            $session->addError($this->__('There was an error while adding item to wishlist: %s', $e->getMessage()));
        	}
        	catch (Exception $e) {
            //$session->addError($this->__('There was an error while adding item to wishlist.'));
        	}
        $this->_redirect('*');
    	}

 	}
}

Now that have the controller wrapped up, we need to modify one file called sidebar.phtml
The file is located here here:

WEBROOT/app/design/frontend/YOURPACKAGE/YOURTHEME/checkout/sidebar/sidebar.phtml

In this file we’ll make the following change around line 56

<?php //first we'll make our id's null ?>
<?php $ids = null; ?>
    <?php foreach($_items as $_item): ?>
        <?php echo $this->getItemHtml($_item) ?>
         <?php now we'll concatenate our Id's into a string
        <?php $ids .= '-' . $_item['product_id']; ?>
    <?php endforeach; ?>
    <?php
        //finally, we'll store the id's into our core session
    	Mage::getSingleton('core/session')->setWishListIds($ids);

         //setup some debug logging to see what we're doing :)
    	//$session = Mage::getSingleton('core/session');
    	//Mage::Helper('debug')->log($session);
     ?>

And we’ll add the Add All to Wishlist button/link here:

<!-- add all items to wishlist -->
        <button style="margin-right:5px;" class="form-button" type="button" onclick="setLocation('<?php echo Mage::getBaseUrl(); ?>wishlist/index/addcart/product/')">
            <span><?php echo $this->__('Add to my Wishlist') ?></span>
        </button>

And now for the Grand Finale!
We’ll activate our module by creating a file in

WEBROOT/app/etc/modules/Mycompany_Addcwl.xml
Inside this file we’ll put the following

<?xml version="1.0"?>
<config>
 <modules>
 <!-- Activate Add All in Cart to Wishlist Module -->
   <Mycompany_Addcwl>
     <active>true</active>
     <codePool>local</codePool>
   </Mycompany_Addcwl>
 </modules>
</config>

Congratulations, have a beer! You can now add all the products in your cart to your wishlist :)

If you know how to Debug, you’ll know how to code

Posted on April 5th, 2010 by admin  No Comments »

A very good friend of mine, a JAVA coder, once told me.

“When I started coding, all I focused on, was learning how to DEBUG properly – I wanted to KNOW what was happening there.”

This is probably the best advice I can offer someone new to Development. Learn how to debug your code from day one, so that you’ll have a clear idea of what your code is doing.

Now, working with Magento you’ll need to know how to debug your code.
Of course you can use the old faithful

print_r($variable);
var_dump($variable);

However, Magento objects are often times very large, and the output will be painful to understand and read.

However, there is a better way.

Install FireFox, and add the extensions

Then install the excellent Magento Debug Module by netresearch
Log into the Magento Admin Backend, and navigate to System->Configuration->Developers Options

Enable the Debug module.
Now in your Magento Code, when you want to debug a variable, add the following

Mage::Helper('debug')->log($variable);

Open the FireBUG console and reload the page, and you’ll see a collapsible output of your object

Thunderbird + MS Exchange + Google Calendar
+ SMS/Email notifications !

Posted on November 4th, 2009 by Riaan Nolan  No Comments »

Mozilla Thunderbird with Microsoft Exchange Mail, Calendars, Address Book and Meeting Requests
+
Gmail and Google Calendar integration with Google SMS and Email Notifications.

Operating Systems:

This how-to will work on both Windows and Linux, for this tutorial we use Windows XP and Ubuntu 9.10 (Karmic Koala)

Benefits:

The software we have chosen are Licensed under the GPL (General Public License) it’s absolutely, 100% FREE of charge. It runs on all Operating Systems.
You can now use Thunderbird to search your Microsoft Exchange Address Book, Accept meeting requests, AND in addition, you’ll be able to sync your Calendar
to your Gmail Calendar and receive FREE SMS and Email Meeting Alerts.

Serving Suggestion:

Create a New Calendar, give your team members read/write access to that Calendar. Enable their Mobile Devices to receive SMSs. Now everyone in that team have a Share Calendar, which will notify every one in your team of new events. Viola!

ETA:

30 Minutes

Read the rest of this entry »