<filename>i3pystatus/bitstamp.py
import urllib.request
import json
from datetime import datetime

from i3pystatus import IntervalModule
from i3pystatus.core.util import internet, require, user_open

import locale
import threading
from contextlib import contextmanager

LOCALE_LOCK = threading.Lock()


@contextmanager
def setlocale(name):
    # To deal with locales only in this module and keep it thread save
    with LOCALE_LOCK:
        saved = locale.setlocale(locale.LC_ALL)
        try:
            yield locale.setlocale(locale.LC_ALL, name)
        finally:
            locale.setlocale(locale.LC_ALL, saved)


class Bitstamp(IntervalModule):

    """
    This module fetches and displays current Bitcoin market prices. Market data
    is pulled from the Bitstamp api.

    .. rubric:: Available formatters

    * {last}
    * {ask}
    * {bid}
    * {volume}
    # * {volume_thousand}
    * {age}
    * {status}

    """

    settings = (
        ("format", "Format string used for output."),
        ("color", "Standard color"),
        ("url", "url to get the data from"),
        ("colorize", "Enable color change on price increase/decrease"),
        ("color_up", "Color for price increases"),
        ("color_down", "Color for price decreases"),
        ("interval", "Update interval."),
    )
    format = "{status}{last}"
    url = "https://www.bitstamp.net/api/v2/ticker/btcusd"
    color = "#FFFFFF"
    colorize = False
    color_up = "#00FF00"
    color_down = "#FF0000"
    interval = 600
    status = {
        "price_up": "▲",
        "price_constant": " ",
        "price_down": "▼",
    }

    on_leftclick = "electrum"
    on_rightclick = ["open_something", "https://bitstamp.net/market/tradeview/"]

    _price_prev = 0

    def _get_age(self, timestamp):
        with setlocale('C'):  # Deal with locales (months name differ)
            # Assume format is always utc, to avoid import pytz
            diff = datetime.utcnow() - datetime.fromtimestamp(timestamp)
        return int(diff.total_seconds())


    @require(internet)
    def run(self):
        price_data = json.loads(
            urllib.request.urlopen(self.url).read().decode("utf-8")
        )

        fdict = {
            "ask": float(price_data["ask"]),
            "bid": float(price_data["bid"]),
            "last": float(price_data["last"]),
            "volume": float(price_data["volume"]),
            # "volume_thousand": float(price_data["volume"]) / 1000,
            "age": self._get_age(int(price_data['timestamp']))
        }

        if self._price_prev and fdict["last"] > self._price_prev:
            color = self.color_up
            fdict["status"] = self.status["price_up"]
        elif self._price_prev and fdict["last"] < self._price_prev:
            color = self.color_down
            fdict["status"] = self.status["price_down"]
        else:
            color = self.color
            fdict["status"] = self.status["price_constant"]
        self._price_prev = fdict["last"]

        if not self.colorize:
            color = self.color

        self.output = {
            "full_text": self.format.format(**fdict),
            "color": color,
        }

    def open_something(self, url_or_command):
        """
        Wrapper function, to pass the arguments to user_open
        """
        user_open(url_or_command)

<filename>i3pystatus/bitstamp.py
import urllib.request
import json
from datetime import datetime

from i3pystatus import IntervalModule
from i3pystatus.core.util import internet, require, user_open

import locale
import threading
from contextlib import contextmanager

LOCALE_LOCK = threading.Lock()


@contextmanager
def setlocale(name):
    # To deal with locales only in this module and keep it thread save
    with LOCALE_LOCK:
        saved = locale.setlocale(locale.LC_ALL)
        try:
            yield locale.setlocale(locale.LC_ALL, name)
        finally:
            locale.setlocale(locale.LC_ALL, saved)


class Bitstamp(IntervalModule):

    """
    This module fetches and displays current Bitcoin market prices. Market data
    is pulled from the Bitstamp api.

    .. rubric:: Available formatters

    * {last}
    * {ask}
    * {bid}
    * {volume}
    # * {volume_thousand}
    * {age}
    * {status}

    """

    settings = (
        ("format", "Format string used for output."),
        ("color", "Standard color"),
        ("url", "url to get the data from"),
        ("colorize", "Enable color change on price increase/decrease"),
        ("color_up", "Color for price increases"),
        ("color_down", "Color for price decreases"),
        ("interval", "Update interval."),
    )
    format = "{status}{last}"
    url = "https://www.bitstamp.net/api/v2/ticker/btcusd"
    color = "#FFFFFF"
    colorize = False
    color_up = "#00FF00"
    color_down = "#FF0000"
    interval = 600
    status = {
        "price_up": "▲",
        "price_constant": " ",
        "price_down": "▼",
    }

    on_leftclick = "electrum"
    on_rightclick = ["open_something", "https://bitstamp.net/market/tradeview/"]

    _price_prev = 0

    def _get_age(self, timestamp):
        with setlocale('C'):  # Deal with locales (months name differ)
            # Assume format is always utc, to avoid import pytz
            diff = datetime.utcnow() - datetime.fromtimestamp(timestamp)
        return int(diff.total_seconds())


    @require(internet)
    def run(self):
        price_data = json.loads(
            urllib.request.urlopen(self.url).read().decode("utf-8")
        )

        fdict = {
            "ask": float(price_data["ask"]),
            "bid": float(price_data["bid"]),
            "last": float(price_data["last"]),
            "volume": float(price_data["volume"]),
            # "volume_thousand": float(price_data["volume"]) / 1000,
            "age": self._get_age(int(price_data['timestamp']))
        }

        if self._price_prev and fdict["last"] > self._price_prev:
            color = self.color_up
            fdict["status"] = self.status["price_up"]
        elif self._price_prev and fdict["last"] < self._price_prev:
            color = self.color_down
            fdict["status"] = self.status["price_down"]
        else:
            color = self.color
            fdict["status"] = self.status["price_constant"]
        self._price_prev = fdict["last"]

        if not self.colorize:
            color = self.color

        self.output = {
            "full_text": self.format.format(**fdict),
            "color": color,
        }

    def open_something(self, url_or_command):
        """
        Wrapper function, to pass the arguments to user_open
        """
        user_open(url_or_command)

# To deal with locales only in this module and keep it thread save This module fetches and displays current Bitcoin market prices. Market data     is pulled from the Bitstamp api.      .. rubric:: Available formatters      * {last}     * {ask}     * {bid}     * {volume}     # * {volume_thousand}     * {age}     * {status} # Deal with locales (months name differ) # Assume format is always utc, to avoid import pytz # "volume_thousand": float(price_data["volume"]) / 1000, Wrapper function, to pass the arguments to user_open