Tuesday, January 20, 2015

TomatoUSB minidlna problem when rebooting the router

There is a problem with TomatoUSB (or other routers running minidlna Media DLNA Server) which causes the files.db overwritten each time the rooter is rebooted.

This looks like a problem with mounting usb disk, which happens after the minidlna daemon is run.

I have managed to get my minidlna running quite "stable".

1. Remove dlna startup from services and make it run after the usb drivers are mounted.
The may appare a problem with USB disk with multiple partitions.

You can run "minidlna -f /etc/minidlna.conf" on disk mount, but what if your minidlna database is located on the disk that is not mounted as the first one?

Here's the script that examines your minidlna.conf script and checks if media_dir and db_dir are available after each patitions is mounted.

minidlna_required_dirs=`awk -F "/" '/^db_dir|^media_dir/ {out="/"$2; for(i=3;i<=NF;i++){out=out"/"$i};print out}' $minidlna_conf`

for dir in $minidlna_required_dirs
    if [ -d $dir ]; then

if [ "$minidlna_ready" = true ]; then
  minidlna -f $minidlna_conf

The script will run minidlna if media_dir(s) and db_dir exist. (are mounted).

Put this script in "USB and NAS -> USB Support -> Run after mounting form field.

In the window "Run after remounting" simply put "service dlna stop" or "killall minidlna".

2. Once you generate your config file, by temporarily enabling minidlna in USB and NAS -> Media Server make sure it is saved on the the disk of your router. It will be lost after reboot - remember you won't run minidlna with other services which means the config file won't be generated.

In order to save your config there are 2 ways:
a) saving the config on your /jffs/ partition. For me this was not possible, as my WNR3500Lv1 router cound not mount this partition (too low space.. didn't check this actually).
b) saving the config file in nvram by running command from ssh command line:

nvram setfile2nvram /etc/minidlna.conf

Remember to resave this file if you change it.

Also remember, that there is no much space in nvram.

Tuesday, August 5, 2014

Removing libwdi drivers

Just a quick tech note.

I needed to root my android phone and change of usb drivers was needed.
Like many of other folks, I've used the libwdi package with a "Zadig" tool for manipulating the drivers. Yeah.. I've accidentaly change the driver for my Logitech Mouse and from that moment it didn't work anymore.

The zadig author points that restoring the original windows signed driver is easy as uninstalling the device using the "Device Manager" with "Remove driver files.." option checked.
It didn't work for me as I manipulated the drivers using Zadig couple times and in my opinion the option mentioned above restores drivers to the previous one.. libusb-wind32 - libusbK - libusb-win32 and so on in my case.

So, if  you are trying to remove libwdi installed USB drivers (libusbK, libusb-win32, winusb) with zadig, and it returns error you can try the pnputil.exe tool. It's included with windows.

It's easy to achieve what you want with:

1. List all 3rd party inf packages by:
# pnputil.exe -e > somefile.txt

2. Then look for "libwdi" string in somefile.txt

Published name :            oem134.inf
Driver package provider :   libusbx.org
Class :                     Urządzenia uniwersalnej magistrali szeregowej
Driver date and version :   06/02/2012 6.1.7600.16385
Signer name :               USB\VID_046D&PID_C019 (libwdi autogenerated)

Now all you need is the command below for reach entry found:

# pnptuil.exe -d oem134.inf

PS. Make sure the devices using the drivers above are not connected and that you running commands with admin priveleges assigned. (command prompt in admin mode).

Friday, May 16, 2014

Disney Cars 2 game problem windows 8

Maybe this solution will work for you ?

My son loves the Disney Cars 1 & 2 games. Well.. he loves Disney Cars movies as well :) This game is not supported on windows 8 (especially running on Intel HD4000 graphic card) but it works.. It hangs randomly but we can play. Suddenly I noticed that it no longer runs.
The process starts and crashes after 10 seconds. Using a grat AppCrashView app I found that the process loads a Bitdefener antivirus module which I have installed 2 days before we tried to play Cars again.

Here's the line:

LoadedModule[4]=C:\Program Files\Bitdefender\Antivirus Free Edition\avc3\avc3_sig_241\avcuf32.dll

After uninstalling the antivirus the game works fine. Yeah!

Though I love Bitdefender I have to admit that I can't use it with Cars game. Back to Avast.
Sorry. Maybe this is not your fault Bitdefender. Maybe the problem related to other games. Who knows.

Hope you find this post and it will save your time. Have a nice gaming!

Friday, May 24, 2013

Notification and confirm service using angular-ui bootstrap, phonegap and AngularJS

I've been playing with AngularJS lately when developing a new application using a Phonegap framework.

Phonegap is a framework which lets you create mobile apps for many platforms by just using HTML5 CSS and Javascript. These won't be as fast as native apps, but it makes developing faster.. I don't want to talk about Phonegap advantages and disadvantages here.

In my mobile applicatin I use alerts and confirmations windows many times.
Ripple - chrome extension that lets you emulate Phonegap someway doesn't provide confirmation windows (as far as I know) so I had to write my own fallback code for using native phonegap notifications on phone and html based notifications. For the second, I've used a great project angular-ui bootstrap which has a dialogs built in.

The code is a AngularJS service. I won't write here how AngularJS is great and awesome. Just look at the website and find yourself using this great framework. I think that Angular service is the right place to put this into work.

I should also mention  that I am using a great angular-phonegap-notification.

My intention was to make my service work similar to Phonegap notification API.

Wednesday, February 6, 2013

Restricting django to one user concurrent session only

Here's the tiny code that helps you avoid multiple users logged using the same account.
# -*- coding: utf-8 -*

from django.conf import settings
from django.core.cache import cache, get_cache
from django.utils.importlib import import_module

class UserRestrictMiddleware(object):
    def process_request(self, request):
        Checks if different session exists for user and deletes it.
        if request.user.is_authenticated():
            cache = get_cache('default')
            cache_timeout = 86400
            cache_key = "user_pk_%s_restrict" % request.user.pk
            cache_value = cache.get(cache_key)

            if cache_value is not None:
                if request.session.session_key != cache_value:
                    engine = import_module(settings.SESSION_ENGINE)
                    session = engine.SessionStore(session_key=cache_value)
                    cache.set(cache_key, request.session.session_key, 
                cache.set(cache_key, request.session.session_key, cache_timeout)

# vim: ai ts=4 sts=4 et sw=4
Hope you like it.
Remember, to put UserRestrictMiddleware somewhere after Session Middleware in MIDDLEWARE_CLASSES (settings.py)

Friday, September 21, 2012

Django cache templatetag with dynamic backend parameter

I've found a nice project django-adv-cache-tag.

From the project website:

With django-adv-cache-tag you can :
  • add a version number (int, string, date or whatever, it will be stringified) to you templatetag : the version will be compared to the cached one, and the exact same cache key will be used for the new cached template, avoiding keeping old unused keys in your cache, allowing you to cache forever.
  • avoid to be afraid of an incompatible update in our algorithm, because we also use an internal version number, updated only when the internal algorithm changes
  • define your own cache keys (or more simple, just add the primary key (or what you want, it's a templatetag parameter) to this cache key
  • compress the data to be cached, to reduce memory consumption in your cache backend, and network latency (but it will use more time and cpu to compress/decompress)
  • choose which cache backend will be used
  • define {% nocache %}...{% endnocache %} blocks, inside your cached template, that will only be rendered when asked (for these parts, the content of the template is cached, not the rendered result)
  • easily define your own algorithm, as we provide a single class you can inherit from, and simply change options or whatever behaviour you want, and define your own tags for them
I am using template fragments caching a lot, but some parts of website need invalidating depending on products type etc. 
I am invalidating cache on save & delete signals for model.

Here's the example:
Say there are 5 types of products and your website includes listing for them (which needs lots of data processing etc) and you want to cache it.

from django.db import models


class Product(models.Model):
    attr1 = ...
    attrn = ...
    type =  models.CharField("Product Type", max_length=6, choices=PRODUCT_TYPE_CHOICES)
Using one backend, modifying product of type1 will purge the entire cache backend. Set up more backends:
# settings.py

    'templates_products_type1': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '',
    'templates_products_type2': {
        'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
        'LOCATION': '',
You can also use Redis for caching, which requires you to run one redis instance with multiple databases. Let's create our own {% my_cache %} templatetag with cache backend name as a first vary_on parameter. (this is the quickest way as you can also use get_pk() or even add your own parameters to {% my_cache %} templatetag. You could also use fragment name but it's not resolvable. Let's get to the code:
from adv_cache_tag.tag import CacheTag
from django.core.cache import get_cache
from django import template

register = template.Library()

class MyCacheTag(CacheTag):
    def get_cache_object(self):
        backend = self.vary_on[0]
        return get_cache(backend)
MyCacheTag.register(register, 'my_cache')
Here's the template code:
# assuming products_type variables is assigned
{% load my_cache_tags %}

{% with backend="templates_products_"|add:products_type %}
{% my_cache 0 products backend other_vary_on_variables %}
{% for product in product_list %}
{{ product }}
{% endfor %}
{% endmy_cache %}
When saving or deleting products of some type, just purge template cache for produdcts only of this specified type.
from django.core.cache import get_cache
#function run on model save / delete

def clear_products_template_cache(type):
    cache_name = "templates_products_" + type
    cache = get_cache(cache_name)
NOTE: This is a SIMPLIFIED solution. I just wanted to point out that you can easily use different backends for one template cache tag. It's your job to make some additional processing code (especialy get_cache_object() for selecting cache backend etc.

Monday, September 17, 2012

Kantor Alior Banku i tajemniczy licznik

W taryfie prowizji i opłat bank wielokrotnie opiera się na wartości "licznika", do wartości którego można
przelewać walutę za darmo. Jeśli nie chcesz czytać całego wpisu, to proszę bardzo.

Możesz wymienić (w tym kantorze) nawet 10 tyś. franków szwajcarskich i nie zapłacisz prowizji za przelew.

Dalej moje boje z kantorami...
W związku z koniecznością wymiany waluty, przy złodziejskim spreadzie walutowym (a więc różnicy w cenie kupna i sprzedaży waluty) postanowiłem poszukać lepszego rozwiązania.

Jako pierwszy przetestowałem serwis inkantor.pl. Jest to jednak kantor, który nie podlega nadzorowi KNF.
Następnym kantorem internetowym był gocash.pl. Jestem z niego zadowolony, a kurs wymiany franka
był jeszcze korzystniejszy.

Obecnie kurs sprzedaży CHF:

3,3717 - gocash
3,3819 - inkantor
3,3666 - kantor alior

W obu przypadkach przelew walutowy zlecony do mbanku trafiał tego samego dnia, o ile zlecony został przed godziną 11ą. Było to nieco problematyczne, gdyż wymiany waluty chciałem dokonywać o godz: 14:50, z której to mbank pobiera kurs do wymiany złotówek na franki w dniu płatności raty za kredyt,
a ja nie chcę bawić się w spekulanta.

Dodam jeszcze, że w przypadku inkantor.pl pobierano ode mnie opłatę ~5 zł za przelew, zaś gocash.pl takiej opłaty nie pobierał.
Może później zrobię porównanie tych serwisów.

Obecnie czas przyszedł na kantor aliorbanku http://kantor.aliorbank.pl
Kursy walut są jeszcze korzystniejsze w moim przypadku. Nie jest to znaczna różnica, gdyż w przypadku gocash.pl te kursy również były bardzo korzystne.

Przelew waluty (nawet w trybie ekspresowym) jest darmowy, ale "do wartości licznika". Co owa wartość oznacza?
Jest to wartość, która powiększa się przy każdej wymianie waluty.
Pierwsza myśl, jaka przychodzi do głowy, to "ile wynosi górna wartość licznika", powyżej której naliczana jest opłata ?
W internecie krążą różne wartości, np. 600 CHF (dla franka szwajcarskiego). Autor tej tezy informuje więc,
że nie opłaca się wymieniać więcej niż 600 franków, gdyż przelanie ich będzie już kosztowne.

Ciekawy tego zagadnienia zacząłem szukać wartości granicznej licznika i niestety nie udało mi się jej znaleźć.
Pani na infolini potwierdziła, że nie ma takiej granicy.

Chodzi o to, by nie wpłacać franków w kasie i korzystać z darmowych przelewów za pośrednictwem tegoż kantoru. Można więc śmiało przelewać każdą wartość waluty, którą za pośrednictwem kantoru wymieniamy.
Pani na infolinii wspomniała też o innych typach zleceń, ale nie to jest tematem tego wpisu.
Najczęściej z kantoru korzystać będzie zwykły zjadacz chleba, który wymienia walutę do swojego kredytu hipotecznego oszczędzając dobre kilkadziesiąt złotych na racie.