Tuesday, September 11, 2012

Script to convert series of WAV files

Assume there are wav files named as "disc_1.wav", "disc_2.wav" so on.
There is also a cover file (a JPEG format file) to be used as cover album embedded into each encoded MP3 file.

If we want to convert them all into MP3:



#!/bin/sh

ARTIST="Hamza Yusuf"
ALB="The Rights and Responsibilities of Marriage"
TY="2002"
GENRE="Vocal"
for i in `ls disc_*.wav | sort -V` ;
do
    TN=`echo $i | awk 'BEGIN { FPAT="[[:digit:]]+"} ; {  print $1 }'`
    lame --ti "./the_rights_and_responsibilities_of_marriage.jpg" --tt "$ALB cd$TN" --ta "$ARTIST" --tl i"$ALB" --ty "$TY" --tn "$TN/13" --tg "$GENRE" $i "$ALB cd${TN}.mp3"

done

Sunday, September 9, 2012

Youtube Video to MP3


  1. Download script youtube-dl from  http://rg3.github.com/youtube-dl/
  2. Make sure we have ffmpeg installed
  3. Write a small script with content as below:

youtube-dl --extract-audio --audio-format mp3 -v -t "$1"

For example, to download and extract the audio and save it as MP3 (assuming the small script above has been saved as utube":

utube http://www.youtube.com/watch?v=RoqRbe3dgwU&feature=g-vrec

Post-processing:

concatenate multiple MP3 files to become one mp3:

mp3wrap <file1> <file2> ... <output>

To downmix the result file to a mono-aural:

lame -m s -a <file> <downmix.mp3>


to copy the ID3 data from the original file to the output file

id3cp <mp3 source> <mp3 dest>





Saturday, June 23, 2012

How to set root password on ReadyNAS

Recently I had forgotten my ReadyNAS password.  Even worse, I couldn't login at all due reckless upgrade I did on the box.  I was able to undo the upgrade by letting the box recopy the Linux from its firmware to the drive (see ReadyNAS forum/documentation on how to make the ReadyNAS box recopy the firmware), but still I forgot what my root password was.

Various steps I had tried as I found on the Internet as well as on the ReadyNAS website, but none of them work. Finally, I had an idea to just access the drive directly thru SATA-to-USB cable and reset the password manually.

Basically what I did was to set the root password stored in the file /etc/passwd (fortunately the authententication is still the old-fashioned one, where the MD5 encrypted password stored directly in the file instead in shadow file).

You might ask, "How the hell I access the drive?".  Well, first you need remove the drive from the ReadyNAS bay (make sure it is turned off!!) then  attach the SATA-to-USB cable to the drive.  Connect the usb end to our PC.

We cannot mount directly to the drive, because some other issues.  To mount, see my previous post ("How to mount disk used by ReadyNAS").  Once it is  mounted (just mount the ext3 partition [first partition], no need to mount the LVM), we can now modify the file /etc/passwd.

First, save the following script (thanks to somebody who posted it on the Internet), say, as /home/<yourloginname>/bin/setpasswd:


#!/usr/bin/perl
################################################################################
# Generate an MD5 hash for a string.
# Created to allow me to set a blank Linux password. Required this to create
# multiple VsFTP accounts with anonymous style credientials.
#
# If all you want is the MD5 Hash for NULL (blank password) here's one...
# $1$VNMbpxGH$sew7cnwH9ixU.x27UbFNn.
#
# Advice: If replacing a Linux password with a blank string, ensure you give 
# the user a shell of /sbin/nologin as you wouldn't want them to login!
################################################################################
# Load dependancies...
# perl -MCPAN -e 'install Crypt::PasswdMD5'
################################################################################

use strict;
use Crypt::PasswdMD5 qw(unix_md5_crypt);
my @salt = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );
my %encrypted;


sub abort {
print "ABORT: $_[0]\n";
exit 1
}


sub gensalt { #------------------------------------------------------------
# uses global @salt to construct salt string of requested length
my $count = shift;

my $salt;
for (1..$count) {
$salt .= (@salt)[rand @salt];
}

return $salt;
} # end gensalt


sub get_encryptedpw { #--------------------------------------------------
my $unencrypted="$_[0]";

# generate traditional (weak!) DES password, and more modern md5
$encrypted{des} = crypt( $unencrypted, gensalt(2) );
$encrypted{md5} = unix_md5_crypt( $unencrypted, gensalt(8) );

return %encrypted;
}

################################################################################
print "Enter password string to encrypt (can be blank) : ";
my $password = <STDIN>;
chomp $password;

get_encryptedpw($password);

print "Plaintext \"$password\" = MD5 Hash: $encrypted{md5}\n";
print "\nReplace the /etc/shadow password string with the above to force pass change\n";


(Don't forget to make it executable by doing "chmod +x ./setpasswd)
Run the script.  It will ask you to enter a password.  An example of the output (with blank password):


$ setpasswd
Enter password string to encrypt (can be blank) : 
Plaintext "" = MD5 Hash: $1$udf2EDLY$a/cLQQ4h25rwZQc9VKmG6/

Replace the /etc/shadow password string with the above to force pass change

Copy the portion after the string "MD5 Hash: " above and paste it in the <READYNAS MOUNTPOINT>/etc/passwd.  To be precise, it should be pasted in line where "root:...". Paste it right after "root:", and let the rest of the existing text still intact.

Save the file, unmount (just use the regular umount for this one), reinsert the drive into the ReadyNAS bay and turn it on.  Once it is running, try to SSH to the box as root and enter the new password.  It should work!


Sunday, March 25, 2012

Undirected Graph

The following small program illustrate how to implement a undirected graph with costs to neighbor nodes.


#ifndef _GRAPH_HPP_
#define _GRAPH_HPP_

#include <iostream>
#include <map>
#include <list>

using namespace std;

/*
 * Undirected graph class
 */
class Graph {
public:
 Graph(unsigned int id=0) { m_id = id; m_Ecount = 0; }
 virtual ~Graph();
 void SetId(unsigned int id) { m_id = id; }
 bool Match(Graph& g);
 bool AddAdjacent(Graph* g, int cost=0);
 bool AddAdjacentOne(Graph *g);
 list GetAdjacents() { return m_Adjacents; }
 
 int GetVCount() { return m_Adjacents.size(); }
 int GetECount() { return m_Ecount; }
 unsigned int GetId() { return m_id; }
 void SetCostTo(Graph *g, int cost);
 int GetCostTo(Graph* g);
 
 private:
 unsigned int m_id;
 int m_Ecount;
 map<Graph*,int> m_cost;
 list<Graph*> m_Adjacents;
};


#endif




graph.pp:

#include "graph.hpp"

using namespace std;

Graph::~Graph()
{
 // TODO:
 m_Adjacents.clear();
}


bool Graph::Match(Graph& g)
{
 cout << "this=" << this << endl;
 cout << "&g =" << &g << endl;
 if ((this == &g) || (g.GetId() == this->GetId()) &&
  (g.GetECount() == this->GetECount()) &&
  (g.GetVCount() == this->GetVCount()) )
  return true;
 return false;
}

bool Graph::AddAdjacentOne(Graph *g)
{
 m_Adjacents.push_back(g);
 //TODO: we need to tell g to add also edge to this object
 m_Ecount++;
 return true;
}


void Graph::SetCostTo(Graph *g, int cost)
{
 if (g == NULL)
  return;
 // Use hash-table to set the cost from this node to g
 m_cost[g] = cost;
}

int Graph::GetCostTo(Graph *g)
{
 if (g == NULL)
  return -1;
 // use hash-table to get the cost from this node to g
 return m_cost[g];
}

bool Graph::AddAdjacent(Graph* g, int cost)
{
 if (!g) return false;

 if (Match(*g))
 {
  cout << "ERROR: Tried to add itself" << endl;
  return false;
 }
 else {
  AddAdjacentOne(g);
  // tell other node to set its adjacent to this node too
  g->AddAdjacentOne(this);
  // add cost from this object to g
  g->SetCostTo(this, cost);
  SetCostTo(g, cost);
  return true;
 }
}



int main()
{
 Graph g[10];
 int i;
 int numOfVertices = 4;

 for(i=0; i<numOfVertices; i++)
  g[i].SetId(i);

 // g0 --- g1
 g[0].AddAdjacent(&g[1]);
 //g1 --- g2
 g[1].AddAdjacent(&g[2]);
 // g2 --- g3
 g[2].AddAdjacent(&g[3]);
 // g3 --- g0
 g[3].AddAdjacent(&g[0]);
 // g0 -- g2
 g[0].AddAdjacent(&g[2], 5);

 list<Graph*>::iterator it;
 list<Graph*> adjacents;

 for(i=0; i<numOfVertices; i++)
 {
  cout << "NODE g[" << i << "]" << endl;
  cout << "\tNumber of Edges in G[" << i << "] = " << g[i].GetECount() << endl;

  adjacents = g[i].GetAdjacents();
  cout << "\tNeighbors:" << endl;
  for ( it=adjacents.begin() ; it != adjacents.end(); it++ )
   cout << "\t\tNode=" << *it << ", g[" << (*it)->GetId() << "], cost="
     << g[i].GetCostTo(*it) << endl;
 }
}

Friday, March 23, 2012

MIVO.TV Network Analysis

While my browser was playing the video streaming (tru flash-plugin) from mivo.tv,  a "netstat -t" revealed high traffic as below:


tcp        0      0 192.168.0.29:56448          68.68.29.24.:macromedia-fcs ESTABLISHED

After googling this "macromedia-fcs" I found:

TCP & UDP Port 1935 (Macromedia-fcs)



Technical description for port 1935:
The RTMP (Real Time Messaging Protocol) service associated with the computer port 1935 is a plain protocol utilized by the Adobe Macromedia Flash application. This proprietary service allows for the streaming of data, video and audio using an active Internet connection among a Flash Server and its associated player. This port supports the three variations of the RTMP service.

The communication port 1935 along with the TCP protocol is used for the delivery of encapsulated RTMPT that traverses firewall applications using HTTPS (secured) connections. The design of this protocol was intended to provide a persistent service for the Flash technology along with other programs like Adobe LiveCycle Data Services ES.

The raw TCP RTMP protocol uses one persistent connection for allowing the implementation of real time communication and smooth delivery of multimedia contents.

The protocol running on the port 1935 achieves this quality of transmission without affecting its ability to send bigger chunks of information including the fragmentation of data.


Digging deeper to the HTML code, I found a port in Javascript like this:


<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
     <codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" 
               width="610" height="878" id="MivoTV" align="top">'
         <param name="wmode" value="transparent">
         <param name="allowScriptAccess" value="always" />
         <param name="allowFullScreen" value="true" />
         <param name="SeamlessTabbing" value="false"/>
         <param name="movie" value="http://mivotv-static.com/swf/MivoTV.swf?r=99123"/>
         <param name="quality" value="high" />
         <param name="scale" value="noscale" />
         <param name="menu" value="true" />
         <param name="devicefont" value="false" />
         <param name="bgcolor" value="#ffffff" />
         <param name="name" value="MivoTV" />
         <embed src="http://mivotv-static.com/swf/MivoTV.swf?r=99999" quality="high" scale="noscale" bgcolor="#ffffff" width="610" height="878" name="MivoTV" align="top" allowScriptAccess="always" allowFullScreen="true" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" wmode="transparent" menu="true" devicefont="false" />
         
<font style="white-space: pre-wrap;"><font face="inherit">But why it doesn't work if I open the URL directly and put some random number at the end [0..99999]?</font></font></p>
<p>


<font style="white-space: pre-wrap;"><font face="inherit"><br></font></font></p>
</object></pre>



'
         

         

         

         

         

         

         

         

         

         

         

         
         
But why it doesn't work if I open the URL directly and put some random number at the end [0..99999]?


Hash template in C++

 

#include <map>
#include <iostream>
#include <cstring>

using namespace std;

struct eqstr {
    bool operator() (const char *s1, const char *s2) const {
   return (::strcmp(s1, s2) < 0 ? true : false);
 }
};


int main()
{
 // template 
    map <const char *, int, eqstr> months;

    months["january"] = 31;
    months["february"] = 28;
    months["march"] = 31;
    months["april"] = 30;
    months["may"] = 31;
    months["june"] = 30;
    months["july"] = 31;
    months["august"] = 31;
    months["september"] = 30;
    months["october"] = 31;
    months["november"] = 30;
    months["december"] = 31;

    cout << "february -> " << months["february"] << endl;
    cout << "september -> " << months["september"] << endl;
    cout << "april     -> " << months["april"] << endl;
    cout << "july      -> " << months["july"] << endl;
    cout << "november  -> " << months["november"] << endl;

 for(map::iterator it=months.begin();
     it != months.end(); it++)
 {
  cout << (*it).first << " => " << (*it).second << endl;
 }
}