Saturday, January 15, 2022

Logitech K400R Wireless Keyboard

I have two Logitech K400R wireless keyboards. Let's call them Fred and Barney. They're great. Each has a tiny USB thingy - dongle makes me think there's some kind of wire. It's just a tiny little thing that plugs into USB. Turns out it's a Unifying Receiver. I'll come back to that.

In my case, I'm only able to put my hands on Keyboard Fred and Receiver Barney. The other keyboard and the other receiver are probably on vacation somewhere. So I've got this mismatched set. Plugged in the receiver and turned on the keyboard and... nothing.

Well I googled and discovered there's software for the Unifying Receiver. Don't know how that could possibly solve my problem, but I download and install it.

(You'll find it here: https://www.logitech.com/en-us/manuals/11916)

To make a longish story shorter, when you plug in the Unifying Receiver (oh and it might even be from yet another Logitech device) and turn on the K400R, it will detect that keyboard and set up a connection. My mismatched Fred Keyboard and Barney Receiver are working great!

Thanks, Logitech!!

Sunday, October 17, 2021

Comparing channel listings of Philo, Sling, Hulu Live TV, YouTube TV, Fubo TV, DirecTV

Update (29 July 2022) this appears to be out of date - NESN, for example, is not on YouTube TV, but might be on DirecTV - not sure. I'll update this soon.

All the wordy nonsense is at the bottom of the post.

Service
(Level)
$$/month
PhiloSling
TV
HuluYou
Tube
FuboDirecTV
Live TVTVStartrEliteEntChUltPrem
255065656580708595140
Local Channels*******
A&E*******
ABC News Live***
ACC Network******
AccuWeather*******
ActionMAX*
AMC*********
American Heroes****
Animal Planet*********
Aspire***
AWE***
AXS TV******
Baby First HD****
BBC America*********
BBC World News*****
BET*********
BET Her****
BET Jams*
BET Soul*
Big Ten Network*******
Black News****
Bloomberg TV******
Boomerang******
Bravo*********
Cartoon Network*******
CBSN***
CBS Sports******
Cheddar Big News*
Cheddar Business**
Cheddar News********
Cinemax East*
CleoTV****
CMT********
CNBC********
CNBC World*****
CNN*******
CNN En Español****
CNNi*****
Comedy Central*********
Comedy TV***
Comet***
Cooking Channel*****
Cozi TV****
Crackle*
Crime + Investigation*
C-SPAN****
C-SPAN2****
Curiosity Stream*
The CW****
Destination America****
Discovery**********
Discovery Family****
Discovery Life****
Disney Channel*********
Disney Junior********
Disney XD********
DIY Network****
DUST*
E!*********
ESPN*********
ESPN2*********
ESPN3*
ESPNEWS******
ESPNU******
ESPN Bases Loaded*
ESPN College Extra*
ESPN Goal Line*
ESTRELLA**
FM**
Food Network**********
Fox Business Network********
Fox News Channel*********
FOX Sports 1*********
FOX Sports 2******
Freeform*********
Fuse*****
FX*********
FX Movie Channel*****
FXX********
fyi***
GAC Family**
Galavision******
Game Show Network*****
getTV***
GINX eSports*
Golf Channel******
Great American Country**
Gusto***
Hallmark Channel*******
Hallmark Drama***
Hallmark Movies & Mysteries*****
HBO East*
HBO 2 East*
HBO Family East*
HBO Latino*
HGTV**********
HISTORY Channel*******
HLN*******
HSN****
IFC*********
INSP**
Investigation Discovery**********
Justice Central***
Law & Crime**
Lifetime*******
LMN***
Local Now****
Logo HD****
MLB Game of the Week*
MLB Network*****
Motor Trend**********
MSNBC*********
MTV********
MTV Classic****
MTV Live**
MTV2******
MTVU*
NASA TV*
Nat Geo WILD*****
National Geographic*********
NBA TV*****
NBCLX**
NBC News NOW**
NBC Sports*********
NBC Universo*****
NECN***
NESN***
Newsy*
Newsmax HD******
NewsNation*****
NFL Network***
NHL Network***
Nick Jr.*******
Nickelodeon East********
NickMusic*
Nicktoons*****
Olympic Channel******
One America News****
Ovation***
OWN******
Oxygen******
Pac-12 Network*
Paramount TV********
PBS Kids****
People TV**
pocket.watch*
POP********
QVC****
QVC 2****
Reelz****
Revolt*****
Revry*
RFD-TV****
Ryan and Friends*
Science*****
SEC Network******
Shop LC****
SHOWTIME® East*
SHOWTIME 2® East*
SHOWTIME EXTREME®*
Smithsonian Channel****
SNY*
Sony Movie Channel*
Sounders FC*
Stadium**
Start TV*
Sportsman Channel**
STARZ*
STARZ ENCORE...**
STARZ Kids & Family*
SundanceTV********
Syfy*********
Tastemade*******
TBS*******
TCM******
TeenNick******
Telemundo****++++
Tennis Channel HD*****
TLC**********
TNT*******
Travel Channel*********
truTV*******
TUDN****
TV Land********
TV One****
TVG*****
TYT*
UniMás******
Universal Kids******
Univision East******
UPtv****
USA Network*********
VH1********
VICE*******
WE tv********
Weather Channel*****
HBO Max+++*
Cinemax+++*
Showtime+++*
Starz++++*
Epix+*++++
And More!OriginalsYouTubeSports++Sports++

I "cut the cord" recently and went looking for a way to get the standard set of "cable" stations as streaming. See, already this is too many words. I swear most of those sites are paid by the word. Anyway, here's my thinking: I was going to pay for Hulu anyway (the $6 one without live TV) because of their original content. So when I compared that with YouTube's Live TV, I ended up saving money. The nice thing about Fubo is they have NESN, so you can watch the Red Sox. And The Weather Channel actually has some original programming, believe it or not. I honestly don't understand why DirecTV is so expensive, but they can probably afford to test the market and adjust later. It's also nice to see some offerings at the low end, and I did initially sign up for Sling when I got off the phone with Comcast and realized I now had NO way to entertain the family. But like I said, I signed up for Hulu. Maybe I'll switch to Fubo next baseball season? Oh, and don't do like I did and call Comcast all pissed off and tell them goodbye without remembering to WRITE DOWN EVERYTHING IN YOUR DVR. Yup, had do reconstruct my whole list from memory. Also I'm using ReelGood to keep track of all my streaming shows, which is something a cord-cutter has to do, that's just life. And I'll say one other thing: I have added back HBOMax to watch Curb (coming soon) and I've signed up for Showtime to watch The Circus and American Rust. It's unlikely everything will ever add up to what I had been paying Comcast. But if it does, that's fine with me, as long as I'm only paying Comcast for Internet. And if another provider comes along (fingers crossed for fiber!!) I'll give the Internet money to them instead. Don't get me started on Comcast's monopoly. OK, enjoy the channel comparison, and if you find anything incorrect, drop me a line at "channels" at-sign "jadbury" dot com and I'll make the necessary edits.

Wednesday, August 25, 2021

Mac Finder needs password for every delete

 This was driving my crazy. My Mac's Finder was asking for a password for every delete, every rename, every move, everything.

I should have put two and two together and realized it was only happening in a folder I had restored from a backup volume.

Here's how I fixed it.

  1. In Finder, go to the top folder giving you trouble, then go up one to its parent.
  2. Right-click the trouble folder and select Get Info
  3. Go to the Sharing & Permissions section
  4. Tap the lock and enter your password.
  5. Under Name you should see your username, and under Privilege it should say Read & Write. Click your username.
  6. Below the list of names and privileges is a plus sign and a minus sign and a circle with dots inside next to a menu pull-down. Click the circle/pull-down.
  7. Select Apply to enclosed items... from the menu.
  8. Click OK to update the whole folder hierarchy with your Read & Write privileges.
You should now be able to work on the files in your formerly trouble folder!

Wednesday, June 30, 2021

docker logs the one I just started

Nobody ever told me about this, so I'm telling you, you're welcome! $ docker logs -f $(docker ps -ql)

Sunday, June 13, 2021

Deploying Swift/Vapor Apps to Cloudhost

My Swift/Vapor deploying adventure with lots of words, because I stand in solidarity with the Recipe People. But no pictures, because I never think of that.

I thought it would be pretty straightforward. I’ve got Linux hosting at Cloudhost (not its real name) so I can just log in and install Swift and Vapor and build my app and run it, right?

Ha ha, good one.

But my hosting is modest - 1 GB of memory is plenty for my typical needs, which is usually limited to hosting an HTML site - Apache on Ubuntu 16.04.

So try and build a Vapor site? Nope, try and try and fail and fail - fatalError kind of stuff. Try adding -v to the build and re-run just that last command directly in Swift and all of a sudden I see the real problem: I’m running out of memory.

Well hell, of course I am!

So all I need to do is build my app off-site and copy the Run file, right? *Hey, don’t get ahead of me, this is my adventure.

Oh, I almost forgot this part. I’ve got a Linux system, and in fact I’ve already built my app there. Just copy the Run file, right? No, because this is Ubuntu 20.04 and so it depends on libraries and such that are four years newer than what’s running at Cloudhost.

But I’ve got this other PC and it’s got a bunch of memory. It might even ben running Linux already, who knows. Scrounge a keyboard and mouse and monitor. Plug it in. Beep beep beep. Won’t even POST.

No problem, pull the drive and drop it into yet another PC. Boot it up and wouldn’t you know, it’s actually running Ubuntu 16.04. In fact, there are ancient Swift directories from November 2016 when I thought I’d have time to play with the compiler. I didn’t. So get a network hooked up, get Swift installed, and…

$ swift -version

blah blah (I didn’t bother saving all the output)

Illegal Instruction

Oh yeah, if you are thinking about running Swift on Linux on an older PC, do this first:

$ cat /proc/cpuinfo | grep ssse3

because if it comes up blank, you’re going to have a bad time.

So no problem, that Ubuntu 20.04 PC is willing to sacrifice itself temporarily (and I know already it’s got ssse3) so unplug its drive and drop in the Ubuntu 16.04 drive.

Now here’s something I’m not 100% sure I needed to do, but I made sure that I installed Swift in the exact same place on both Ubuntu 16.04 systems - the one on my PC and the one at Cloudhost. In both cases, I have /opt/swift-5.4.1-RELEASE-ubuntu16.04. So if there are libraries that would cause a freakout because of different locations, that’s not going to happen.

And finally I see what I’ve been hoping for:

$ export PATH=/opt/swift-5.4.1-RELEASE-ubuntu16.04/usr/bin:"${PATH}"

$ swift -version

Swift version 5.4.1 (swift-5.4.1-RELEASE)

Target: x86_64-unknown-linux-gnu

So get Vapor installed, pull down my app, and (sudden thunder clap drum roll)

It works!!

*Oh wait… connect from the browser, no it doesn’t!! And this is something I didn’t realize about Vapor, you need to have the Resources/Views directory and all its .leaf (or .html) files. And, it turns out, your Public directory. No problem, so I did a clone of my whole app to get whatever files it needs. As they change, I can pull to refresh them. Then I re-copied the Run file, but this time dropped it in the same x86_64-linux-whatever location as where it came from. This way git doesn’t think I have any untracked files.

Now run it again, and it looks like it works, then hit it from the browser, and it actually does!!

So here are the takeaways:

  • Here are the links for installing swift and vapor
  • You'll have much better luck with your build system separate from your hosting
  • `cat /proc/cpuinfo | grep ssse3` # to make sure your build system is up to running Swift
  • Make sure you have enough memory on your build system (not sure how much that is tbh)
  • Make sure your hosting and build systems have the same exact Ubuntu version (major.minor is probably enough, but…???)
  • Install Swift to the same location on both build and hosting (not 100% sure you need to do this, but I think you do and it can’t hurt, right?)
  • `git clone` your whole app, even though you don’t need the Sources, you do need Resources and Public folders
  • scp .build/x86_64-linux-whatever/debug/Run from your build system to the same spot, so it’s ignored by git

I think that’s it. I hope this helps somebody!

Wednesday, June 02, 2021

Vapor/Leaf #ifdef(sortof)

The Swift/Vapor site I'm working on has one index.leaf to rule them all. (index.html, actually, because I thought I might want to look at my templates in a browser, but tbh I never have - but I digress)

And I find it really handy sometimes to throw in an error message just wherever, like this:

<div class="container">
    #ifdef(error):
    <p class="text-danger">#(error)</p>
    #endif
    #bodyBlock()
</div>

Of course there's no such thing as #ifdef. And I searched and I searched and even thought about implementing #ifdef

And then just when I was about to ask on Discord (and I hate doing that)... I don't even know what made me think of this, but here's what works:

<div class="container">
    #if(error??false):
    <p class="text-danger">#(error)</p>
    #endif
    #bodyBlock()
</div>

And tbh I don't know why it works, because if error doesn't exist, why should ?? even help? But it does. And it does!

So if "error" is in my render context, I'll get a nice red dangerous error message. Sweet!

Sunday, May 16, 2021

(not) Auto Vapor Restart

 I was thinking it might be fun to have auto restart of Vapor, like you can do with NodeJS. But then I thought more about what happens when you need to change multiple files, and you make change after change, and it won't build & run until you've made all of the changes.

Anyway, if you add this to routes.swift:

app.delete("kill-switch") { (req: Request) -> Response in
    exit(0)
}

And you start the server like so:

$ while true ; do vapor run ; sleep 3 ; done

Then you can restart it using curl or Postman or (if you use app.get) your browser:

$ curl -s 'http://localhost:8081/kill-switch' -X DELETE

Wait, what about reloading the page when the server restarts? That should be doable, right?

Friday, May 14, 2021

Vapor 4 and MySQL

tldr; if you get connection reset/connection refused errors, try using unixDomainSocketPath instead of hostname.

I've had a heck of a time connecting Vapor 4 to MySQL. I know, maybe I should be using PostgreSQL, but I've got this old database I'd like to be able to connect to and provide new functionality with Swift code.

So I put this code in configure.swift on Linux:

    app.databases.use(.mysql(
            hostname: "localhost",
            username: "dbuser",
            password: "passW0rd",
            database: "whichdb",
            tlsConfiguration: .forClient(certificateVerification: .none)
    ), as: .mysql)

and that worked great.

But connecting to my Linux system is sometimes a pain in the neck, but it turns out that for some reason I have the same database on my Mac. I connect from the command line and `show tables;` lists every table I have on the Linux database. So copy the project to the Mac and `vapor run migrate` (because I'm going to play with the galaxies sample) and I get this error:

connection reset (error set): Connection refused (errno: 61)

Well to make a long story short, I ran lsof and saw that mysqld was listening on port 3306 but also had the file /tmp/mysql.sock open. Then I knew what to search for, and discovered that there is indeed an option to connect by socket:

    try app.databases.use(.mysql(
            unixDomainSocketPath: "/tmp/mysql.sock",
            username: "dbuser",
            password: "passW0rd",
            database: "whichdb"
    ), as: .mysql)

So basically you replace hostname with unixDomainSocketPath and you don't need the TLS configuration nonsense. Oh, and that init throws, so add try.

Hope this helps somebody!

Saturday, March 06, 2021

Picture This

If you're like me, you've got sticky notes covering every inch of every service of your vast empire.

If you're really like me, those sticky notes are all virtual. Mostly they take the form of "hey Siri, remind me in an hour to do a thing." They end up in my Reminders app and I can route them to whatever todo app they belong to.

The Apple Watch makes that super convenient. Raise your wrist, speak the magic phrase (or hold down the giant button) and remember to include a time, so it will put a badge on the reminder app.

Sometimes, though, there's a glitch. From Apple, can you even believe it? If Steve Jobs were alive, this would be solved by now, but he's not, and that's just how life goes.

Uh oh, something's wrong. Please try again. Oddly enough, if you try again, it will work. But if you've said something brilliant and you're not sure you can re-create it, here's a way to capture it: Apple Watch Screen Capture.

So it turns out that if you press the two buttons on the side of your Apple Watch, it will take a screenshot. I think you have to go to settings to enable that, which you should do before you need it, right? This will show up in your Photo Library as a PNG. And now you've got your brilliant utterance, or whatever gibberish Siri thinks you said.

And if you're like me, you've got a reminder to look at your Photo Library every now and then, because otherwise who knows when you'd ever see it, right?


Update (5/14/21): for what it's worth, I hardly ever see this anymore - the WatchOS 7.4 update must have fixed whatever was causing so many Siri problems. So thanks, Apple!

Monday, February 22, 2021

Play my slides, please!

Did you ever need to take notes while you watch your slides play, but you don't want to switch back and forth between your Keynote and your text editor? Here you go... Save this to your Mac as main.swift - no other name will work, then run it in a terminal like so:

$ swift main.swift


import Cocoa

var pid = pid_t(-1)

let bid = "com.apple.iWork.Keynote"

for x in NSWorkspace.shared.runningApplications {
    if x.bundleIdentifier == bid {
        pid = x.processIdentifier
        break
    }
}

guard let keynote = NSRunningApplication(processIdentifier: pid) else {
    print("Can't find Keynote")
    exit(-1)
}

let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)

let key: UInt16 = 0x79

guard let keydown = CGEvent(keyboardEventSource: src, virtualKey: key, keyDown: true) else {
    fatalError("Can't get keydown")
}

guard let keyup = CGEvent(keyboardEventSource: src, virtualKey: key, keyDown: false) else {
    fatalError("Can't get keydown")
}

while (true) {
    keydown.postToPid(pid)
    usleep(10_000)
    keyup.postToPid(pid)
    usleep(15_000_000)
}

Monday, February 15, 2021

Creating a CloudKit Container

I was working through a CloudKit tutorial and needed to create a container for my app.

I tried clicking the + button to create a CloudKit container from XCode 12 directly, but nothing happened.

So I clicked the CloudKit Dashboard and could see there were no containers.

I tried to create one. I entered iCloud.com.domain.app (reverse URL format) and gave it a name. Then I got an error message in red, "Unable to find a developer."

OK, well I'm logged in as the Account Holder, not as a Developer per sé, but this should work. Kept trying. Nothing.

So I tried something a little crazy: I went to the Certificates, Identifiers & Profiles section of App Store Connect. I created an identifier for the container I was trying to create.

After I did that, I went back to XCode and clicked the plus (+) again. Lo and behold, the container I had specified in the identifier I had created, all of a sudden showed up.

Will this work? Time will tell. But if you're getting the same error trying to create a CloudKit container, maybe this will help.

If so, you can buy me a beer!

😀 🍺

Saturday, July 25, 2020

The Power of VS

I'll never forget the day my friend who worked at Microsoft sent me a present - it was the full set of discs for Visual Studio. I don't even remember all of the things I could install. Visual C++ was the main thing, of course. 

But no, not today - not that VS. I'm talking about the "vs" that's short for "versus" - which is Latin for "against"

Did you ever want to look something up, but you don't even know what you're looking for? But you know about something else that's like it.

Take Visual Studio, for example. What's out there in the world that's like Visual Studio but isn't Visual Studio?

Try this: go to the browser and type, "visual studio vs" - don't hit enter, just let the Google think about it.


Unless, I suppose, you've got predictions turned off, you'll see all these things that somebody thinks are like Visual Studio. My personal favorite is up there twice: that's right, PyCharm and IntelliJ, both by JetBrains. They are pretty much the greatest thing since... 

Yes, by all means do ask the Google about "sliced bread vs"

Monday, July 20, 2020

Soup: Split Pea With Chicken

There comes a time, usually in the summer, when the freezer becomes overrun with chicken bodies. That time was today.

And nothing in the fridge for lunch. But I've got a package of split peas in the cupboard. Who cares if it's 90 degrees outside? Let's make soup!

Three chicken bodies and 6-9 cups of water, depending on how thick you want your soup. Simmer for an hour. Cool for a few minutes, then pick some chicken off the bones. [update: I tried 6 cups, I think 7 might be better]

Chopped/sauteed about a half onion from the fridge's veggie drawer in a couple TBS of buttery.

Add back the broth and chicken, plus the split peas. Bring back to a boil, simmer for an hour or so. [update: I tried to get away with simmering for just 30 minutes, but I think at least 40-45 might be needed]

Salt and pepper to taste.

Tuesday, May 26, 2020

Switching Java Versions

Believe it or not, I was unfamiliar with this way of switching Java versions:

$ export JAVA_HOME="$(/usr/libexec/java_home --version 1.8.0_251)"

Hope this helps somebody!

(because I know that someday that somebody will be me!!)

Sunday, May 17, 2020

30-Day Song Challenge

I keep seeing the "30-Day Song Challenge" on Instagram Stories. I'm terrible at Instagram, so I probably won't be posting my own selections. But when I googled what all the 30 days were, I kept seeing post after post on these nothing-but-ads sites. Well here they are, and I'll upload the graphic, too - tap it to get it full sized.

1. A song you like with a color in the title
2. A song you like with a number in the title
3. A song that reminds you of summertime
4. A song that reminds you of someone you'd rather forget
5. A song that needs to be played loud
6. A song that makes you want to dance
7. A song to drive to
8. A song about drugs or alcohol
9. A song that makes you happy
10. A song that makes you sad
11. A song you never get tired of
12. A song from your preteen years
13. A song you like from the 70s
14. A song you'd love to be played at your wedding
15. A song you like that's a cover by another artist
16. A song that's a classic favorite
17. A song you'd sing a duet with on karaoke
18. A song from the year you were born
19. A song that makes you think about life
20. A song that has many meanings to you
21. A song you like with a person's name in the title
22. A song that moves you forward
23. A song you think everybody should listen to
24. A song by a band you wish were still together
25. A song you like by an artist no longer living
26. A song that makes you want to fall in love
27. A song that breaks your heart
28. A song from an artist whose voice to love
29. A song you remember from your childhood
30. A song that reminds you of yourself

Saturday, May 16, 2020

iOS Edit Menu

I use the three finger double tap accessibility gesture to put my iPhone in zoom mode, handy for reading fine print and drawing tiny pictures. You then use three fingers to pan the zoomed view around the screen.

But recently I discovered that if you're not zoomed in, there are three finger gestures that do other things.

  • swipe left: undo
  • swipe right: redo
  • tap shows an Edit menu of undo/redo, cut/copy/paste

The best thing about this is that note I can turn off Shake to Undo, which I'm constantly having to cancel while grocery shopping. Problem solved!

Plus, iOS text editing isn't great about offering the Paste function when you drag the cursor to a new location. When that happens, just three-finger-tap and then choose Paste from the menu. Another problem solved!

Tuesday, April 21, 2020

Stacked Enchiladas

   Ingredients:
     * 1 package, corn or flour tortillas
     * 1 pint, sour cream
     * 2 cups, chopped turkey or chicken, cooked
     * 1 or 2 cans, enchilada sauce
     * 1/2 cup, chopped green onions
     * one or two little cans, chopped green chiles
     * 1/2 to 2/3 pounds, shredded cheddar or Monterey Jack cheese

   mix sour cream, green onions, chiles, meat and 3 teaspoons of enchilada
   sauce. in a round casserole dish, spread enchilada sauce to cover the
   bottom. place a tortilla that has been dipped in enchilada sauce in the
   bottom of the casserole dish then layer with approximately 1/4 cup of
   meat mixture and 1/4 cup of shredded cheese. repeat layers ending with
   tortilla and cheese. bake covered in 350 degree oven for 45 minutes.
   remove the cover for the last 15 minutes of baking.

   Muy delicioso!!

   (Makes 8 servings.  Calories per serving: about 550, 300 from fat)

     Copyright 1999, Dave Diamond. Last  updated on February 26, 2000.

Another recipe rescued from an old hard drive. Enjoy!

Thursday, March 26, 2020

Apple Watch Workout Sync

I have an Apple Watch problem. I'm obsessed. I can't not close my rings. Every challenge, accepted.

So the March Challenge is 31 workouts - no problem. I double up a couple days just to be sure.

Then it's the 26th and I look at my progress - wait, 13? It's not counting all my workouts!!

But when I look at the Workouts tab on the iPhone Activity app, sure enough, they're all there.

Googled around, nothing jumped out at me, so I started a chat with Apple.

To make a long story short, they had me unpair and re-pair my watch and my phone, which was kind of time consuming but not a big deal.

And the problem was fixed! March Challenge completed!!

Now if this happens to you - even if you just have to unpair/re-pair your watch and phone for any reason - here are some things to keep in mind:

1. by the end of the day, my watch battery was super low. if you're going to unpair/re-pair, you might want to put it on the charger while you do so.

2. I got to the grocery store to discover that my credit cards weren't there anymore. you have to go into the Watch app on iPhone and re-add your cards, which is just a couple of clicks, BUT you do have to know your cards' PIN codes.

Wednesday, August 28, 2019

Homemade Taco Seasoning

I haven't made this yet, but I don't want to lose it

https://gimmedelicious.com/2018/03/16/the-best-homemade-taco-seasoning/


Wednesday, July 31, 2019

EXIF metadata with a Promise

I had occasion to use exiftool recently, but instead of a callback, I'd rather use promises.

This is what I came up with:

const exif = require('exiftool');
const util = require('util');

const exif_metadata = function (data) {
    return new Promise((resolve, reject) => {
        exif.metadata(data, (err, metadata) => {
            if (err) {
                reject(new Error(err));
            } else {
                resolve(metadata);
            }
        });
    });
};


Worked great!

const fs_readFile = util.promisify(fs.readFile);
 

Promise.resolve()
  .then(() => {
    return fs_readFile(path);
  })
  .then(data => {
    return exif_metadata(data);
  })
  .then(metadata => {
    console.log('metadata: %O', metadata);
  })
  .catch(error => {
    res.send(error.toString());
  });