Check for new Dropbox folders on Linux

For a customer, I created a service on a remote server that processes files delivered via Dropbox. Problem is Dropbox on Linux will sync all the folders in its root folder, unless it’s excluded. You can exclude all folders except the one you’re interested in, but as soon as you add a folder to your Dropbox, it will appear on your Linux server.

This script will warn you if a new folder appears. It doesn’t exclude automatically new folders, but this feature could be added if you’re brave enough.

#!/usr/bin/perl
# When using Dropbox on Linux, the complete dropbox folder is 
# sync'ed by default, which can use precious disk space if 
# we only need some folders.
# Because we cant choose which folders will be sync'ed on
# Linux, we can only exclude folders we don't want. So this script
# reports when a new folder is added to the Dropbox top folder.
# A nice feature would be to be able to only allow some folders.
# Note: since we can't exclude files, they are not reported.
# Dont add a large file to the root of Dropbox, you can't exclude it from syncing.

# if this script finds folders not in the allowed list, it sends
# an email and a notification, in case the mail is flagged as spam.

# I choose not to exclude new folders directly in this script,
# in case something breaks. This script is run on a server used by
# a customer as a WebService endpoint, so better be safe.

# To exclude a folder from syncing, use the dropbox-cli script available at
# https://www.dropbox.com/download?dl=packages/dropbox.py
# then do
# ./dropbox.py exclude add "Folder to exclude"
#
# Coriolis Stephan Burlot, Apr 11, 2018

use strict;
use Data::Dumper;
use MIME::Lite;
use WebService::Prowl;

## the path to the Dropbox folder
my $dropbox_folder = '/home/stephan/Dropbox/';

## email settings
my $email_address = 'EMAIL_ADDRESS';

## I use Prowl (prowlapp.com) to send notifications to my phone.
## prowl settings
my $prowl_api_key = 'PROWL_API_KEY';

## Allowed folders
# famous last words:
# customer: "the folder is named TEST_Service, we'll change the
# name when we go in production."
my @allowed_folders = qw/TEST_Service/;

#################################
## sends a email with the message passed as parameter
sub send_email($) {
  my $content = shift @_;
  
  my $msg = MIME::Lite->new(
    From  => $email_address,
    To    => $email_address,
    Subject => 'Dropbox Bot',
    Data  => $content
  );
  $msg->send;
}

#################################
## sends a notification via Prowl
sub send_notification($$) {
  my ($app, $event, $message) = @_;
  if ($event eq "") {
    $event = ' ';
  }
  
  # grab your API key from prowlapp.com
  my $ws = WebService::Prowl->new(apikey => $prowl_api_key);
  $ws->verify || die $ws->error();
  $ws->add(application => "$app",
       event     => "$event",
       description => "$message",
       url     => "");

}

#################################
## MAIN
#################################

# I dont use smartmatch, ie
# if ($file ~~ @allowed_folders)
# so I create a hash for simple matching.
my %allowed = map { $_ => 1 } @allowed_folders;

chdir $dropbox_folder;
if (opendir(my $dh, $dropbox_folder)) {
  my @folders = grep !/^\./, readdir($dh);
  closedir $dh;
  
  # array of bad folders
  my @bad = map { -f $_ || exists $allowed{$_} ? (): $_ } @folders;
  if (scalar(@bad) != 0) {
    print "New folders: " . join(", ", @bad) . "\n";
    send_notification('Linode_Small', 'Dropbox Bot', "There are new folders in Dropbox: you should exclude them.");
    send_email("Hello,\n\nI found these new folders in Dropbox:\n\n" . join("\n", @bad) . "\n\nThey should be excluded.\n");
  }
} else {
  send_notification('Linode_SMALL', 'Dropbox Bot', "I cant open Dropbox folder. Is it still there?");
  send_email("Hello,\n\nI can't opendir $dropbox_folder\n\nIs Dropbox still here?");
  die "Can't opendir $dropbox_folder: $!\n";
}

Enjoy.

Tweet Nest support for 280 chars

If you use Tweet Nest to keep an archive of all your tweets, you need a few changes to have all your long tweets stored.

I’ve made a quick hack to solve this temporarily:

– Change the text column of tn_tweets to varchar(512) (if twitter changes the limit again…)
– in the class.twitter.api.php file, replace (at the top):

public $dbMap = array(
  "id_str"       => "tweetid",
  "created_at"   => "time",
  "text"         => "text",
  "source"       => "source",
  "coordinates"  => "coordinates",
  "geo"          => "geo",
  "place"        => "place",
  "contributors" => "contributors",
  "user.id"      => "userid"
);

with

public $dbMap = array(
	"id_str"       => "tweetid",
	"created_at"   => "time",
	"full_text"    => "text",
	"text"         => "text",
	"source"       => "source",
	"coordinates"  => "coordinates",
	"geo"          => "geo",
	"place"        => "place",
	"contributors" => "contributors",
	"user.id"      => "userid"
);

I added a mapping between full_text to text because twitter returns the 280 chars tweets in the full_text field.

in the loadtweets.php file, line 127, add this line:

$params['tweet_mode'] = 'extended';

(before the

$data = $twitterApi->query('statuses/user_timeline', $params);

line)

so Twitter returns the extended tweets.

That’s all.

I posted this as a comment on the TweetNest repo : https://github.com/graulund/tweetnest/issues/91

NSConference 2010

I was in Reading UK last week to attend the NSConference 2010. I will not write a full report of what happened there, because others will do that better.

The only thing I want to say is:if you want to improve your skills in Cocoa, for Mac, iPhone or iPad, you should go: you’ll have the best speakers, the best organization you can dream of. And you will come back with new contacts, new ideas, new code to try.

You can (should) read Alex Repty report here.

PHP is teh suck

The other day, I had to write a PHP script that reads a csv file of addresses and outputs the longitude and latitude of every address in the file.

Since I haven’t done a lot of PHP recently, I had to look in the documentation for the function that reads a file into an array because I couldn’t remember the name.

Lire la suite…