Author - Web Developer - Educator
Found 5 results for tag "blog"
RSS Feed

2017 is a Rollercoaster!

Many authors/blog writers/facebook fanboys would make a statement after not posting for so long saying “Sorry for not posting, but I’ve been super busy.” However, I’m not going to do that.

This is a professional blog, and neglecting a post for almost 6 months is ridiculous! I’m not going to apologize, because I am at fault for not dedicating the time to post to a blog, especially one as important as this.

Even though I may not be a super-famous author like J. K. Rowling or George R. R. Martin, I do believe that something as important as this should not just be left aside (especially since I was never one to believe the fact of “leaving a site alone”).

Regardless, I won’t apologize. Instead, I’ll gloat.

I’ll gloat about how much I’ve been able to get done over the past 6 months:
  • My job with Heart renewed back in April, and I am continuing to teach English 40+ hours a week to Japanese children
  • My job with AB Tech continued throughout the rest of the semester, and also continued into the fall (the summer was not kind)
  • Japanoblog has many, many new videos (including Ueno Zoo, Tokyo Hanami trips, rescheduling videos, recipe videos, a few new comics, a few food challenges, informational articles, and more, including a new site design which took me a good portion of the summer to complete)
  • ALT Helper has almost taken a backseat, but has picked up (which is also surprising, as the Facebook page has over 100 likes, even though nothing important is on it!). While progress did teeter off in the summer, to make way for Japanoblog’s design, it has continued with database building, design implementation, and browser testing
  • Meow City Café has started (at least, the initial planning has started)
  • Life in Japan has become a bit more complicated. With a bunch of new bills, including Citizen Tax, National Health Insurance, Pension, and more, both Keat and I are paying nearly $1,000 a month just in bills!
  • Speaking of life in japan, Keat’s going through a rough patch right now, so we may or may not continue to have dual incomes in the near future.
  • Transportation has become a bit harder, since nobody told me that I could apply to have my foreign (US) license converted to a Japanese license, and that the process doesn’t take 2 months of classes. Hence, my International Driver’s Permit expired in August, so the company took back the car, and Keat and I are car-less, which isn’t too bad in Japan, but it is certainly a pain when my furthest school is a 60+ minute walk (in total), and the nearest grocery store is almost 30 minutes away…
  • On a related note, I’ve taken the responsibility to replan, rewrite, and reorganize the Training Manual for Heart, because there is quite a lot that their training did not provide for that we had to learn on the job


I don’t care about that! Where’s the next story?


Well, I have some good news and some bad news: the good news is that Omega Noir is coming! The bad news is that it I had to transcribe the story – all 325 pages! Since Japan is a bit paranoid about having non-BoE issued technology in the Teacher’s Room, I carried a notebook with me and wrote story when I had downtime.

Which does mean that it will take some time to digitize the hand-written material into a workable format, and then the editing begins.

My hopes are that this story works better than the first-first draft, and keeps the reader guessing at every page, but only time will tell.

What’s in the future?


Honestly, I don’t know. My expectation is that I will still be writing, and hopefully Omega Noir #1 will be out before the end of the year, my job with Heart continues to at least the end of the contract, and things with the bills and transportation smooth out.

What will happen next year? I don’t know – we could move to Chiba, Tokyo, or move back home to America. Only time will tell…


Tags:#rowling, #martin, #japanoblog, #meowcity

RSS Feed

How many drafts does it take?

As I browse through my online profiles, I realize that I haven't updated my blog. IN 5 MONTHS! Geez, my online life really has fallen behind. I'm not proud of that.

My many drafts
My many drafts for Omega Noir
So, what has been keeping me busy? I'm glad you asked:

Working on 3rd draft of Omega Noir 1 manuscript


During NanoWrimo 2015, I wrote the majority of "Omega Noir: Ascension", which was the first of my magical fantasy series. During 2016, I finished the manuscript and began editing it, and really liked where it was going. However, while writing "Omega Noir: Chaos Cast" (#2), and editing what I had of that, I realized two things:
  1. Vol 1(1) had lots of plot holes
  2. Vol 2(1) had a sucky villian


So I started a 2nd draft of Omega Noir (#1), and got about 70 pages in, but I realized I was doing the same thing: making sucky villians and building up plot holes. Additionally, the story didn't flow the same way, and lost even MY interest.

Hence, I began Draft #3. This one has a better hook, explains as it goes, and keeps on moving. I'm already 56 pages in, and so much has already happened, with a lot more to go!

Teaching Japanese Elementary and Middle School


My job in Japan has me teaching at 4 different schools: 2 elementary schools (1-6 grade) and 2 middle schools (7-9 grade). My job: Teaching (or assisting in teaching) the English Language.

Luckily, the programs have already been planned out, so all I have to do is show up, maybe bring an activity, and be active. It's not the hardest job in the world, but it is technically the first 8-5 job I've had.

Teaching AB Tech


While teaching English during the day, I'm also teaching HTML by night (well, late evening). I still have my job with AB Tech, and I'm so happy that AB Tech was willing to let me keep my job while across the world. I've had to do a lot of video recording (and editing) as my course is completely online, so I can't just show up and talk for two hours like I did before.

Managing Japanoblog


Japanoblog has become a big part of our lives. While in Japan, we have traveled around the area, including Tokyo and Kyoto, documenting different adventures, sights, foods, and more. Although we still have to work on the weekdays, it's nice to get out and share our adventures with our fans.

Managing the cats


Getting the cats to Japan (after the paperwork) was easy. However, shortly after we arrived, the cats got fleas. We're still not quite sure how, because they never had fleas in America, and we didn't bring them. But somehow, they got fleas, and we've been fighting them ever since. The two of them fight like siblings and we keep them fed and watered, and they like the treats that Japan has to offer.

During some nights, Maru will come into the bedroom and sleep on our heads (or lick our faces) while Chi traps us under the blankets. Other nights (or days), neither of them will enter the bedroom, and when we drag them in, they immediately dash out. No idea why.

Figuring out Japan lifestyle


Comapring Japan to America is like night and day (which, since we're 14 hours ahead, can be a literal definition). There are many things in Japan that are different from America, such as traveling, paying bills, bank accounts, phones, and more. We'll do an article/video on Japanoblog and talk about that in detail.

So until the next post, I'm still busy.


Tags:#tokyo #kyoto #japanoblog #cats #abtech #english #omeganoir

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

Our New Project: Japanoblog

Keat and I have been dwelling on this over the past few months (aka: years), and one thing has been certain: we want to go to Japan.

We waited until after the holidays wrapped up to really start this, but one step that we have taken to assure that we are really going to Japan is to start a travel blog; in this case, Japanoblog!


Keat is currently applying for jobs over there, and hopefully will leave within the next few months. Me? Well, I'm kind of anchored down until May 10th, because I have 3 classes to teach until then. I can't just abandon them now.


Basically, Japanoblog is going to have multiple sections that we want to cover.

Japan-o-food

Japan-o-food is going to cover different Japanese recipes that people can make in their home. We'll also go around to different restaurants and food stalls and review their food.

Japan-o-trains

As a train fan, I want to host a segment about Japanese trains; the different types, prices, routes, and maybe a bit of history.

Japan-o-tours

After going to Japan in 2008, I got to explore a few different places, and wanted to offer the same opportunity to the public (filming approved, of course)

Japan-o-tips

Japanese tips to help everyone live each day a little better, whether in Japan or America.

Japan-o-days

Lastly, since this is a thing on Youtube, we're going to film some of our day-to-day activities and let people see what we do.

Japan-o-comics

Keat is going to draw some comics about our adventures and post them online for everyone to view.

Lastly, Everything Else - this list includes videos that don't fall into one of the above categories.

Overall, the whole reason why we are doing this is because we want others to enjoy our Japanese experience, especially if they want to keep up with us (aka: our parents). We both think that it will be fairly fun to do this project, and make a bit of money on the side through Youtube and Patreon.

So take a moment to explore Japanoblog and let me know what you think.


Tags:#japanoblog #japan #living #moving #keat

RSS Feed

Bachelor for a Week - Day 4

The System

It's been a while since I posted a System comic on here, but I thought this would be nice.

Day 4 of Bachelor-ship, and the days are starting to run together. I've completed more work on the Shadow Dev Beta site, and if I keep this up, I should be able to release it by September 1st. That'll be one major accomplishment out of my way.

Not much has really happened today. I kept watching Voyager - I'm on S7:E2 now, so almost done with the series. Still glad I got to see the whole thing from the start.

I also found out the issue behind why my txt's wouldn't sync with Gmail: my IMAP was turned off. After I turned it on, all of my txt's synced within a matter of minutes.

If I keep up this "blogging" thing, I'll have been blogging for a year in just short of 3 months. To be honest, I'm glad I'm doing this. If not for a personal record (or for you readers out there), then for personal enjoyment to entertain whoever is reading this.

Keat comes home in T-48 hours. Honestly, I can't wait. With the kitties meowing their heads off, no internet access at home, and trying to get work done during these ever-longing days, I may lose my mind before Saturday gets here. Good thing I have a small client meeting and a janitor coming tomorrow to keep my schedule in tact.

PS: According to the server log, I've been logged on since 1:05pm. To date, I've worked 35 hours so far this week. Only 5 more, and I'll qualify for overtime! (that is, if I got paid for it)


Tags:#thesystem # #keat #voyager #txt #blog #kitties