Thursday, October 24, 2013

Bookmarklet Reporting with dotProject

I’ve been using dotProject for keeping track of my hours on certain projects. It’s a bit of overkill for my needs, but it was easy to get started without worrying about trying to find the perfect tool. Over time I’ve found that going my own route has given me some perspective of what I want.

dotProject's interface is rather ancient by web standards, and it’s feature-set is a bit daunting. Some features seem overly complicated and others seem rather sparse. However, the simple html design lends itself to being very flexible to get what I need out of the system.

One particular report that is my bread and butter is the “Task Log”. All my projects have tasks, and I log hours to those tasks. At the end of the month I just want a list of all the logged hours for the month in a nice list.

However, the big issue I have is the default begin/end dates are useless to me. They load on a 2 week cycle, so the default end-date will be the current date, with the begin date set to 2 weeks ago. Changing them should be simple, but the date textboxes are read-only, and the only way to change them is with a popup widget that is cumbersome to deal with.

One day I had some inspiration and thought, if the dates are being sent as query parameters, why not just formulate those parameters myself? After a little bit of experimentation I ended up building 2 JavaScript bookmarklets: One runs the report for the current month, and the other opens a dialog asking for the month before running the report.

A bookmarklet is just a bookmark, but instead of a URL to a webpage, it contains JavaScript that instructs the browser to do something. In this case I'm instructing it to open the URL of the report using the dates that I want.


I’m going to show the main logic I used, followed by compacted versions. I'm not a huge fan of compacted code, but I was afraid that there might be a size limit for bookmark's URL. At the end I’ll show some examples in screenshots.


Full disclosure: this is my test code, some or all of it may not work correctly, you may need to make some tweaks.


Main code logic
Don’t forget to use your URL instead of the fake one used in this example 

//This is the URL before you add the date parameters
var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";

//first day of current month
var begin_date = new Date();
begin_date.setDate(1);    

//last day of current month
var end_date = new Date(begin_date.getFullYear(), begin_date.getMonth() + 1, 0);

//open the URL, with the formatted dates
open( buildURL( formatDate(begin_date), formatDate(end_date)));

//format YYYYMMDD
function formatDate(dtDate) 
{
    var sDate = "";
    sDate += dtDate.getFullYear();
    sDate += pad2(dtDate.getMonth()+1);
    sDate += pad2(dtDate.getDate());    
    return sDate;
}

//pad 0 (zero) to single-digit date parts (i.e. 3/9/2013 = 03/09/2013)
function pad2(n) 
{
 var str = String(n);
 if(str.length < 2) { 
  str = "0" + str; 
 }
 return str;
}

//return the full URL (BASE_URL + THE date parameters)
function buildURL(sBegin, sEnd) {
    var str = "";
    str = BASE_URL+"&log_start_date="+sBegin+"&log_end_date="+sEnd;
    return str;
}



Task Log: Current Month (compacted)
Don’t forget to use your URL instead of the fake one used in this example
//open report for the current month:
javascript:(function(){
 var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";
 function fd(d) {var s="";s=d.getFullYear();s+=pd(d.getMonth()+1);s+=pd(d.getDate());return s;}
 function pd(a){a=String(a);a.length<2 a="" amp="" br="" return=""> var m1 = new Date();m1.setDate(1);
 var m2 = new Date(m1.getFullYear(),m1.getMonth()+1,0);
 location.href=BASE_URL+"&log_start_date="+fd(m1)+"&log_end_date="+fd(m2);
 })(); 

Task Log: Ask for Month
Don’t forget to use your URL instead of the fake one used in this example
//ask for month (number), then open the report:
javascript:(function(){
 var BASE_URL = "http://dotproject.example.com/index.php?m=projects&a=reports&project_id=0&report_type=tasklogs&log_userfilter=0&do_report=submit";
 function fd(d) {var s="";s=d.getFullYear();s+=pd(d.getMonth()+1);s+=pd(d.getDate());return s;}
 function pd(a){a=String(a);a.length<2 a="" amp="" br="" return=""> var m1 = new Date();m1.setDate(1);
 var m = prompt("Enter Month: ", m1.getMonth()+1);
 m1.setMonth(m-1);
 var m2 = new Date(m1.getFullYear(),m1.getMonth()+1,0);
 location.href=BASE_URL+"&log_start_date="+fd(m1)+"&log_end_date="+fd(m2); 
 })();


Adding bookmarklets in pictures

Default report parameters, those dates won't help me
Start with a new bookmark, and paste the JavaScript into the Location field
Here's the result, the dates load correctly!
Creating a separate bookmark to ask for the month
Here is the bookmarklet asking for the month
The report showing the correct dates!


Wednesday, October 16, 2013

Download Adobe Connect Presentations

Download your own copy of an Adobe Connect 8 Presentation




The following are some methods I used to download offline copies of presentations given at a class I took at the University of Washington.  Adobe Connect 8 was the web meeting software used, and it should be noted that Adobe provides documentation on how to provide offline copies, but for various reasons our instructors weren't able to figure it out.

If you search the Adobe Connect user forums, you’ll notice it’s filled with people posting questions on how to export their presentation. I found some good information in the forums and other places, and this post simply lists the methods I used to achieve the goal.


The Easy Way Out: Throw money at the problem
Without a doubt, the easiest solution is to use a screen recording utility.  You may already have a favorite tool, but I payed for one called Screencast-O-Matic.  For what it’s worth, it did a great job for the price.  In hindsight, I would have just recorded the presentations as they became available.
http://www.screencast-o-matic.com



The Do It Yourself Method
Disclaimers:
  • You must be comfortable with the basics of editing and and video (I do you no favors)
  • Fail Early! If it’s not working out, don’t blame yourself and go the easy route

Software: FLV Editor Lite

I found a good free Flash editor called FLV Editor.  It’s free lite version will work fine if you stay under 4 input files, and honestly if you need more you shouldn’t use this method.  If you find the software useful, I’d encourage you to support the developer and buy the software.

The publisher also has a player called FLV Player, which is a pretty robust player despite its ugly interface.  It plays FLV files better than the VLC Player.

Download the presentation

You will have to download the presentation directly from the web software using these steps:  
1. View the Adobe Connect video on your browser like you normally would
2. Remove the extra parameters from the URL, and add this on the end: /output/filename.zip?download=zip
3. Reload page, wait for a download dialog to display and save the file


What is in that Zip file anyway?

The zip file you receive consists of several Flash (FLV) files that make up different parts of the presentation (audio/video/chat/etc); together they form the entire presentation.  The way I understand it, there is one file that controls all the others, called mainstream.

In the best case scenario, the presenter gives the presentation without stopping the recording. However, if they paused any part of the presentation at any time, a new file is created.  This is where the mainstream file steps in, it keeps track of which files should be “played” when, like a music conductor in an orchestra.  This file will not help us, but it’s important to understand how it works.

Extract Audio/Video

I only wanted the audio and the screen share.  Unfortunately the audio and screen shares are stored in separate files.  In the best case scenario:
  • The audio is stored in a file similar to: cameraVoip_****.flv
  • The screen share video is stored in a file similar to: screenshare_****.flv


Video can also be stored on the voip file (usually a web cam of the instructor), so we will need to separate the audio from the video in that file.  Then we will merge the audio to the video from the screenshare file.


Here are the steps to follow this best-case scenario:
  1. Open the FLV Editor
  2. Add the cameraVoip file  
    1. Drag the file into the editor section
    2. Choose the option to un-link the audio & video
    3. Delete just the video part, leaving the audio behind (this can be tricky)
  3. Add the screenshare file
    1. Drag the file into the editor section
    2. It should only have a video part, no sound
  4. Make sure the audio and video line up,and export to Flash
    1. There is an option to export to other formats with the pay version


If you have more than one of either the audio or video

The instructions are similar to the best-case scenario, except you have to get a little creative.  If you can watch the original presentation on the website, you may be able to figure out where the presenter paused.  You can then try to match up all the files in the editor appropriately.



Are there other options?
I originally tried an awesome command-line utility called ffmpeg:  
  • It can work with flv files, but isn’t so good with converting them, so stick to flv
  • If you have more than one of either the audio or video files, prepare for a difficult time
  • Sometimes the audio/video would be out of sync, usually because one of the files was ~5 seconds longer than the other.  
  • There are plenty of examples on the web on how to use this tool.
  • http://www.ffmpeg.org

My method was to extract the audio, then combine it with the video using a script.
Here are the 2 commands that were the heart of my script:

ffmpeg -i cameraVoip*.flv -vn -acodec mp3 output_audio.mp3
ffmpeg -i output_audio.mp3 -i screenshare*.flv -acodec copy -vcodec copy output_video.flv


If you can follow what’s going on in those 2 commands, you can try ffmpeg.  I found it a fun exercise to remind myself that I still have some command-line skills, and that was good enough to move on to something else that would get the task finished faster.


Conclusion
This are the methods I used to download copies of the presentations: I tried to piece the presentation together by myself, but if I ran into any issues I immedately went to the screen recorder.

Your presentation can vary wildly, so you might have to do some investigation with the various files in the zip archive to determine the best course of action.  Hopefully I have at least given you some inspiration.