Skip to main content
booksonic article

Booksonic in the media

I was recently made aware that a computer magazine had written an article about Booksonic in their holiday edition for 2019. How fun!

This lead me to do some Googling and it turns out this wasn’t the first or last time Booksonic had been featured. So I thought it could be fun to compile a list about when and where this has happened. If you have read about Booksonic somewhere not mentioned or maybe you are even planning to write about Booksonic I would love it if you let me know at [email protected] or in the comments below.

Linux Journal, Issue 281, September 2017

Booksonic won the editors choice award, later on in the magazine there was an article titled “Build your own audible” where a Booksonic server was set up using ironicbadgers docker container. This article was published again on the Linux journal website in January 2018.

Unfortunately Linux Journal has since had to shut down, the good news is that when they did they published all old issues for free on archive.org so if you want to read this issue it is available here.

Maximum PC, Holiday Special 2019

This holiday special had a five page article called “Take control of your audiobooks” that is centered around Booksonic. This article was mentioned on the cover.

Linux Format, Issue 259, February 2020

This issue contains an article called “Building an audiobook streaming server” and covers how to set up the Booksonic server. It recommends using the docker container created by Linuxserver.io but also includes full instructions for how to install it manually using tomcat and openjdk. This article was mentioned on the cover.

Share

How to read the manifest of an appx package file using Powershell

Reading the manifest of an installed appx package is easy, however today a colleague of mine was working on a custom install script for appx packages and quickly found out that Microsofts Get-AppxPackageManifest can’t be used on an actual appx file.

Some quick testing later and we now have an extended version of the function that handles already installed packages as well as appx package files.

function Get-POPSAppxPackageManifestExtended{
    
    param($Package, $User)

    if(Test-Path $Package){
        Add-Type -Assembly "System.IO.Compression.FileSystem"
        $zip = [IO.Compression.ZipFile]::OpenRead($Package)
        $file = $zip.Entries | Where-Object { $_.Name -eq "AppxManifest.xml"}
        $stream = $file.Open()

        $reader = New-Object IO.StreamReader($stream)
        $xml = [XML]$reader.ReadToEnd()

        $reader.Close()
        $stream.Close()
        $zip.Dispose()

        $xml

    }else{
        if($User){
            Get-AppxPackageManifest -Package $Package -user $User
        }else{
            Get-AppxPackageManifest -Package $Package
        }
    }

}
Share

How I upgraded the Lenovo 4 10 Plus to Android Pie/9 and passed SafetyNet

Before you do anything listed below Please Please Please understand that if done incorrectly you will break your tablet and make it unusable. It is also important to note that not all devices with this name is the same, I have only tested this on the X704L but it would probably work the same on X704F as well, do not try this on any other tablets without first verifying with the creators that it works on your tablet.

I am writing this guide mainly as a reference for my future self so it will be on a level where you already have to know the basics of these things. If you don’t understand the steps in my guide, please head over to the XDA thread instead and have a look at their instructions for installing the OS.

I have made backups of all the files I mention in this guide as I know this type of thing tends to disappear after a few years. If any of the files / sites I link to has disappeared let me know and I will share these files. I will only share my copy of the files once the official ones are gone as I want the creators/maintainers to get the credit they deserve. By going the official route you also make sure you always get the latest versions.

The following are the steps I followed when I did it earlier this week, please note that newer versions might require different steps.

I started by installing Minimal ADB and Fastboot on my computer, this was to allow me to send commands to the tablet easier.

Next I enabled developer options on the tablet and enabled OEM unlock and USB debugging, I connected the tablet to the computer and ran the following command

adb reboot bootloader

This put the tablet in the bootloader mode where you only see a Lenovo logo. Once I saw the logo I ran another command. Keep in mind that this command will factory reset the device.

fastboot oem unlock-go

As the device is now factory reset I had to enable USB debugging again and after that it was time to start downloading the stuff I was going to install.

First off was TWRP. One thing to keep in mind here is that the TWRP states that it is for X704F and not X704L. The version I used worked fine on the L but make sure to verify that newer versions do this as well before flashing. The version I used was twrp-3.3.1-0-X704F.img.

Next it was time to download the ROM, when I write this there is only one Pie ROM available for the tablet and that is an Unofficial version of Lineage OS 16 maintained by yener90. I used the version that was released 20190609

Since Lineage comes without any Google software I also downloaded the Micro GApps pack from The Open GApps Project. Make sure to check Arm64, Android 9 .0 and Micro before hitting download.

The last thing I needed to download for now was Magisk. I downloaded the latest stable version which at the time I write this is 19.3. When I was at it I also downloaded the Magisk Manager APK as that would be required later.

Once everything was downloaded I put a copy of everything both in the root of the internal storage and at the root of an external SD card. Then I ran the command

adb reboot bootloader

Once again, remember that this will only show you the Lenovo logo, when I saw it I ran the command

fastboot flash recovery twrp-3.3.1-0-X704F.img

Once flashed I used the volume buttons to navigate the menu at the top of the screen, wen it said Recovery Mode I used the power button to select it. This booted TWRP where I selected that I want to write to system.

The first thing I did now was make a backup of everything to an external SD card so I always have a way back if I want to.

Now it was time to clean out the old Android, hit wipe but don´t use the slide, instead hit format data and type yes. Once done, hit the back button and go to advanced wipe. Check Dalvik/ART Cache, System and Cache then swipe to wipe them. Go back to the main menu and reboot into recovery. If it asks if I want to install a TWRP app I always say no.

Once back in TWRP I began by flashing the ROM, then GAPPS and lastly Magisk, then I rebooted into system. Once again say no if it asks for installing a TWRP app.

Now I went through the setup of the tablet and once done I installed the Magisk Manager apk that I downloaded earlier.

Insie Magisk manager I headed to the settings and made sure Magisk Hide was enabled and also enabled that Magisk manager itself should be hidden (this is done by regenerating a package with a random name, cool!)

I headed to Google Play and installed the app “Termux”, in my case it was version 0.72.

Then I went back to magisk manager and installed the module “Busybox for Android NDK version 1.30.1. When it was installed I rebooted the device.

Now I headed over to XDA again and downloaded “MagiskHide Props Config” version 4.0.3. Then I went back to Magisk manager and installed this as a new module and rebooted the device.

When the tablet was back up I opened up Termux and typed su and hit enter, gave it root permissions and then typed props. I followed the menu that was started like this
Edit device fingerprint -> pick a certified fingerprint -> Lenovo -> Lenovo K6 Note (7.0) -> yes for reboot.

When the device was back up I ran the SafetyNet check inside Magisk Manager and saw that everything was green but when I tried to search for Netflix on Google Play it still didn’t show up. To fix this I headed in to the tablets settings, then apps, show system apps. Then clear all data for Google Play Services and Google Play. Now I rebooted the device one final time and then it was done.

The tablet is now running Android Pie and passes SafetyNet. One last thing to keep in mind is that SafetyNet is always updated so this will probably break in the future and then Magisk will probably update to fix it again etc etc. If always passing SafetyNet is really important to you I recommend looking for a new tablet with official updates.

Share

Stickers!

Everyone loves stickers, right?

At least I do, that’s why I had some Booksonic stickers made for myself last week and since I know there are some people out there that love Booksonic as much as I do I bought a few extra.

They are vinyl stickers and the size is roughly 3.5 x 3.5 cm.

If you are interested in getting some stickers let me know below or on [email protected] Since this is something I am doing for fun and not profit I’m setting the price to pay what you want + shipping. Shipping cost is $4.

Share
Booksonic app giveaway

The Booksonic app stopped working for almost ten hours today due to bug

First of all, I want to say that I am very sorry to all of you who have been unable to use the Booksonic app today.

Second I want to get in to a bit of what actually happened as well as give a promise that I will make sure it can never happen again.

Ok, so the reason that you haven’t been able to connect to your server today is due to two things. Today at 08:05 Swedish time booksonic.org went down. This was due to a break in the fibre cable leading to the server center that is hosting it.

The second and more important thing is why this caused you not to be able to connect to your own servers. 

First of all I want to make one thing very clear, Booksonic is a selfhosted server and as such this should not happen if my servers go down, that is very important to me.

None of your data between the server and app is ever routed through booksonic.org and will never be so. That said, there are two times that Booksonic connects to my servers. One is when you send me a log file, the second is when the app checks if it has an internet connection and that’s where the problem was.

The app determines if you have an internet connection or not by checking if it can reach booksonic.org. if it can’t, it is supposed to give you a message about it and then move on. The reason this is checking my servers instead of your own booksonic server is so that it can let you know if the problem is that your booksonic server is down or that your internet is down.

What this means is that when booksonic.org went down today all that should have happened is that you should have seen a message in your app letting you know that you don’t have an internet connection but since you actually did you should have been able to use the app just fine anyway, this however  is not what happened. It turns out there is a bug in the code that checks the internet connection. 

While I haven’t been able to verify this yet as I don’t have access to a computer at the moment my guess is that the reason it messes up is because you actually got a connection response (booksonic.org is behind cloudflare) just not the one it was expecting.

This bug is now my highest priority and I will make sure that a fix for it is found and pushed to GitHub and the Booksonic beta channel (sign up on the Google play page if you are interested) before the end of the week. If for some reason I am unable to get a fix for it working before then I will temporary disable this internet checking feature until I am able to find a fix because the fact that your apps stop working when my servers go offline is simply unacceptable to me.

Update 28/4:

After running some tests I have to admit that my first guess about what was messing up the connection was wrong, it was not the internet check in the app that was buggy, it was the version check on the server.

I have released a new version of the server where this is fixed and since I was releasing a new version of the server any way I also fixed the bug where the covers would not stretch to fit.
The new version of the server is called 1.1 and can be downloaded at booksonic.org

Share

Deleting domains from your pihole history database

For a while I have had an error in my home automation system that caused my hub to do hundreds of request to popeen.com every night. Today I finally sat down and fixed it and once it was fixed I also wanted to purge all the lines from the database so it doesn’t screw up my statistics anymore. Doing so was fairly simple but took me a few minutes to figure out so I decided to write it down here. That way I can come back here whenever I need to do it again and hopefully help someone else out at the same time.

First you SSH into the server running pihole, I am assuming you know how to do that already and if not there are plenty of guides for it if you google it so I won’t cover it here.

The first thing we need to do is shutdown pihole so we are free to modify the database, to shut down pihole run the command

sudo service pihole-FTL stop

Then we need to access the database, we do so by running the command

sudo sqlite3 /etc/pihole/pihole-FTL.db

ok, now it’s time to delete the domain, we do this by running this command, replace popeen.com with the domain you want to purge.

delete from queries where domain = "popeen.com";

when you have purged all the domains you want we exit the database by hitting CTRL + C

and lastly we start pihole up again by running

sudo service pihole-FTL start
Share
powershell

Building Powershell GUIs that won’t freeze when you use them

A few days ago I wrote about how important I think it is that you build a GUI for your scripts if they are to be used by anoyone else.

If you have ever built a GUI using Powershell however, you know there is a problem with it that I didn’t mention, that is, whenever your script is actually doing anything the GUI will freeze and windows will tell you it isn’t responding. This is not good as most users will then try to close it and try again. We don’t want that.

The reason this happens is because you are running your form (GUI) and logic in the same thread, something you should never do, problem is, Powershells support for multithreading is limited at best.

In the last post I also talked about my module EasyGUI and mentioned that there are features I wouldnt go in to in that post, one of those features is an easy way to use threads.

There are two ways to use threads in EasyGUI, I go through both of them below as well as a tip on how I prefer to use them.

Method 1.

Passing in a scriptblock to the thread, here I am creating it on the fly but you could also store the scriptblock in a variable and pass that to the function instead

New-Thread {
    0..60|Foreach-Object{
        $SYNC.myLabel.Text = $_
    }
}

Method 2.

You could also write the code for the thread in a separate script file and then pass that to the New-Thread function like this

New-Thread "D:\Program\Powershell\myThread.ps1"

One thing to be aware of is that the threads will start running emediatly when you create them. Often you might not want that. What I usually do is create the threads inside a scriptblock that I store in a variable, then when I need the tread to run I run that scriptblock. That would look something like this.

$myThread = {
    New-Thread {
        0...60|Foreach-Object{
            $SYNC.myLabel.Text = $_
        }
    }
}

#Now it's time to run the thread, simply type the & sign and then the variable containing the scriptblock
&$myThread

$SYNC ? Where did that come from?

Noticed that did you?

This is a variable that’s automatically created when you initialize the EasyGUI module. It’s a hashtable that’s synced between all threads so you can communicate between them. In the examples you see that I am using $SYNC.myLabel. This is created in the GUI like this.

$SYNC.myLabel = New-Label @{
    Location = "15, 15"
}

or like this

$myLabel = New-Label @{
    Location = "15, 15"
}
$SYNC.myLabel = $myLabel

If you want to see a complete example of a GUI script with threading implemented there is an example availiable in the Easy GUI repository.

Share

Booksonic Bridge Preview

As part of communicating more what happens with the Booksonic project I thought it might be a good idea to show what the Bridge will look like.
Important to know is that most parts of the bridge currently doesn’t have an interface but as they are created I’ll add them to this post.

If you have any suggestions or ideas for improvements to the design let me know in a comment here, at reddit.com/r/booksonic or at [email protected]

Share

Writing Powershell GUIs the easy way

One of the most important tools for any IT professional or service desk technician that works in a Windows environment is without a doubt Powershell. Not only is it extremely powerful but it is also very fun to work with if you ask me.

One of the great features of Powershell that I feel doesn’t get enough love from the Powershell community is the ability to write scripts with graphical user interfaces. Yeah, yeah, I know, you want to be able to do a quick change in the script and then rerun it inside ISE and anyone that doesn’t know how to use a console shouldn’t be in IT anyway, right? Wrong!

It is my firm belief that a clear and easy to use interface is just as important as the logic itself when you write a script that is going to be used by someone else. For most people, that means the interface needs to be graphical. I base this belief on having worked in an IT department at a large company for several years as well as maintained the Booksonic project since the start in late 2015. If you want to change my mind, feel free to try and do so in the comments below.

Now with that out of the way I will stop trying to convince you about writing user interfaces for your scripts, the fact that you are reading this post probably means that you are already doing it or thinking about doing it. Instead I am going to focus on how to do it in a way so the code is easy to read and maintain even once you start writing more complex UIs.

When I first started writing powershell I noticed that most examples of people writing powershell UIs get really messy real fast.

A typical example you may find online looks something like this

Add-Type -AssemblyName System.Windows.Forms
Add-Type -Name Window -Namespace Console -MemberDefinition '
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();     
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);

[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0)       '

$font = New-Object System.Drawing.Font("Times New Roman",24,[System.Drawing.FontStyle]::Bold)

$label = New-Object System.Windows.Forms.Label
$label.Cursor = [System.Windows.Forms.Cursors]::Hand
$label.Text = "Click me to open popeen.com" 
$label.BackColor = "Transparent"
$label.ForeColor = "Blue" 
$label.AutoSize = $true
$label.Location.X = 15
$label.Location.Y = 15
$label.Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }

$form = New-Object system.Windows.Forms.Form
$form.Width = 600
$form.Height = 200
$form.Text = "Example form"
$form.Font = $font
$form.Controls.Add($label)
$form.ShowDialog() 

Now functionally speaking there is nothing wrong with that script and in fact it may not look that bad either but remember, all we have done is created a window and added one label to it. Imagine how cluttered this would become once you started doing some more advanced UIs. A better way to write the above that I have actually never seen anyone use other than me and some of my colleages would be using -Properties like this.

Add-Type -AssemblyName System.Windows.Forms
Add-Type -Name Window -Namespace Console -MemberDefinition '
        [DllImport("Kernel32.dll")]
        public static extern IntPtr GetConsoleWindow();     
        [DllImport("user32.dll")]
        public static extern bool ShowWindow(IntPtr hWnd, Int32 nCmdShow);

[Console.Window]::ShowWindow([Console.Window]::GetConsoleWindow(), 0)

$label = New-Object System.Windows.Forms.Label -Properties @{
    Cursor = [System.Windows.Forms.Cursors]::Hand
    Text = "Click me to open popeen.com" 
    BackColor = "Transparent"
    ForeColor = "Blue"
    AutoSize = $true
    Location = "15, 15"
    Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }
}

$form = New-Object system.Windows.Forms.Form -Properties @{
    Size = "600, 200"
    Text = "Example form"
    Font = New-Object System.Drawing.Font("Times New Roman", 24, [System.Drawing.FontStyle]::Bold)
}
$form.Controls.Add($label)
$form.ShowDialog() 

While this takes up about the same space it looks much better right? This way a quick glance at the code gives you a much better understanding of what it is you are looking at.

If you choose to stop reading here and start writing your UIs in this way I beleive you will have a much easier time maintaining that script then you had before. However, I have taken it a step further in my scripts.

When I write a script I use a specific framework that makes the code even quicker to read and also includes some other nice features that I won’t go in to in this post but might make future posts about. One of the most important parts of this framework is a module I call EasyGUI and that you can download at https://gitlab.com/Popeen/EasyGUI

This module builds on the second example above and simplifies it even more. It also includes some other cool stuff that I also won’t go in to here but again, might make another post about. If we decided to use EasyGUI to write the example above it would look like this

Import-Module EasyGUI

Initialize-EasyGUI
Hide-Console

$form = New-Form @{
    Size = "600, 200"
    Text = "Example form"
    Font = New-Font -Font "Times New Roman" -Size 24 -Style $FONTSTYLE.Bold
}

$label = New-Label @{
    Cursor = $CURSOR.Hand
    Text = "Click me to open popeen.com" 
    BackColor = "Transparent"
    ForeColor = "Blue"
    AutoSize = $true
    Location = "15, 15"
    Add_Click = { Start-Process -FilePath iexplore  -ArgumentList "https://popeen.com" }
}

$form.Controls.Add($label)

Show-Form $form
Stop-Console 

I dont know about you but I find that to be much more readable then the first example we looked at, especially when you are working with a lot more then just a label.

It should be noted that not every forms object is in EasyGUI yet as I add them when I need them but adding them yourself should be very easy even for someone new to Powershell and if not just post a comment below and let me know what object you would like added.

I would love to hear your thoughts on this, is it something you would ever use or do you think I’m just talking rubbish when I say that UIs are this important or that a simple module like this can make it a lot more quick, fun and easy to code and maintain UIs.

Share