jQuery Masked Input

No Comments »

Found this plugin for jQuery for masking input boxes to restrict input to a specific format.

http://digitalbush.com/projects/masked-input-plugin/

Definitely pleased with this plugin. Very easy to use, and the format for specifying masks is easy as well.

1
$("#CellPhone").mask("(999) 999-9999");

That’s how easy it is to set up a mask.

I do have one problem with it though. It’s basically a one to one mapping for characters (you can specify optional sections on the end) but it doesn’t allow something more regex based. For instance: at least one but up to three letters, followed by 6 numbers (a135923 and ab473922). I will probably try to extend it if I ever run across this situation though.

Give it a look if you need to restrict input on textboxes.


MP3 Folder Cleaner

No Comments »

This is just a quick Python script that I put together to help sort through my music collection. I have a pretty large one, around 24,000 tracks, and I’m trying to consolidate all of them into a more standardized bitrate of 192kbps.  Since they’re all over the map, I figured I would put them into correct bitrate, over, and under folders, so that the ones that are correct can be tagged with MusicBrainz Picard, and the rest can be down converted or reacquired in order to get that consistency.

Requirements:

  • Python 2.5.2 or greater (older versions may work, but you should have at least this)
  • Mutagen (http://code.google.com/p/mutagen/) – you can install it using easy_install

Usage:

Just run the script in a command prompt, and it will ask you which directories to use.

Updates

  • August 19, 2010 – 11:17 PM
    • Moves files based on their metadata instead of just file name
    • Fixed some character handling (removing invalid filepath characters
    • Handles situations where a track may not have tags

Source:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
import os, sys, shutil
from mutagen.easyid3 import EasyID3
from mutagen.mp3 import MP3

dir = raw_input("Enter the directory to work in: ")
move192 = raw_input("Where should 192kbps files go?: ")
moveOver = raw_input("Where should files over 192kbps go?: ")
moveUnder = raw_input("Where should files under 192kbps go?: ")

if not os.path.isdir(dir):
    print "Start directory must be valid directory"
    sys.exit()
   
if not os.path.isdir(move192):
    print "192kbps path is not a directory"
    sys.exit()
   
if not os.path.isdir(moveOver):
    print "Over 192kbps path is not a directory"
    sys.exit()
   
if not os.path.isdir(moveUnder):
    print "Under 192kbps path is not a directory"
    sys.exit()
   
def cleanPath(value):
    value = value.encode("ascii", "replace")
    deletechars = '\/:*?"<>|'
    for c in deletechars:
        value = value.replace(c,'')
    return value;
   
def deleteError(function, path, excinfo):
    print "ERROR: Could not delete " + path
    again = raw_input("Try again? (Enter 'y' for yes, otherwise press Enter): ")
    if (again == "y"):
        shutil.rmtree(path, False, deleteError)

def processMP3(filepath, file):
    audio = MP3(filepath, ID3=EasyID3)
    name = ""
    if ("artist" in audio and "title" in audio and "album" in audio):
        name = cleanPath(audio["artist"][0] + " - " + audio["title"][0] + " (" + audio["album"][0] + ").mp3")
    else:
        name = file
   
    if audio.info.bitrate == 192000:
        print "Moving " + file + " to " + os.path.join(move192, name)
        shutil.move(filepath, os.path.join(move192, name))
    elif audio.info.bitrate < 192000:
        print "Moving " + file + " to " + os.path.join(moveUnder, name)
        shutil.move(filepath, os.path.join(moveUnder, name))
    elif audio.info.bitrate > 192000:
        print "Moving " + file + " to " + os.path.join(move192, name)
        shutil.move(filepath, os.path.join(move192, name))

def process(directory):
    for f in os.listdir(directory):
        if not os.path.isfile(os.path.join(directory, f)):
            process(os.path.join(directory, f))
        else:
            (name, ext) = os.path.splitext(f)
            if ext == ".mp3":
                processMP3(os.path.join(directory, f), f)
               
    print "Deleting " + directory
    shutil.rmtree(directory, False, deleteError)
           
process(dir)

Oregon Trail: The Movie

No Comments »


Creating a Vertically Oriented Table

No Comments »

For the project that I’m working on at my company, one of the pages required developing a table that was vertically oriented (first cell in each row is a header, each data item takes a column). It also had to be editable in place, which means that using a traditional table would be extremely difficult and hackish.

I settled on using unordered lists and some jQuery to give the appearance of a table, and it seems to have worked out splendidly.

CSS Styles

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
.table-container {
    border: 1px solid #AAAAAA;
}
.vertical-list-container {
    overflow-x:scroll;
    width: 600px;
    border-left: 1px solid #AAAAAA;
}
.vertical-list {
    float: left;
    width: 230px;
    padding-bottom:10px;
}
.vertical-list .label {
    padding-right: 14px;
    text-align:left !important;
    font-weight: bold;
}
.vertical-list li {
    vertical-align: middle;
    text-align: center;
    margin-top: 5px;
    padding: 5px 10px;
    min-height: 15px;
    border-bottom: 1px dotted #E0E0E0;
    border-right: 1px dotted #E0E0E0;
}

jQuery magic to make it more table-y. This code basically extends the inner section (id = “scroller”) to the maximum width of the table columns (based on how many there are). It then stretches the container to fit within the whole parent container that the scroll bar will go all the way across. Finally, it loops through each column, and then uses a custom selector to find any cell heights that are above the minimum amount, and then updates all of the heights for those rows

Edit: I made a change to how the heights are calculated. I realized that a taller height in a later row wouldn’t have it’s original height recognized. I replaced it with a dictionary based approach, where each row index stores the maximum height it encounters before applying the final row heights

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$.extend($.expr[':'], {
    height: function (a, i, m) {
        //Check to make sure it's :height(>##) or :height(<##)
        if (!m[3] || !(/^(<|>)\d+$/).test(m[3])) { return false; }  
        return m[3].substr(0, 1) === ">" ?
                        $(a).height() > m[3].substr(1) : $(a).height() < m[3].substr(1);
    }
});

$().ready(function () {
    var scrollWidth = 230 * ($(".vertical-list-container").find(".vertical-list").length);
    $("#scroller").width(scrollWidth);

    var tableContainerWidth = $(".table-container").width();
    $(".vertical-list-container").width(tableContainerWidth - 232);

    var heights = {};
    $(".vertical-list").each(function (x) {
        $(this).find("li:height(>15)").each(function (index) {
            var z = $(this).index();
            var height = $(this).height();
            if (heights[z] === undefined) {
                heights[z] = height;
            } else {
                if (heights[z] < height) {
                    heights[z] = height;
                }
            }
        });
    });

    $(".vertical-list").each(function (y) {
        for (var key in heights) {
            if (heights.hasOwnProperty(key)) {
                $(this).find("li:eq(" + key + ")").height(heights[key]);
            }
        }
    });
});

Then finally, here’s the structure for the HTML code that displays the data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<div class="table-container">
    <ul class="vertical-list float-left">
        <li>Row Header</li>
        <li>Row Header</li>
    </ul>
    <div class="vertical-list-container">
        <div id="scroller">
            <ul class="vertical-list">
                <li>Item 1, Field 1</li>
                <li>Item 1, Field 2</li>
            </ul>
            <ul class="vertical-list">
                <li>Item 2, Field 1</li>
                <li>Item 2, Field 2</li>
            </ul>
        </div>
    </div>
</div>

Double Rainbow Guy in Real Life

No Comments »


BIG BANG BIG BOOM

No Comments »

This video is absolutely mind boggling. I’m sure you will enjoy this

BIG BANG BIG BOOM – the new wall-painted animation by BLU from blu on Vimeo.


Concealed Weapons

No Comments »

Trying to sell some cleverly concealed weapons


Becoming an Adult

No Comments »

Have a cigar


BP Spills Coffee

No Comments »

Jay shared this, and I thought it was amazing. Check it out