jellyfin-kodi/resources/lib/ga_client.py

196 lines
No EOL
6.4 KiB
Python

import sys
import os
import traceback
import requests
import logging
import clientinfo
import hashlib
import xbmc
import platform
import xbmcgui
import time
from utils import window, settings, language as lang
log = logging.getLogger("EMBY."+__name__)
# for info on the metrics that can be sent to Google Analytics
# https://developers.google.com/analytics/devguides/collection/protocol/v1/parameters#events
logEventHistory = {}
# wrap a function to catch, log and then re throw an exception
def log_error(errors=(Exception, )):
def decorator(func):
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except errors as error:
ga = GoogleAnalytics()
errStrings = ga.formatException()
ga.sendEventData("Exception", errStrings[0], errStrings[1], True)
log.exception(error)
log.error("log_error: %s \n args: %s \n kwargs: %s",
func.__name__, args, kwargs)
raise
return wrapper
return decorator
# main GA class
class GoogleAnalytics():
testing = False
def __init__(self):
client_info = clientinfo.ClientInfo()
self.version = client_info.get_version()
self.device_id = client_info.get_device_id()
# user agent string, used for OS and Kodi version identification
kodi_ver = xbmc.getInfoLabel("System.BuildVersion")
if(not kodi_ver):
kodi_ver = "na"
kodi_ver = kodi_ver.strip()
if(kodi_ver.find(" ") > 0):
kodi_ver = kodi_ver[0:kodi_ver.find(" ")]
self.userAgent = "Kodi/" + kodi_ver + " (" + self.getUserAgentOS() + ")"
# Use set user name
self.user_name = settings('username') or settings('connectUsername') or 'None'
# use md5 for client and user for analytics
self.device_id = hashlib.md5(self.device_id).hexdigest()
self.user_name = hashlib.md5(self.user_name).hexdigest()
# resolution
self.screen_mode = xbmc.getInfoLabel("System.ScreenMode")
self.screen_height = xbmc.getInfoLabel("System.ScreenHeight")
self.screen_width = xbmc.getInfoLabel("System.ScreenWidth")
self.lang = xbmc.getInfoLabel("System.Language")
def getUserAgentOS(self):
if xbmc.getCondVisibility('system.platform.osx'):
return "Mac OS X"
elif xbmc.getCondVisibility('system.platform.ios'):
return "iOS"
elif xbmc.getCondVisibility('system.platform.windows'):
return "Windows NT"
elif xbmc.getCondVisibility('system.platform.android'):
return "Android"
elif xbmc.getCondVisibility('system.platform.linux.raspberrypi'):
return "Linux Rpi"
elif xbmc.getCondVisibility('system.platform.linux'):
return "Linux"
else:
return "Other"
def formatException(self):
exc_type, exc_obj, exc_tb = sys.exc_info()
latestStackFrame = None
allStackFrames = traceback.extract_tb(exc_tb)
if(len(allStackFrames) > 0):
latestStackFrame = allStackFrames[-1]
log.error(str(latestStackFrame))
errorType = "NA"
errorFile = "NA"
if(latestStackFrame != None):
fileName = os.path.split(latestStackFrame[0])[1]
codeLine = "NA"
if(len(latestStackFrame) > 3 and latestStackFrame[3] != None):
codeLine = latestStackFrame[3].strip()
errorFile = "%s:%s(%s)(%s)" % (fileName, latestStackFrame[1], exc_obj.message, codeLine)
errorFile = errorFile[0:499]
errorType = "%s" % (exc_type.__name__)
log.error(errorType + " - " + errorFile)
del(exc_type, exc_obj, exc_tb)
return errorType, errorFile
def getBaseData(self):
# all the data we can send to Google Analytics
data = {}
data['v'] = '1'
data['tid'] = 'UA-85356267-1' # tracking id, this is the account ID
data['ds'] = 'plugin' # data source
data['an'] = 'Kodi4Emby' # App Name
data['aid'] = '1' # App ID
data['av'] = self.version # App Version
#data['aiid'] = '1.1' # App installer ID
data['cid'] = self.device_id # Client ID
#data['uid'] = self.user_name # User ID
data['ua'] = self.userAgent # user agent string
# add width and height, only add if full screen
if(self.screen_mode.lower().find("window") == -1):
data['sr'] = str(self.screen_width) + "x" + str(self.screen_height)
data["ul"] = self.lang
return data
def sendScreenView(self, name):
data = self.getBaseData()
data['t'] = 'screenview' # action type
data['cd'] = name
self.sendData(data)
def sendEventData(self, eventCategory, eventAction, eventLabel=None, throttle=False):
# if throttling is enabled then only log the same event every 5 min
if(throttle):
throttleKey = eventCategory + "-" + eventAction + "-" + str(eventLabel)
lastLogged = logEventHistory.get(throttleKey)
if(lastLogged != None):
timeSinceLastLog = time.time() - lastLogged
if(timeSinceLastLog < 300):
log.info("SKIPPING_LOG_EVENT : " + str(timeSinceLastLog) + " " + throttleKey)
return
logEventHistory[throttleKey] = time.time()
data = self.getBaseData()
data['t'] = 'event' # action type
data['ec'] = eventCategory # Event Category
data['ea'] = eventAction # Event Action
if(eventLabel != None):
data['el'] = eventLabel # Event Label
self.sendData(data)
def sendData(self, data):
log.info("GA: " + str(data))
if(settings('metricLogging') == "false"):
return
if(self.testing):
url = "https://www.google-analytics.com/debug/collect" # test URL
else:
url = "https://www.google-analytics.com/collect" # prod URL
try:
r = requests.post(url, data)
except Exception as error:
log.error(error)
if(self.testing):
log.info("GA: " + r.text.encode('utf-8'))