Superb quality and spec AB-Com PULSe 4K SE. Crazy offer! Only £99! FREE UK DELIVERY! 4K UHD, Enigma 2, Multiboot 4 images & more!...
Superb quality and spec AB-Com PULSe 4K Rev II Twin Satellite tuner only £149! FREE UK DELIVERY! 4K UHD, Enigma 2, SATA HDD facility, Multiboot 4 images & more!...

[Mut@nt HD2400] Watch log?

adennisa15

New member
Joined
Oct 3, 2021
Messages
18
Reaction score
0
Points
1
What type of support thread are you creating?
Support question
What OpenViX Image build number are you using?
6.7.020
Have you tried re-flashing WITHOUT settings restore?
NO
Have you tried re-flashing WITH a settings restore?
YES
This is probably more of a developer question, than a support question? (So this might be better asked elsewhere, feel free to point me in the right direction...)

Q: I'd like a simple logfile that contains information about what has been watched and when.

e.g. something along the lines of...
Rich (BB code):
[timestamp 1] playback started of "/path/xxx episode 6.mp4"
[timestamp 2] playback ended of "/path/xxx episode 6.mp4"
[timestamp 3] started viewing service nnn - 'service name 1' [maybe with prog name too?]
[timestamp 4] started viewing service ppp - 'service name 2'
etc...

I'm currently using OpenVix 5.7.020 on a Mut@nt HD2400, if that makes any difference?

I've had a bit of a dig around, but so far, nothing has leapt out at me.

Is that something that can be obtained just by turning on some existing debug/logging, or would it require code change, either in enigma2 or maybe through a plugin?

I'm a software developer with several decades of experience, including reasonably familiar with Python - I'd be up for trying to write something, but for now, I'm just looking for some initial orientation, before I head off in completely the wrong direction! :)

Thanks ;)
 
This is probably more of a developer question, than a support question? (So this might be better asked elsewhere, feel free to point me in the right direction...)

Q: I'd like a simple logfile that contains information about what has been watched and when.

e.g. something along the lines of...
Rich (BB code):
[timestamp 1] playback started of "/path/xxx episode 6.mp4"
[timestamp 2] playback ended of "/path/xxx episode 6.mp4"
[timestamp 3] started viewing service nnn - 'service name 1' [maybe with prog name too?]
[timestamp 4] started viewing service ppp - 'service name 2'
etc...

I'm currently using OpenVix 5.7.020 on a Mut@nt HD2400, if that makes any difference?

I've had a bit of a dig around, but so far, nothing has leapt out at me.

Is that something that can be obtained just by turning on some existing debug/logging, or would it require code change, either in enigma2 or maybe through a plugin?

I'm a software developer with several decades of experience, including reasonably familiar with Python - I'd be up for trying to write something, but for now, I'm just looking for some initial orientation, before I head off in completely the wrong direction! :)

Thanks ;)
you would have to turn on debug logs, then read the debug file(s) and then sift through each line extracting the information you want.
you might also have to add debug lines to modules to add information if its not there.
there are other ways maybe but not simple code change.
 
Thanks @twol, definitely a good suggestion of how to do this.

I've turned the debug logs on and there's definitely useful info in there. Extracting it shouldn't be too hard, I just need to get to grips with how the log files behave over time (rotate/name/truncate etc).

I had a decent sized log file built up yesterday, but then it disappeared when I flashed from 6.7.020 to a self built 6.8.007 (mutant2400 not being built for 6.8+), which thinking about it is probably quite reasonable as the new rootfs will blow away the old and I bet debug log files aren't backed up and restored along with everything else.... Shame I didn't think to grab the debug log before I loaded the new version on though! 🫤 Never mind...
 
Menu/setup/system/logs settings …..you can specify hiw much to keep.
otherwise it will delete to save on disk space
 
They are rolling logs, so a new one is created once the file size limit is reached.
 
This is probably more of a developer question, than a support question? (So this might be better asked elsewhere, feel free to point me in the right direction...)

Q: I'd like a simple logfile that contains information about what has been watched and when.

e.g. something along the lines of...
Rich (BB code):
[timestamp 1] playback started of "/path/xxx episode 6.mp4"
[timestamp 2] playback ended of "/path/xxx episode 6.mp4"
[timestamp 3] started viewing service nnn - 'service name 1' [maybe with prog name too?]
[timestamp 4] started viewing service ppp - 'service name 2'
etc...

I'm currently using OpenVix 5.7.020 on a Mut@nt HD2400, if that makes any difference?

I've had a bit of a dig around, but so far, nothing has leapt out at me.

Is that something that can be obtained just by turning on some existing debug/logging, or would it require code change, either in enigma2 or maybe through a plugin?

I'm a software developer with several decades of experience, including reasonably familiar with Python - I'd be up for trying to write something, but for now, I'm just looking for some initial orientation, before I head off in completely the wrong direction! :)

Thanks ;)

This is not terribly hard to do. Are you wanting to do the work yourself?
Example:
watch-history_20260503120321.webp
 
This is not terribly hard to do. Are you wanting to do the work yourself?
Example:
...
Thanks, what is that? Does something already exist, or is that just a mock up?

No, I have no great masochistic desire to reinvent the wheel! If something already exists, then I'll happily try it out!
 
LOL
It would probably take more energy to make a proper mock-up. Anyway, unzip the attached folder and install it in the receiver. Reboot. That should be enough to make it work. Customize it to your liking.
 

Attachments

LOL
It would probably take more energy to make a proper mock-up. Anyway, unzip the attached folder and install it in the receiver. Reboot. That should be enough to make it work. Customize it to your liking.
Thanks @el bandido, that's fantastic!

You previously said "it's not terribly hard to do", well, maybe not if you're already familiar with how to write plugins and know how enigma2 works internally, it isn't! But yes, from a quick look at your code, it doesn't look that complicated. Don't worry, I fully appreciate how much experience lies behind producing apparently "effortless" code like this! :)

I managed to find some time last night to get this installed and quickly tried it out. Naturally, it worked first time. I'll live with it for a dew days and see if it's giving me the info I think I'd like to have. I'll certainly customise if not.

Another quick look at the log file this morning shows it includes a couple of 3 minute IEPG data 1 entries - maybe the first customisation will be to filter those out ;)

Thank you though, for producing this, it's what's great about a community like this! Long may it continue. (y)
 
I made a few edits and put it into .ipk format. It takes 1 minute to log a channel or services. Anything less than that is considered surfing and is discarded. All the useless epg entries are also gone. Compare this python plugin to the first version to see what was changed in the code. Make more edits as needed.
 

Attachments

Why don't you inherit, instead of creating a whole new screen just to display a ScrollLabel?
 
Well you have the Yellow/Clear button. That is why. Feel free to change or alter it. It's short, around 230 lines...Feel free to improve it! Thanks.
 
Well you have the Yellow/Clear button. That is why. Feel free to change or alter it. It's short, around 230 lines...Feel free to improve it! Thanks.
You can get rid of 40 lines. Probably more if you question the try/except logic. And no need for the embedded skin.

Code:
# -*- coding: utf-8 -*-
#
# TNAP Watch History
# Silently logs watched channels/shows with duration.
# Log file: /var/log/watched.log
#

from Plugins.Plugin import PluginDescriptor
from Screens.TextBox import TextBox
from Components.ActionMap import ActionMap
from Components.Sources.StaticText import StaticText
from ServiceReference import ServiceReference
from enigma import iPlayableService
from datetime import datetime, timedelta
import os

LOG_FILE      = "/var/log/watched.log"
MAX_LOG_BYTES = 2 * 1024 * 1024   # rotate when file exceeds 2 MB
MIN_WATCH_SECS = 60               # ignore channel surfs shorter than 1 minute

_tracker = None


# ---------------------------------------------------------------------------
# Log rotation: keep the second half of the file when size limit is hit
# ---------------------------------------------------------------------------

def _rotateLog():
    if os.path.exists(LOG_FILE) and os.path.getsize(LOG_FILE) > MAX_LOG_BYTES:
        with open(LOG_FILE, "r+") as f:
            f.seek(0, 2)  # seek eof and the read pos with tell
            f.seek(f.tell() // 2)  # seek to centre
            f.readline()  # move to next full line
            data = f.read()
            f.seek(0)
            f.write(data)
            f.truncate()


# ---------------------------------------------------------------------------
# Background tracker — one instance lives for the whole session
# ---------------------------------------------------------------------------

class WatchHistoryTracker:
    def __init__(self, session):
        self.session = session
        self._reset()
        session.nav.event.append(self._onEvent)
        # Capture service already playing before our hook was registered
        self._onServiceStart()

    def _reset(self):
        self._start_time = None
        self._channel = ""
        self._title = ""

    def _onEvent(self, evt):
        if evt == iPlayableService.evStart:
            self._onServiceStart()
        elif evt == iPlayableService.evUpdatedEventInfo:
            self._fetchEpg()
        elif evt == iPlayableService.evEnd:
            self._writeDuration()
            self._reset()

    def _onServiceStart(self):
        ref = self.session.nav.getCurrentlyPlayingServiceOrGroup()

        channel = ""
        if ref:
            try:
                channel = ServiceReference(ref).getServiceName() or ""
            except Exception:
                pass
        channel = channel.strip()

        # Skip if same channel (evStart fires multiple times for same service)
        if channel and channel == self._channel:
            return

        # Flush previous channel before switching
        if self._start_time and self._channel:
            self._writeDuration()

        self._start_time = datetime.now()
        self._channel = channel
        self._title = ""
        self._fetchEpg()

    def _fetchEpg(self):
        service = self.session.nav.getCurrentService()
        if not service:
            return
        try:
            info = service.info()
            event = info and info.getEvent(0)
            if event:
                title = (event.getEventName() or "").strip()
                if title.lower() not in ("dummyeventname", "no information", ""):
                    self._title = title
        except Exception:
            pass

    def _writeDuration(self):
        if not self._start_time or not self._channel:
            return
        secs = int((datetime.now() - self._start_time).total_seconds())
        if secs < MIN_WATCH_SECS:
            return
        # Final EPG attempt in case evUpdatedEventInfo was missed
        if not self._title:
            self._fetchEpg()
        dur = str(timedelta(seconds=secs))
        stop = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        parts = [stop, "watched %s" % dur, self._channel]
        line = " | ".join(filter(None, [stop, f"watched {dur}", self._channel, self._title])) + "\n"
        try:
            _rotateLog()
            with open(LOG_FILE, 'a') as f:
                f.write(line)
        except Exception:
            pass


# ---------------------------------------------------------------------------
# Plugin entry points
# ---------------------------------------------------------------------------

def autostart(reason, **kwargs):
    if reason == 0:
        session = kwargs.get("session")
        if session:
            global _tracker
            _tracker = WatchHistoryTracker(session)


def openViewer(session, **kwargs):
    session.open(WatchHistoryViewer)


def Plugins(**kwargs):
    return [
        PluginDescriptor(
            name=_("TNAP Watch History"),
            description=_("Silently logs watched channels and shows"),
            where=PluginDescriptor.WHERE_SESSIONSTART,
            needsRestart=False,
            fnc=autostart,
        ),
        PluginDescriptor(
            name=_("TNAP Watch History"),
            description=_("View recently watched channels and shows"),
            where=PluginDescriptor.WHERE_PLUGINMENU,
            needsRestart=False,
            fnc=openViewer,
        ),
    ]


# ---------------------------------------------------------------------------
# Viewer screen
# ---------------------------------------------------------------------------

class WatchHistoryViewer(TextBox):
    def __init__(self, session):
        TextBox.__init__(self, session, text=self._loadLog(), title=_("Watch History"))
        self["key_yellow"] = StaticText(_("Clear Log"))
        self["actions"] = ActionMap(["ColorActions"], {"yellow": self.clearLog, }, -1)

    def _loadLog(self):
        if not os.path.isfile(LOG_FILE):
            return _("No watch history yet.\n\nChannels will be logged here as you watch them.")
        try:
            with open(LOG_FILE, "r", encoding="utf-8", errors="replace") as f:
                lines = f.readlines()
            if not lines:
                return _("Log is empty.")
            lines.reverse()
            header = _("Timestamp | Watched duration | Channel | Show Title | Description\n")
            header += "-" * 90 + "\n"
            return header + "".join(lines)
        except Exception as e:
            return _("Could not read log: %s") % str(e)

    def clearLog(self):
        try:
            if os.path.isfile(LOG_FILE):
                os.remove(LOG_FILE)
            self["text"].setText(_("Log cleared."))
        except Exception as e:
            self["text"].setText(_("Could not clear log: %s") % str(e))
 

Attachments

  • 1.webp
    1.webp
    38.6 KB · Views: 8

OpenViX Feeds Status

Back
Top