Author - Web Developer - Educator
Found 13 results for tag "ide"
RSS Feed

Update Youtube Video Privacy with API and OAuth

OAuthI posted this on my Facebook and Github, but I thought I'd post it here for a more public audience.

Recently, while working on Japanoblog, I realized that there was a problem: when we created videos, we would post them for our Patreon supporters 3 days early so they could get early access to them. However, I had a few options:
  1. I could post a separate video to Youtube/Vimeo/etc and share the link, but then wait 3 days and upload the real video and take down the temp one (which would mean 2x the work, and misleading stats)
  2. I could make the video "Unlisted" and share the link with our Patreon supporters, then wait 3 days and change the video to "Public" for all, or
  3. Do the 2nd option, but then have the server automatically change the status to "Public" when the video was ready to go public (as per the blog post publishing date

Well, being the pragmatic programmer that I am, I figured out how to make the server do it for me. But it was not an easy task (apparently, nobody had done this before - at least, on a public searchable point). After scouring the internet to dissect the Youtube API, Google OAuth (along with token creation), researching and pulling parts from about 7 different public user projects, and some patient testing, I finally have it...I hope.

This script is based on Dom Sammut's code and the Youtube Sample Code (PHP #1).

(Don't want to copy/paste? Here's the Github repository)

So, without further ado, here is what I have come up with:

First: get your tokens


You need to generate your tokens to get the process started.
<?php
 

 
#Primary code from https://www.domsammut.com/code/php-server-side-youtube-v3-oauth-api-video-upload-guide/
 
#Create Client ID and Client Secret by creating OAuth credentials 
 
# at https://console.developers.google.com/apis/credentials
 
# MAKE SURE YOU UPDATE YOUR REDIRECT URL TO MATCH!!!!!!!!!
 
$CLIENT_ID = "XXXXXXXXXXXXXX.apps.googleusercontent.com";
 
$CLIENT_SECRET = "XXXXXXXXXXX";
 
$application_name="APPLICATION_NAME";
 
 
 
// Call set_include_path() as needed to point to your client library.
 
#set_include_path($_SERVER['DOCUMENT_ROOT'] . '/directory/to/google/api/');
 
#Download the PHP Client Library from Google at https://developers.google.com/api-client-library/php/
 

 
#This has been installed using Composer - update if you download the files directly
 
set_include_path(get_include_path() . PATH_SEPARATOR . '/PATH/TO/vendor/google/apiclient/src/');
 
require_once 'Google/Client.php';
 
require_once 'Google/Service/YouTube.php';
 
session_start();
 
 
 
/*
 
 * You can acquire an OAuth 2.0 client ID and client secret from the
 
 * {{ Google Cloud Console }} <{{ https://cloud.google.com/console }}>
 
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 
 * <https://developers.google.com/youtube/v3/guides/authentication>
 
 * Please ensure that you have enabled the YouTube Data API for your project.
 
 */
 
$OAUTH2_CLIENT_ID = $CLIENT_ID;
 
$OAUTH2_CLIENT_SECRET = $CLIENT_SECRET;
 
#$REDIRECT = 'http://localhost/oauth2callback.php';
 
$REDIRECT = 'http://YOUR_URL.com/oauth2callback.php';
 
$APPNAME = $application_name;
 
 
 
 
 
$client = new Google_Client();
 
$client->setClientId($OAUTH2_CLIENT_ID);
 
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
 
$client->setScopes('https://www.googleapis.com/auth/youtube');
 
$client->setRedirectUri($REDIRECT);
 
$client->setApplicationName($APPNAME);
 
$client->setAccessType('offline');
 
 
 
 
 
// Define an object that will be used to make all API requests.
 
$youtube = new Google_Service_YouTube($client);
 
 
 
if (isset($_GET['code'])) {
 
    if (strval($_SESSION['state']) !== strval($_GET['state'])) {
 
        die('The session state did not match.');
 
    }
 
 
 
    $client->authenticate($_GET['code']);
 
    $_SESSION['token'] = $client->getAccessToken();
 
 
 
}
 
 
 
if (isset($_SESSION['token'])) {
 
    $client->setAccessToken($_SESSION['token']);
 
    echo '<code>' . $_SESSION['token'] . '</code>';
 
}
 
 
 
// Check to ensure that the access token was successfully acquired.
 
if ($client->getAccessToken()) {
 
    try {
 
        // Call the channels.list method to retrieve information about the
 
        // currently authenticated user's channel.
 
        $channelsResponse = $youtube->channels->listChannels('contentDetails', array(
 
            'mine' => 'true',
 
        ));
 
 
 
        $htmlBody = '';
 
        foreach ($channelsResponse['items'] as $channel) {
 
            // Extract the unique playlist ID that identifies the list of videos
 
            // uploaded to the channel, and then call the playlistItems.list method
 
            // to retrieve that list.
 
            $uploadsListId = $channel['contentDetails']['relatedPlaylists']['uploads'];
 
 
 
            $playlistItemsResponse = $youtube->playlistItems->listPlaylistItems('snippet', array(
 
                'playlistId' => $uploadsListId,
 
                'maxResults' => 50
 
            ));
 
 
 
            $htmlBody .= "<h3>Videos in list $uploadsListId</h3><ul>";
 
            foreach ($playlistItemsResponse['items'] as $playlistItem) {
 
                $htmlBody .= sprintf('<li>%s (%s)</li>', $playlistItem['snippet']['title'],
 
                    $playlistItem['snippet']['resourceId']['videoId']);
 
            }
 
            $htmlBody .= '</ul>';
 
        }
 
    } catch (Google_ServiceException $e) {
 
        $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
 
            htmlspecialchars($e->getMessage()));
 
    } catch (Google_Exception $e) {
 
        $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
 
            htmlspecialchars($e->getMessage()));
 
    }
 
 
 
    $_SESSION['token'] = $client->getAccessToken();
 
} else {
 
    $state = mt_rand();
 
    $client->setState($state);
 
    $_SESSION['state'] = $state;
 
 
 
    $authUrl = $client->createAuthUrl();
 
    $htmlBody = <<<END
 
  <h3>Authorization Required</h3>
 
  <p>You need to <a href="$authUrl">authorise access</a> before proceeding.<p>
 
END;
 
}
 
?>
 
 
 
<!doctype html>
 
<html>
 
<head>
 
    <title>My Uploads</title>
 
</head>
 
<body>
 
<?php echo $htmlBody?>
 
</body>
 
</html>


Now that that's all set, save the response to a file (I recommend "the_key.txt"), and modify and run the following:
<?php
 
/**
 
 * This code is to be run automatically to update a Youtube video's privacy status
 
 *
 
 * First, generate your key using "get-token.php" - read the notes below for generation
 
 * Next, update this file with the appropriate information (path to key file, Client ID, 
 
 *    Client Secret (OAuth Required), Application Name, Database Login, Database Query, and
 
 *    location of PHP Client Library - all download information is below)
 
 * 
 
 * @author Kyle Perkins
 
 * @site https://github.com/kode29/google-youtube-api-privacystatus
 
 * 
 
 * NOTICE: Rest of copyright should be in tact for other scripts (Dom Sammut (domsammut.com) and Ibrahim Ulukaya (Google)
 
 * Last Update: 20160108
 
**/
 

 
#Primary code from https://www.domsammut.com/code/php-server-side-youtube-v3-oauth-api-video-upload-guide/
 
# Mixed with sample code from https://developers.google.com/youtube/v3/docs/videos/update (PHP #1)
 

 

 
#Generate the "the_key" with get-token.php and store it into "the_key.txt" or wherever you want to store it BEFORE running this script.
 
# Also, make sure "the_key" has a REFRESH TOKEN!
 
$key_file = "/path/to/the_key.txt";
 

 
#Create Client ID and Client Secret by creating OAuth credentials 
 
# at https://console.developers.google.com/apis/credentials
 
# MAKE SURE YOU UPDATE YOUR REDIRECT URL TO MATCH!!!!!!!!!
 
$CLIENT_ID = "XXXXXXXXXXXXXX.apps.googleusercontent.com";
 
$CLIENT_SECRET = "XXXXXXXXXXX";
 
$application_name="APPLICATION-NAME";
 

 
#CHeck the DB for updated videos
 
$video_list=array();
 
    $dbh = new PDO('mysql:host=localhost;dbname=DATABASE_NAME', "DATABASE_USER", "DATABASE_PW");
 

 
	$sql="select `video` from `TABLE` where `stamp` like '".date("Y-m-d H:i:")."%'";
 
				$query = $dbh -> prepare($sql);
 
				$query->execute();
 
				if ($query->rowCount() > 0){ #rowCount() won't work on some databases
 
					$values = $query->fetch(PDO::FETCH_ASSOC);
 
					while (list($key, $value) = each($values)){
 
						$video_list[]=$value;
 
					}
 
				}
 
$key = file_get_contents($key_file);
 
if (count($video_list)>0){
 
foreach($video_list as $VIDEO_ID){
 
	$VIDEO_ID = str_replace("https://youtube.com/watch?v=", "", $VIDEO_ID);
 
	$VIDEO_ID = str_replace("https://youtu.be/", "", $VIDEO_ID);
 

 
#Sample $VIDEO_ID can be "gYY3fVz6PjY";
 
/**
 
 * This sample adds new tags to a YouTube video by:
 
 *
 
 * 1. Retrieving the video resource by calling the "youtube.videos.list" method
 
 *    and setting the "id" parameter
 
 * 2. Appending new tags to the video resource's snippet.tags[] list
 
 * 3. Updating the video resource by calling the youtube.videos.update method.
 
 *
 
 * @author Ibrahim Ulukaya
 
*/
 

 
// Call set_include_path() as needed to point to your client library.
 
#Download the PHP Client Library from Google at https://developers.google.com/api-client-library/php/
 

 
#This has been installed using Composer - update if you download the files directly
 
set_include_path(get_include_path() . PATH_SEPARATOR . '/PATH/TO/vendor/google/apiclient/src/');
 
    
 
require_once 'Google/Client.php';
 
require_once 'Google/Service/YouTube.php';
 
session_start();
 

 
/*
 
 * You can acquire an OAuth 2.0 client ID and client secret from the
 
 * Google Developers Console <https://console.developers.google.com/>
 
 * For more information about using OAuth 2.0 to access Google APIs, please see:
 
 * <https://developers.google.com/youtube/v3/guides/authentication>
 
 * Please ensure that you have enabled the YouTube Data API for your project.
 
 */
 
$OAUTH2_CLIENT_ID = $CLIENT_ID;
 
$OAUTH2_CLIENT_SECRET = $CLIENT_SECRET;
 

 
$client = new Google_Client();
 
$client->setClientId($OAUTH2_CLIENT_ID);
 
$client->setClientSecret($OAUTH2_CLIENT_SECRET);
 
$client->setScopes('https://www.googleapis.com/auth/youtube');
 

 
#$redirect = filter_var('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'], FILTER_SANITIZE_URL);
 
# If running via Cron, HTTP_HOST may be blank
 
$redirect = filter_var('http://YOUR_URL/' . $_SERVER['PHP_SELF'], FILTER_SANITIZE_URL);
 
$client->setRedirectUri($redirect);
 

 
$scope=array("https://www.googleapis.com/auth/youtube", "https://www.googleapis.com/auth/youtubepartner", "https://www.googleapis.com/auth/youtube.forcessl");
 

 
// Define an object that will be used to make all API requests.
 

 

 
#if (isset($_GET['code'])) {
 
#  if (strval($_SESSION['state']) !== strval($_GET['state'])) {
 
#    die('The session state did not match.');
 
#  }
 
#
 
#  $client->authenticate($_GET['code']);
 
#  $_SESSION['token'] = $client->getAccessToken();
 
#  header('Location: ' . $redirect);
 
#}
 
#
 
#if (isset($_SESSION['token'])) {
 
#  $client->setAccessToken($_SESSION['token']);
 
#}
 
$client_id = $CLIENT_ID;
 
$client_secret = $CLIENT_SECRET;
 
#var_dump($key);
 

 
  $client = new Google_Client();
 
    $client->setApplicationName($application_name);
 
    $client->setClientId($client_id);
 
    $client->setAccessType('offline');
 
    $client->setAccessToken($key);
 
    $client->setScopes($scope);
 
    $client->setClientSecret($client_secret);
 

 
// Check to ensure that the access token was successfully acquired.
 
if ($client->getAccessToken()) {
 
/**
 
         * Check to see if our access token has expired. If so, get a new one and save it to file for future use.
 
         */
 
        if($client->isAccessTokenExpired()) {
 
            $newToken = json_decode($client->getAccessToken());
 
            $client->refreshToken($newToken->refresh_token);
 
		#This is for debugging if your token is not regenerated
 
	    #var_dump($client->getAccessToken());
 
            file_put_contents($key_file, $client->getAccessToken());
 
        }
 

 
$youtube = new Google_Service_YouTube($client);
 

 
  try{
 

 
    // REPLACE this value with the video ID of the video being updated.
 
    $videoId = $VIDEO_ID;
 

 
    // Call the API's videos.list method to retrieve the video resource.
 
    $listResponse = $youtube->videos->listVideos("status", array('id'=>$videoId));
 

 
#	array( 'id' => $VIDEO_ID, 'status' => array('privacyStatus' => 'public')));
 

 
    // If $listResponse is empty, the specified video was not found.
 
    if (empty($listResponse)) {
 
      $htmlBody .= sprintf('<h3>Can't find a video with video id: %s</h3>', $videoId);
 
    } else {
 
      // Since the request specified a video ID, the response only
 
      // contains one video resource.
 
      $video = $listResponse[0];
 
	$videoStatus = $video['status'];
 
	$videoStatus->privacyStatus = 'public'; #privacyStatus options are public, private, and unlisted
 
	$video->setStatus($videoStatus);
 
	$updateResponse = $youtube->videos->update('status', $video);
 

 

 
#    $htmlBody .= "<h3>Video Updated</h3><ul>";
 
#    $htmlBody .= sprintf('<li>Tags "%s" and "%s" added for video %s (%s) </li>',
 
#        array_pop($responseTags), array_pop($responseTags),
 
#        $videoId, $video['snippet']['title']);
 
#    $htmlBody .= '</ul>';
 
$htmlBody = "We're Good!"; #Just a debug phrase to know that the script completed successfully. Not required to output
 

 
  }
 
    } catch (Google_Service_Exception $e) {
 
      $htmlBody .= sprintf('<p>A service error occurred: <code>%s</code></p>',
 
          htmlspecialchars($e->getMessage()));
 
    } catch (Google_Exception $e) {
 
      $htmlBody .= sprintf('<p>An client error occurred: <code>%s</code></p>',
 
          htmlspecialchars($e->getMessage()));
 
    }
 

 
    $_SESSION['token'] = $client->getAccessToken();
 
    } else {
 
      // If the user hasn't authorized the app, initiate the OAuth flow
 
      $state = mt_rand();
 
      $client->setState($state);
 
      $_SESSION['state'] = $state;
 

 
      $authUrl = $client->createAuthUrl();
 
      $htmlBody = <<<END
 
  <h3>Authorization Required</h3>
 
  <p>You need to <a href="$authUrl">authorize access</a> before proceeding.<p>
 
END;
 
    }
 
#      echo "<body>$htmlBody</body>";
 
}}
 
	?>
 

Again, Here's the Github repository)


Tags:#php #mysql #japanoblog #video #youtube #api #oauth

RSS Feed

VIM Search and Replace

VIMI thought I'd post this because I needed it, and quick access doesn't hurt. I had a recent experience where I needed to replace a lot of text in a text file in the command line.

While I like to use vim as my text editor of choice while in a Linux system, I hated the fact that I had to find each instance of a word and manually type out the replaced word.

So, I found a solution: (thank you VIM Wiki)

:%s/
The %s command works just like wq, so you need to proceed it with a colon. But here's how it works:
:%s/FIND/REPLACE/OPTIONS
I hope this seems straight forward, but here's the breakdown: %s - initiate the :substitute feature FIND - the word/phrase you want to find REPLACE - the word/phrase you want to replace it with OPTIONS - there are a series of options you can include, the most popular one being g Here is an example:
:%s/cat/dog/g
This replaces all instances of "cat" with the word "dog". Simple, right?

Options

Here is the list of options I have come up with so far:
c - ask for confirmation (similiar to the -i flag)
i - case insensitive search/replace
I - case sensitive (the flag \C can also be tacked on to the word in case you want the word to be case sensitive only)
:%s/\<cat\>/dog/g - while not in the Options field, this searches for the whole words only (such as "cat", but not "categories")

There are plenty of other examples on the VIM Wiki page, but I thought I'd post this guide here for my benefit and anybody elses that needs it.


Tags:#vim #linux #texteditor #search #replace #guide

RSS Feed

My terrifying Day

For those of you that want to know a little more about how my day turned horrible, here are the full details.

Let's start on Monday, September 15th (Skip the boring stuff):

6PM
I wake up from a long day on Sunday, and felt it was acceptable to sleep in on Monday, since I had nothing to do. On the previous day, Keat received payment (in cash) from our neighbor for dog sitting, and splits it with me, since I did half of the work as well.

Our friend Kat, had also paid me $22. I had forgotten why, but realized it was because I had purchased some domains for her, and she just paid me back.

10PM
I start to clean the house a bit, because it needed to be done.

12AM, Tuesday, September 16th
Keat and I sit down and start watching "Good Morning, Vietnam", which is a Robin Williams film (rated R, 1987). I had never heard of it, but Netflix suggested it, and it was actually pretty good. There is actually a scene in there where the Robin's character seems really down and depressed, and when he is greeted by his fellow soldiers, they all show their support for him, then have to drive away. Robin's expression said it all for his recognition in today's society (and, sadly, he will be missed).

2:30AM
Keat and I are still up, so we decide to start watching "Who Framed Roger Rabbit." All throughout the film, we were curious how Disney got the rights to some famous WB cartoon characters, the fact that Christoper Lloyd (Doc Brown from "Back to the Future") was a bad guy, and how they did all of the cartoon/real life interactions in 1988 - almost a decade before CG and at least a decade before Space Jam.

5AM
Keat hits the hay while I stay up and write. I didn't see a reason to go to bed for roughly 2 hours, since I had to leave to teach at AB Tech at 8:30 in the morning.

7:45AM
I stop my writing for the time being, getting roughly 2600 words written, and cresting 77,000 total words. The fact that I'm almost finished with Book 3 was exciting to me, and I hope to finish it by the end of the week. Regardless, I take a shower and get dressed to leave.

8:40AM
Leave for AB Tech

9:20AM
Walk in, talk to my Advisor, get the key to my room, unlock it, then start talking to her about some Spring courses that I may be teaching. After a few minutes, I head back to my room, only to find that it has been closed and locked. Apparently, one of the other instructors, talking to my Advisor's Boss (the official terms are a bit lost) thought the room was open and unused, so he locked up. After I told him the situation, he apologized and unlocked the door. I walk in and start setting up for my 10am class.

10AM
Class begins. I do the Riddle of the Day, take attendance, and show them the instructions for the lab of the day.

10:15AM
A lot of people are having questions about the lab (Installing Windows 8.1 on a Virtual Machine). I install Win 8.1 on the Instructor Machine, going through the same motions, and spend roughly 15 minutes trying to find a solution. I did find one, let everyone know, then informed my Course Advisor about the situation. Apparently, a key step was left out of the instructions, but it has been rectified.

12PM
I start to shut down the class, get asked a few computer questions by some students, and lock up.

12:30PM
I leave AB Tech campus to head back home and sleep.


(In case you didn't care about the above stuff, the real story begins here)
12:45PM
Location: I-40 West, just short of Exit 27 (the exit to Waynesville). I'm on the left lane. My car starts to slow down a bit. I step on the gas pedal to maintain speed, but notice that my RPM guage is only around 2-3, where usually it is around 5-6, so it did seem a little low. Coasting toward Exit 27, I notice that my "TRAC OFF" light comes on. The only other times that I've seen that is when I am on very loose gravel or ice.

Realizing that my car is starting to act funny, I start to steer right, but find out that my power steering has locked up. Not good. So I try to force it, but to no avail. Therefore, I do the only other thing I can think of: slightly turn left to get off the road. My car continues to slow down. The gas pedal is doing absolutely nothing. I crawl to a stop as far left as I can, but not completely off the road (see image below - the circle is roughly where I was stopped, and how much of my car was still "in the road"). As soon as I stop, all of my dash lights go off. In a slight panic mode, I cut the car off, wait a few seconds, then try to start it again. After a bit of revving, it starts, then immediately quits. I try it a few more times, but the same effect happens.

The point of Terror

So, since I remembered that I had "Roadside Assistance" through my auto policy, and a GPS-enabled device that tracked my travels, I called State Farm. In a slight panic mode (again), I ask "Is this the line for offroad assistance?" (Keep in mind that I am sitting on the left side of I-40W with cars and trucks zooming past me at 75+mph, only mere inches from sideswiping or nicking me) The person understood what I was asking and said that my policy did cover this, but they needed to verify my name, address, and date of birth. I gave them that. Then, I was transferred to "Roadside America", which would be handling the scheduling and all of that.

After a few minutes of "Hold music", I was finally answered. The person on the other end was extremely calm (kudo points), but had absolutely no idea where I-40 was. They also spent roughly 10 minutes "trying to pinpoint my location" using my GPS device, which I have 2 in the car: the device from State Farm, and my phone. After "pinpointing" my location, they asked if I was "in the city of Haywood County". No, it's not a city. The closest "city" I would be near would be Canton or Clyde, depending on which direction you go. I keep saying "I'm on I-40 West, just short of Exit 27". They asked "what is the name of the exit?" I said "Exit 27, it leads to Highway 19/23", which the person didn't understand. So, after going on Hold (again) for about 5 minutes, still watching and fearing for the cars, the person told me that they "found a towing company. They are 6 miles away. Is that acceptable, or do you have a preferred towing location?" I respond, "Do I have a choice?" They respond back, "Okay, here's there number." Then, they told me "the towing company isn't a towing company. I have found another towing company that should tow you to another body shop. Here's there number." (Keep in mind that I do not have a pen and paper handy, because I'm scared for my life for all of the cars and trucks that are zooming past me - also, keep in mind that I AM NOT COMPLETELY OUT OF THE ROAD.) They then told me "The body shop isn't a body shop. Well, it's not a mechanic. Here's the number for a mechanic shop." (Still, freaking out every few minutes as more trucks and cars fly past me within inches of striking me - which some of them honk and flip me the bird.) Okay, I thought, maybe this chaos is almost over.

Suddenly, they said that in order to schedule the Tow Truck, I would have to pay $50, along with an $11 service charge. I respond (frantically), "Okay, just get it done." (Thinking I'm glad that I have cash right now, because my father always told me to "carry cash around, because tow truck drivers don't take checks or cards")
The person (Roadside America) asked, "Is it okay to proceed with the charges?"
Me: "YES!"
RA: "Okay, we will need your credit card information."
Me: "Okay, you should already have that on file. Can't you just charge it?"
RA: "No sir, we do not have that on file. I will need your name, card number, and expiration date to proceed with the charges."
Me: *sigh* "Okay, my name is ____, card number is ___, and expiration date is ____."
RA: "Just to verify, your name is ___, card number is ___, and expiration date is ___. Is that correct?"
Me: "YES!"
RA: "Okay, we will need the billing address to proceed with the charges."
Me: "Okay, okay! My billing address is _____, Waynesville, NC 28786."
RA: "Your billing address is _____, Waynesville, 28786?"
Me: "YES!"
RA: "Okay, the charges have successfully gone through. I will need to put you on hold again to call the towing company to come pick you up."
Me: "Okay, okay, please hurry. I'm still on I-40 about to be sideswiped at any minute!"
RA: "Please hold."

RA: "Okay, sir, I have contacted the towing company, and the highway patrol to inform them of your situation. A police car should be there within 5 minutes to make sure you're not sideswiped, and the tow truck should be there within 45 minutes."
Me: "Finally!"
RA: "Thank you for calling Roadside America. I will call you back on your phone to verify the schedule." (Hangup)

At this time, it is roughly 1:25PM - it has taken me roughly 30 minutes to schedule the tow truck to come.

Shortly after, I see a tow truck going down I-40 East, and turn its lights on, which usually means that they found me and need to turn around. Unfortunatly, the closest exit is 31, which means they will need to travel roughly 3 miles down I-40E, then 3 miles up I-40W to get me. The tow truck pulls in front, sticking out into the highway more than me, and the guy tells me to stay in the car (the only possible way out was through my driver window, because the door couldn't open for me to get out, and getting out on the right side was suicide).

The tow truck towed me up, with the IMAP car showing up shortly after, making sure to keep the traffic away. The tow truck drove across the highway, to the right side, and the guy told me to get out, so I did. I filled out a bit of paperwork for him, then got in his truck, riding backward to Canton. We arrive at Singleton's automotive (which I had been meaning to try anyway) and thanked the tow driver profusely, since he risked his life to rescue me. He told me that "Next time you call roadside assistance, tell them that you're in the middle of the highway and some urgency is needed, because you're in a dangerous location!" I told him I did, and the person did not understand.

At 1:45PM, I sat in Singleton's awaiting for the result and final paperwork. I filled that out, asked if I owed anything right now, and they said No, so I called Keat to come pick me up.

2:10PM
Keat picks me up, I explain everything, and she stops by McD's because we are both hungry. After sitting in the drive-thru for about 10 seconds, the car in front of us honks their horn, meaning that they had been there for a while and not been helped. So we go across the street to Sonic's and pick up some popcorn chicken. We head home, I get undressed, then get a call from Singleton's saying that the problem is my Fuel Pump - apparently, it had lost pressure and needed replacement. Labor and parts would be an estimated $589.40 (or something like that). I sighed, thinking "There goes all of my money" and agreed to it. It was either "Pay $600 now and get my car fixed, so we can have 2 cars, or scrap that one and pay $5000+ for a new(er) car." I would rather keep my old car right now.

Afterwards, we both take a nap before Keat needs to head in to work at 6 (starting at 7:30).

6:15PM-ish
Keat gets up from the bed, gets dressed, and leaves for work. I stay in bed until roughly 3AM when she calls saying that she is off. And that is where we are now.




I can't believe that it took that long and that much just to get a tow truck scheduled, and the fact that partner programs with State Farm don't have access to client files is ridiculous. They should have access to all client files and automatically charge them (upon permission) instead of having to relay all of that information, especially if one is sitting on the left side of the highway and may not exist within the next few minutes.


Tags:#roadsideassistance #car #tow #statefarm

RSS Feed

My First Mobile App

I've been trying to push my limits for the past few days, to make up for the fact that I've been very de-motivated. So, I decided to pick up the progress on WNC Local, which has been going well. I've also been working on the WePay API as well, and that's been...enlighetning? It's been a little challenging, but it's good to get the experience.

So, to take a break from the many hours I've spent slaving over the API, I decided to switch directions for a bit and start tackling the Android and see what I can do with mobile apps. Not having a speck of knowledge in Java, it is a real challenge.

However, thanks to the Android SDK bundle, the Eclipse IDE was included (I've had experience with Eclipse when I was working on C++ back in 2003), and Eclipse+Android Development Toolkit (ADT), getting to "Hello World" was fairly simple.

Using the techniques mentioned on the basic training page, I created the following:
My First App Icon
(Yes, that is Asuna in the background)

My First App

The basic training allowed for the creation of the basic app: input text, output the text.
My First App Output

The documentation was not completely fool-proof, so I had to do some additional research to do a few things (thanks to Toast), like this:
Search Button Pressed

Settings Button Pressed

And the documentation didn't go this far, so I thought I'd add this based on some UI experiences:
String cannot be Blank

I know it's not a very impressive app, but it's not bad for my 1st one done within an hour.

In case you want to fork it or view the source code, I have the app on Github: https://github.com/kode29/MyFirstApp

Here's the APK if you want it

Here's to seeing what Mobile App Development can do!


Tags:#android #app #development #github #wnclocal #wepay #c++ #sdk #eclipse #ide #adt

RSS Feed

Raspberry Pi: The (Unofficial) Missing Startup Guide

Raspberry Pi Logo If you just ordered a Raspberry Pi (like me) and unboxed it only to find a circuit board and no instructions, let me outline a few things for you and make it simple to go from "box" to "running" with little to no hassle:

(also because the "Quick Start" guide was a little more confusing than expected - based on the directions, I thought it required a Windows-based computer to set up a Linux circuit board. I'm glad I was wrong, but it took me a while to find it out)

Step 1: Gathering the Necessary Parts/Cords


Here is a list of items that you will need to set up your Raspberry Pi:

  1. Micro-B USB Power Cord (with at least a 700 mA / 5V output - most cell phone chargers will work)
  2. A USB Powered Keyboard (hopefully with an input power of ~100mA)
  3. An HDMI cable (for HDMI TV's or Monitors) OR an double male RCA-RCA cable (for CRT TV's - if you have a double yellow male Video-Video cable, that will work too, as you will only need the yellow video jack). Don't expect to get a VGA connection out of this, because HDMI-VGA connectors are super expensive
  4. A Network cable (recommended)
  5. A dedicated blank (or can be blanked) 4GB+ SD Card (or Micro SD card with a full SD Reader - that's what mine is)

The SD card is here because that is the "hard drive" of the Raspberry Pi. Which means that the Pi does not come with it's own pre-installed OS, as I found out the hard way.

Alright, all of the parts have been gathered.


Step 2: Get the OS


Next, you'll need a functioning computer with internet, and go to raspberrypi.org/downloads to get an operating system.

Note Note: When I saw "For your free download go to raspberrypi.org/downloads " on the box, I thought it was for some free open source items - they didn't say "Go here for your Operating System"

At the time of this writing, the latest version of the common Raspberry Pi OS is a Debian-based distro called Raspbian (specifically, "2013-02-09-wheezy-raspbian").

Download the ZIP or Torrent of the OS to your hard drive (about 1.8GB in size) and unzip if you downloaded the ZIP.

Now, you will have to process the IMG to the SD card using a specific program.

Linux/Mac: you can use dd from a terminal
Windows: Follow the instructions on raspberrypi.org/wp-content/uploads/2012/12/quick-start-guide-v1.1.pdf to use Win32DiskImager

I'll be discussing Linux instructions from here.

Linux


Put the SD card into your machine (or into the USB Dongle if you don't have a card reader). Once your machine recognizes the card, find the specific location of where the card is located in the mounted file system (Debian: Go to "Applications" > "System Tools" > "Disk Utility").

Once you find the location, format the card (if you haven't done so already) so it is blank (I recommend formatting using a FAT system). Now, unmount the card, but don't pull it out of the machine.

You will need to perform the following command to get the Pi to properly read the card:
 
sudo dd bs=1M if=[location of your img file].img of=/dev/[card location]
 

Example:
 
sudo dd bs=1M if=2013-02-09-wheezy.raspbian.img of=/dev/sdf
 

NoteNote: You will want to write to the whole card, not just a partition. Double check to see if there are any numbers after your mount location. If there are, you may be writing to a partition and not directly to the card

That process will take a couple of minutes. Once it is done, confirm that it transferred the full amount to the card (1.8GB). If it did not, repeat this process from the "Format" step.

Note Note: This took me about 12 tries before the card was properly written to for the Pi to read it

Once it is properly written to, you can just remove the card, but I recommend "Powering down the device" first.

Step 3: Starting up the Pi


Hopefully, everything up to this point has been successful. If so, please proceed.

  1. Assuming you haven't already, open the Raspberry Pi from the box. I have a Model B
  2. Put the SD card into the slot below
  3. Plug in the Network cord, USB Keyboard, and HDMI/RCA cable into their respective slots (also, make sure that your TV/Monitor is on the right Input setting to receive signal)
  4. Plug in the Micro B cord into the small port opposite the Network port for power

Success! You should now see a Red LED (PWR [Power]) in the corner light up. If it did, you have power!

You should also see a Green LED (ACT [Activity]) start to flash. If it is, your Pi is reading the SD card. If it is not, your SD card may have not been written to correctly (as in my case). If it's blinking, please refer to elinux.org/R-Pi_Troubleshooting for Troubleshooting tips.

Note Note: For the longest time, I could not figure out why the Red LED would come on, but I wouldn't get any display or additional LED's. From some of the forums I was on, they called for pulling out a multimeter and testing the power flow between points. I was expecting this to be an "easy DIY project", not "easy, but you need some electrical engineering experience before you can boot up" kind of deal. Luckily, my problem was the SD card, which I was able to finally rectify.

If your Network cord is plugged in, you should also see 2-3 additional lights: FDX (green [File Data Transfer]), LNK (green [Link Connectivity]), and 100 (100Mbps, orange if 100, nothing if just 10).

Step 4: Setting up


Alright! Hopefully everything went well and your Pi is powered up, fully connected, and reading the SD card properly.

I recommend to at least do the following, just so your Pi has a standard basis for operations, unless you have other plans for it.

  1. On your screen, you should see the Startup logo and sequences (unless you are reading this slower than it took to start up). Regardless, you should see a large blue box with options
  2. Select the 2nd choice: expand_rootfs. This will expand the root file system to the SD card for usability and storage
  3. Set your Locale (if necessary)
  4. Set your Timezone
  5. Turn on SSH
  6. Hit "Finish" and confirm a reboot

Default Login: pi
Default PW: raspberry - I recommend changing this to something you will remember

Last Note


I would highly recommend running "sudo apt-get update; sudo apt-get upgrade" before too long, just to make sure you have the latest system updates.

That's it! Your Raspberry Pi should be fully configured as a base to do whatever you want it to do. Go explore the options!

What can I do now?


There are a gazillion+ things that you can do with a Raspberry Pi. My first project was to create a webcam-based monitoring system from the instructions I received from pingbin.com/2012/12/raspberry-pi-web-cam-server-motion/ (including making it Wifi).

You can make a:
  • personal music server
  • small desktop environment (try startx after you reboot)
  • small network file storage system
  • media center (see openelec.tv)
  • small web server
  • sensor for recording temperature, light, wind, speed, etc
  • lightweight search engine
  • multi-core cluster processor
  • ...and more! Go google something

Enjoy!

PS: This site/guide/reference point does not in anyway endorse Raspberry Pi or the manufacturer. This guide was written as a hope to help others get started without the hassle of spending half a day to figure it out, or (if like me) have little experience tinkering with projects like this.


Tags:#raspberrypi #startup #guide #power #led #blinking #help

RSS Feed

Monday Rollercoaster

Since I seem to droll on with my previous catch-up posts, I promise to keep this one short and sweet:

Today:
  • Came in today, worked with Janet to get her new menu ready
  • Recorded/processed payments/invoices for 3 clients
  • Added rewards to said clients
  • Signed up for Basecamp, explored it a bit
  • responded to emails, including Tom, Kat (+debugging), client (previous system), client (current checkout system), client (invoice followup), Amazon Spoofing
  • Checked my backlogged Reader
  • Ordered mini-squishies
  • Scanned for Health Insurance quotes - couldn't find anything usable under $90/mthCompany insurance survey
  • reconciled accounts (both)
  • split insurance declarations into one document
  • updated SD's G+ page
  • added G+ to Blog and site (for Author Verification program)
  • updated Janet's site with new roll
  • explored IdeaPaint some more
  • worked on the Team Operating Manual a bit

Previous to today:
  • Rewatching the reboot of Doctor Who, got Keat hooked
  • Signed SD up for Pintrest, flickr
  • made some major progress on the SD Portal
  • became Google Engage partner
  • talked with White Fox Studios
  • went to family gathering, had fun
  • started going to N-Scale meetings
  • PiLam volunteer meetings
  • Interviewed two people
  • Southern Atlantian Archery Day (SAAD):, rain, bow broke, stayed a night at Keat's parent's place, got refund for busted bow
  • JapanFest!
  • Sacred Stone Baronial Birthday: fun, shot some, went and stayed the night at friends house b/c it was so humid
  • met with SMDC, we are moving! (videos)
  • SD now insured
  • Got award from Powder Creek Traditional Archery


See? Told you it would be short and sweet.

And here's a short and sweet comic to sum up what Niko has been doing when I'm not in the chair:
Kitty in Chair


Tags:#doctorwho #janet #invoices #basecamp #squishies #insurance #googleplus #ideapaint #pilambdaphi #saad #japanfest #trains

RSS Feed

Real World Portal

RSS Feed

Starting to feel like a President

Garfield

Today is certainly the start of something new. Let's just say that I think I'm finally starting to understand the phrase "Work on the business, not in the business."

Put it this way: a typical day would consist of covering a bit of all areas (as the President does when he wears multiple hats), but mainly development time making adjustments, tweaks, and additions to client sites.

However, today, I worked on the following: Accounting reconciliation, HR development, Internal Affairs planning, Business Credit establishment, Marketing Strategy planning, Client File reconciliation, Budget Planning, Loan Application, Server Status Reporting/Investigation, Partnership Proposal Negotiations, Technical assistance, Sales Team development, chasing a support team for solving a business profile issue, and 5 minutes of coding to update the browscap.ini file.

On top of (finding the correct place to vote and) voting, delivering an application to HCC, delivering a payment for a personal bill, paying my insurance bill, playing with the cats, watching some more Doctor Who (I'm on Season 4), and cooking dinner.

That's a Tuesday for you!

MthruF Fail


Tags:#garfield #mthruf #browscap #president #business #sales #marketing

RSS Feed

A bunch of browser-based comics

Since my comic repository is growing faster than I can post, I thought I'd go ahead and post a bunch of browser-based comics. Enjoy!


XKCD
Foxtrot
CH Tabs
Firefox


That will do it for now.


Tags:#xkcd #foxtrot #cyanide&happiness #firefox #browsers

RSS Feed

Headin' to a Party!

Bug

It feels like forever since I posted last, but I thought I'd get an update in before I head to a friend's party tonight.

I've been working on the NSMT alert system, and it keeps bugging me how something works so perfectly on our end (we've even tried to break the system, and it still worked), but it doesn't work on the remote end. I can't really determine the issue and it's becoming harder and harder to figure out what the issue is if the end-user doesn't let us know if something is causing it or what their environment is for their system. It could be anything from a simple security setting to browser restrictions to Admin settings to anything! We don't really provide Tech Support (and this is one of the main reasons). I've been down that road and it baffles my mind how some technology users can be so oblivious about something so simple (it's like someone calling a car mechanic and saying "My car is going WHIRR - fix it!" when the car is sitting in the driveway - impossible to diagnose from remote and impossible to fix if if the problem can't be determined).

I'm also working on some training videos, and found how how YouTube works with privacy settings. I originally uploaded a video and posted it online, but found out that the video was only available to me and my friends. I tweaked that and found out how to make it public, but private. I was also asked how to increase the volume and told them how to increase it via the YouTube application (I told them "we didn't design it, so we can't change it"). I told them that the volume works fine on our end at 30% with and without headphones, so I can't tell what their problem is.

I've also had to push some other client projects back to get this done. It's really irking me to tell these clients "Please wait while we get this done for another client", but what can you do when the company only has 1 developer?

Anyway, I'm gonna call it a night and head to my friend's party in Asheville.


Tags:#bug #videos #fix #nsmt

RSS Feed

Calling it a night

Dilbert

After 2.5 weeks working on the same thing, I'm calling it a night. I finally have the advanced record modifier done for a client. It uses jQuery to find eligible fields, turns them into a textbox on click, allows for editing of the content, and auto-saves it when the field is clicked out. I spent the past few weeks trying to get the .live function to work with the .bind function, only to have the whole system backfire on me. I finally did a small-scale model from scratch, and made the whole system work in 25 lines (with error trapping and notifications). I was baffled that I could get this 25-line jQuery to work properly and more, but couldn't get it in my original 200+ line script. I finally decided to scrap that and use my small scale model to do that. After some initial tweaking, it finally worked. I then had to add some features covering drop down boxes, and that worked as well. Afterwards, I made a tutorial video for the client showing the New system in action, and just emailed them about that. Here's the code now:
$(document).ready(function(){
 
  $("div.clickbox").live('click', function(){
 
    // find the box's name and value
 
    var boxname=$(this).attr('name');
 
    var boxval=$(this).text();
 
    if ($(this).has('form').length==0){ // dont add form if it exists
 
      $(this).html("
"); $("#box").focus(); } $("#box").blur(function(){ var boxname=$("#box").attr('name'); var boxval=$("#box").val(); $.post("save.php", {name: boxname, box: boxval}, function(data){ //alert(data); //troubleshooting }); $.get('fetch.php', false, function(data){ $("#results").html(data); //get the results as we add more }); // replace the text box with the value $(this).parent().parent().html($("#box").val()); }); //dont submit the form if someone presses Enter $('#boxform').submit(function(){ return false; }); }); $('#results').load('fetch.php'); //initially show the results });
I'm sure there is an easier way to do this, but for the basic jQuery knowledge I have, this works.

On the flip side, I have a lot to do for this client. My todo list is already growing, and it seems that they keep emailing me with new features and ideas. I hope they know that we have other clients waiting to get work done as well.

I came in this morning (early afternoon?) and was determined to finish the jQuery record modifier. I also received word that a tenant had some internet issues, so I made sure to take care of that first since I didn't get to see her Friday (like I promised). After about an hour of debugging and troubleshooting, I guessed that the wireless device was bad, so I went to the office, got a spare one (thank god), and replaced it. She was up and running in a matter of minutes.

I then got an email from the Executive Director of the building asking for some Tech help with installing a program. He was out of the office at the time, so I emailed him saying to tell me when he got back in and I'd take a look at it. I got a text from Keat saying to pick her up from school, and a short moment later, the Executive Director walks in and says he's here. I ask him to wait about 30 minutes, and I'll be right in. I went to go pick up Keat, got back, helped him install a piece of software, and got back in the office. By this time, it was 2:15. I hadn't even touched the system.

I finished up my Reader and went to tidy up some loose ends I had yesterday. IE was giving me a headache because of a new request the Client had asked (switching two sections on the main page). Everything was fine yesterday until I went to email them saying it was done, but I got the idea to check the page in IE first. I did that, and (of course) IE messed everything up. I tried to insert some IE-specific CSS, but IE didn't want that. I finally made the code inline, and still no luck - that's when I went home last night. After re-looking at it, I made one small change (deleting the space between -- and [ for the IE-specific CSS comment), and that worked. Finally, 1 task down. Time to work on the Record modifier.

...and that brings us to the beginning of the post. I'm glad to call that Task complete, but I can guarantee that for every 1 task completed for this client, I'm gonna get 2 more. It seems like my todo list will never end.

I'm trying to teach Keat how to do some basic coding (do cover some of the more basic work while I work on the advanced stuff), but it seems that we either can't find a common time to do it, or every time we CAN do it, something comes up and we can't train. We're looking to hire an additional developer soon (if this work load keeps up) and an HR person down the road. Don't know how salary will be, but I'll look into that once I'm done with this ever-growing todo list.

PS: I also beat R&C: Up Your Arsenal last night. It took forever to get R&C 1 to the point where I could get the 10% discount on weapons, and the boss fight only took me 4 tries, but I will give the overall game a 9/10 on fun.


Tags:#jquery #ie #css #dilbert #todo #video #ratchetandclank

RSS Feed

Bad day? That's okay! I have GENIES!!!

More Genies? Why not?
(edited from the original for audiences - view original)

Today seemed to start off good, but then it went down the hole.....fast. And it seemed like I had to build my own ladder to get out of the hole.

Anyway, onto the details: I woke up at about 10:30ish, because Keat had class at 11:30. After writing last night's entry, I wanted to sleep for as long as I could. However, after falling asleep to Futurama and hearing the "Anthology of Interest II" episode (the one where Leela finds her "true home" in a certain film containing lollipop children, a brain-less scarecrow, a squeaky 1930's android, an ironic lion, and an omnipotent wizard), and I realized, "If the Wicked Witch of the West melted with just a small amount of liquid, then does that mean that she never drank anything or ever took a shower? I mean, I can understand the 'no shower' thing because she's a wicked witch and that would make her ugly, but never showering? That's just down right repulsive!"

Anyway, Keat was dropped off at school, and I went to the office. I knew that the server transfer was taking place, and I really want to thank the support guy I'm working with at my hosting company. He's helping me out through the transistion from RHEL 3AS (cPanel) to CentOS 5 (Plesk). I thought that it would be a lot of work to transfer the files over, but I didn't realize it would take this much work (I'll get into one bugging detail at the end).

As I drove to the office, I received a call from Allan, the Executive Director of the building. I couldn't get to the phone before it went to voicemail, but he said that his computer wasn't connecting to the internet and his computer was "fading out." Wasn't quite sure what that meant, but I was only 5 minutes from the office.

I arrived and jumped straight into work. I opened the office door, placed my laptop bag on my chair, and went right into the server room to check the primary connection. It was working fine. So....what's up with Allan's computer?

I went back to my office and set up my laptop. After going through my daily emails and my DDN (or RSS as most know it, but I call it my "Daily Digital Newspaper"), I jumped back into the server transition. It seemed kind of slow since only 1 domain was being transfered at a time. Apparently, the MySQL databases weren't being moved until I said so. 1 task down.

I had a to-do list from a client from yesterday, so I took care of that while I had the chance. 2 tasks down.

After about 2 hours, I had an issue with the MySQL database transfer and credentials. I asked the support guy, and he fixed most of the issue. However, I found out that they want each site to have its own unique login to the database instead of 1 generic login. I went with 1 generic login for the longest time because it was quick. Security wise - that is a large risk. Now I know that Q&D (quick and dirty) isn't the best way to go.

After a while, I realized: "Hey, when they are transferring the shadowdev.com domain, my email system will be down!" So I sent an informative email to the support guy with my backup email address.

After a LONGER while, I was wondering what was taking so long. I hadn't heard anything from my support guy since 1pm (EST) and was wondering how things were going. I went to go pick up Keat at school, got some quick lunch (needed to get back in case there were more server issues), and got back to the office. Guess what: the internet goes out. I started to get furious! THIS IS JUST WHAT I NEEDED! Here I am trying to oversee a sensitive server transition, and the freakin' internet just went out. What a day.

I went to the main server room thinking the problem was local. Nope, the main server wouldn't connect either. Therefore, the problem was on our ISP's end. I tried to load the community college's website on my phone for a contact number (they're our ISP), only to find out that their main site is down. Great. So if their site is down, then the whole county is down. I called someone I knew over there only to get voicemail. I thought "If their phones are on a VoIP system, and the network is down, then their phones are out." Just great. I called again after 10 minutes just because I could, and got the person I was looking for. She let me know that the main internet supplier in the whole region had a fiber link cut and they didn't know how long it would take to fix. That was 3pm. I'm online now, so I hope they fixed it if the office and home use the same artery for the connection.

Keat asked me a few marketing budget questions while we were waiting, and then (after leaving an informational letter) we left for Keat's oil appointment. We pulled into the station to have her car serviced and went for a stroll downtown. Stopped by the library, then had a chocolate malted and a Cheerwine at the Woolworth's Sandwich bar in downtown. Add a Turkey sandwich, and that's good livin' right 'der.

We came home and I took a little nap. Got up, responded to some emails and checked by DDN, then did some laundry. However (here's the detail) I found out that the main reason why the server transistion is taking so long is because the server support guy is going through each of my database configuration files and changing the information to the site-specific login. All 11GB of files.

Honestly, I would have been happy if the files, databases, and domains were transfered as they are, and I would take care of the relative and absolute file location updates and database privileges. That's how I expected to spend Thanksgiving: updating server files.

However, the server support guy said that since so many sites depended on the main shadowdev.com domain, he was going to wait to transfer that until Friday or Saturday. One problem: most of the sites that have a news feature use a centralized function for parsing content links and link-like information - and that's in the main shadowdev.com files. Without the shadowdev.com files, the sites with news features can't parse the link-related content properly. It's going to be a long break.

But I found two things that cheered me up today. 1: the comic above. I can't believe nobody thought (and published) of it before! It all makes sense! and 2: Keat and I were finishing up our chocolate malt, and she stood up to go to the restroom. She put her phone on the table and said "You hold on to it if the car guys call." The moment she places it on the table, "RING RING RING". That was something you couldn't time if you had to do it again. She answered, her car was ready, and she ran to the restroom. She and I had a fun hypothetical conversation after that. Her: "HELLO! YOUHAVETHEWORSTTIMINGINTHEWORLD!" / Car guy: "Your car is ready." / Her: "THANK YOU!" That made me laugh.


Edit: 2010-11-23 22:14:32 Forgot one thing. This photo made me smile as well. Thought I'd share it around.


Enough for today. Time for a whatever-we-can-cook-up dinner. Then, off to Thanksgiving....yay.


Tags:#thanksgiving #cyanideandhappiness #genie #car #server #parse #oz #futurama #centos #internet #mysql

RSS Feed

Creative Distance

Saw this on The System. Had to share and archive for all time.
The System


Tags:#thesystem #computer #ideas