From 63f6892a81bdab90f4b97e9252fe9134cd16f892 Mon Sep 17 00:00:00 2001 From: Andrey Maksimov Date: Fri, 19 Jan 2024 19:24:01 +0300 Subject: [PATCH] Add telemetry --- data/com.github.tenderowl.frog.gschema.xml | 10 ++++++++ flatpak/com.github.tenderowl.frog.json | 1 + flatpak/python3-nanoid.json | 14 ++++++++++ frog/main.py | 29 +++++++++++++++++++-- frog/services/clipboard_service.py | 4 +++ frog/services/posthog.py | 3 --- frog/services/screenshot_service.py | 3 +++ frog/services/share_service.py | 3 +++ frog/services/telemetry.py | 30 ++++++++++++++++++++++ frog/widgets/language_popover.py | 5 ++-- frog/widgets/preferences_general_page.py | 5 +++- 11 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 flatpak/python3-nanoid.json delete mode 100644 frog/services/posthog.py create mode 100644 frog/services/telemetry.py diff --git a/data/com.github.tenderowl.frog.gschema.xml b/data/com.github.tenderowl.frog.gschema.xml index 7e6ea37..650aac4 100644 --- a/data/com.github.tenderowl.frog.gschema.xml +++ b/data/com.github.tenderowl.frog.gschema.xml @@ -1,6 +1,16 @@ + + "" + App Installation ID + Unique installation identifier. + + + true + Telemetry activation + Telemetry activate status. + -1 diff --git a/flatpak/com.github.tenderowl.frog.json b/flatpak/com.github.tenderowl.frog.json index b45f1c3..364891b 100644 --- a/flatpak/com.github.tenderowl.frog.json +++ b/flatpak/com.github.tenderowl.frog.json @@ -41,6 +41,7 @@ "tesseract.json", "libportal.json", "zbar.json", + "python3-nanoid.json", "python3-loguru.json", "python3-pytesseract.json", "python3-pyzbar.json", diff --git a/flatpak/python3-nanoid.json b/flatpak/python3-nanoid.json new file mode 100644 index 0000000..4f27ec6 --- /dev/null +++ b/flatpak/python3-nanoid.json @@ -0,0 +1,14 @@ +{ + "name": "python3-nanoid", + "buildsystem": "simple", + "build-commands": [ + "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"nanoid\" --no-build-isolation" + ], + "sources": [ + { + "type": "file", + "url": "https://files.pythonhosted.org/packages/2e/0d/8630f13998638dc01e187fadd2e5c6d42d127d08aeb4943d231664d6e539/nanoid-2.0.0-py3-none-any.whl", + "sha256": "90aefa650e328cffb0893bbd4c236cfd44c48bc1f2d0b525ecc53c3187b653bb" + } + ] +} \ No newline at end of file diff --git a/frog/main.py b/frog/main.py index 6f61235..bdbe0a7 100644 --- a/frog/main.py +++ b/frog/main.py @@ -30,14 +30,15 @@ import sys from gettext import gettext as _ +import nanoid from gi.repository import Gtk, Gio, GLib, Notify, Adw, GdkPixbuf, Gdk, GObject from loguru import logger from frog.config import RESOURCE_PREFIX, APP_ID from frog.language_manager import language_manager from frog.services.clipboard_service import clipboard_service -from frog.services.posthog import posthog from frog.services.screenshot_service import ScreenshotService +from frog.services.telemetry import telemetry from frog.settings import Settings from frog.window import FrogWindow @@ -47,6 +48,7 @@ class FrogApplication(Adw.Application): gtk_settings: Gtk.Settings settings: Settings = GObject.Property(type=GObject.TYPE_PYOBJECT) + installation_id: str = GObject.Property(type=str) def __init__(self, version=None): super().__init__(application_id=APP_ID, @@ -57,6 +59,9 @@ def __init__(self, version=None): # Init GSettings self.settings = Settings.new() + telemetry.set_is_active(self.settings.get_boolean('telemetry')) + self.ensure_installation_id() + self.add_main_option( 'extract_to_clipboard', ord('e'), @@ -123,16 +128,29 @@ def do_command_line(self, command_line): self.activate() return 0 + def ensure_installation_id(self): + self.installation_id = self.settings.get_string("installation-id") + if not self.installation_id: + logger.info("No installation id was found. Generating a new one.") + self.installation_id = nanoid.generate() + self.settings.set_string("installation-id", self.installation_id) + telemetry.set_installation_id(self.installation_id) + telemetry.capture('new Installation ID generated') + + telemetry.set_installation_id(self.installation_id) + def on_preferences(self, _action, _param) -> None: + telemetry.capture('preferences activated') self.get_active_window().show_preferences() def on_github_star(self, _action, _param) -> None: - posthog.capture('github_star', 'github_star_activated') + telemetry.capture('star github activated') launcher: Gtk.UriLauncher = Gtk.UriLauncher() launcher.set_uri('https://github.com/TenderOwl/Frog') launcher.launch(callback=self._on_github_star) def on_about(self, _action, _param): + telemetry.capture('about activated') about_window = Adw.AboutWindow( application_name="Frog", application_icon=APP_ID, @@ -158,27 +176,34 @@ def on_about(self, _action, _param): about_window.present() def on_shortcuts(self, _action, _param): + telemetry.capture('shortcuts activated') builder = Gtk.Builder() builder.add_from_resource(f"{RESOURCE_PREFIX}/ui/shortcuts.ui") builder.get_object("shortcuts").set_transient_for(self.get_active_window()) builder.get_object("shortcuts").present() def on_copy_to_clipboard(self, _action, _param) -> None: + telemetry.capture('copy_to_clipboard activated') self.get_active_window().on_copy_to_clipboard(self) def on_show_uri(self, _action, param) -> None: + telemetry.capture('show_uri activated') Gtk.show_uri(None, param.get_string(), Gdk.CURRENT_TIME) def get_screenshot(self, _action, _param) -> None: + telemetry.capture('screenshot activated') self.get_active_window().get_screenshot() def get_screenshot_and_copy(self, _action, _param) -> None: + telemetry.capture('screenshot_and_copy activated') self.get_active_window().get_screenshot(copy=True) def open_image(self, _action, _param) -> None: + telemetry.capture('open_image activated') self.get_active_window().open_image() def on_paste_from_clipboard(self, _action, _param) -> None: + telemetry.capture('paste_from_clipboard activated') self.get_active_window().on_paste_from_clipboard(self) @staticmethod diff --git a/frog/services/clipboard_service.py b/frog/services/clipboard_service.py index 09f4b12..1e4c4cc 100644 --- a/frog/services/clipboard_service.py +++ b/frog/services/clipboard_service.py @@ -31,6 +31,8 @@ from gi.repository import Gdk, GObject, Gio from loguru import logger +from frog.services.telemetry import telemetry + class ClipboardService(GObject.GObject): __gtype_name__ = 'ClipboardService' @@ -47,6 +49,7 @@ def __init__(self): def set(self, value: str) -> None: self.clipboard.set(value) + telemetry.capture('clipboard set') def _on_read_texture(self, _sender: GObject.GObject, result: Gio.AsyncResult) -> None: try: @@ -57,6 +60,7 @@ def _on_read_texture(self, _sender: GObject.GObject, result: Gio.AsyncResult) -> self.emit('paste_from_clipboard', texture) def read_texture(self) -> None: + telemetry.capture('clipboard read texture') self.clipboard.read_texture_async(cancellable=None, callback=self._on_read_texture) diff --git a/frog/services/posthog.py b/frog/services/posthog.py deleted file mode 100644 index 687de63..0000000 --- a/frog/services/posthog.py +++ /dev/null @@ -1,3 +0,0 @@ -from posthog import Posthog - -posthog = Posthog(project_api_key='phc_mggXA1JbzpJR95H9RO5yNVIh6kVDliVjD5hOjiaXkj6', host='https://us.posthog.com') diff --git a/frog/services/screenshot_service.py b/frog/services/screenshot_service.py index fe63be3..20a34de 100644 --- a/frog/services/screenshot_service.py +++ b/frog/services/screenshot_service.py @@ -32,6 +32,7 @@ from loguru import logger from frog.config import tessdata_config +from frog.services.telemetry import telemetry try: from PIL import Image @@ -82,6 +83,7 @@ def capture(self, lang: str, copy: bool = False) -> None: If image is not recognized, returns None. """ + telemetry.capture('screenshot capture', {'language': lang}) self.portal.take_screenshot( None, Xdp.ScreenshotFlags.INTERACTIVE, @@ -151,4 +153,5 @@ def decode_image(self, self.emit("error", "No text found.") def capture_cancelled(self, cancellable: Gio.Cancellable) -> None: + telemetry.capture('screenshot cancelled') self.emit("error", "Cancelled") diff --git a/frog/services/share_service.py b/frog/services/share_service.py index 9dd9a84..592324a 100644 --- a/frog/services/share_service.py +++ b/frog/services/share_service.py @@ -31,6 +31,8 @@ from gi.repository import GObject, Gtk from loguru import logger +from frog.services.telemetry import telemetry + class ShareService(GObject.GObject): __gtype_name__ = "ShareService" @@ -55,6 +57,7 @@ def providers() -> List[str]: ] def share(self, provider: str, text: str): + telemetry.capture("share", {'provider': provider}) if not text: return diff --git a/frog/services/telemetry.py b/frog/services/telemetry.py new file mode 100644 index 0000000..03c9b1b --- /dev/null +++ b/frog/services/telemetry.py @@ -0,0 +1,30 @@ +from typing import Any + +from gi.repository import GObject +from posthog import Posthog + + +class TelemetryService(GObject.GObject): + _gtype_name = 'TelemetryService' + + posthog: Posthog | None + installation_id: str | None + is_active: bool = True + + def __init__(self): + super().__init__() + self.posthog = Posthog(project_api_key='phc_HpETCN6yQKZIr8gr6mBQTd3H0SjKUBrNMI3AizoX97f', + host='https://eu.posthog.com') + + def set_installation_id(self, installation_id: str): + self.installation_id = installation_id + + def set_is_active(self, is_active: bool): + self.is_active = is_active + + def capture(self, event: str, props: Any = None): + if self.posthog and self.is_active: + self.posthog.capture(self.installation_id, event, props) + + +telemetry = TelemetryService() diff --git a/frog/widgets/language_popover.py b/frog/widgets/language_popover.py index c1fbceb..a5a3b2b 100644 --- a/frog/widgets/language_popover.py +++ b/frog/widgets/language_popover.py @@ -31,7 +31,7 @@ from frog.config import RESOURCE_PREFIX from frog.language_manager import language_manager -from frog.services.posthog import posthog +from frog.services.telemetry import telemetry from frog.settings import Settings from frog.types.language_item import LanguageItem from frog.widgets.language_popover_row import LanguagePopoverRow @@ -96,6 +96,7 @@ def _on_language_removed(self, _sender, _lang_code: str): @Gtk.Template.Callback() def _on_search_activate(self, entry: Gtk.SearchEntry): + telemetry.capture('language_search activated') self._on_language_activate(self.list_view, 0) @Gtk.Template.Callback() @@ -104,7 +105,7 @@ def _on_language_activate(self, _: Gtk.ListBox, row: LanguagePopoverRow): self.emit('language-changed', item) self.active_language = item.code language_manager.active_language = item - posthog.capture(item.code, 'language-activated') + telemetry.capture('language-activated', {'language': self.active_language}) self.popdown() @Gtk.Template.Callback() diff --git a/frog/widgets/preferences_general_page.py b/frog/widgets/preferences_general_page.py index b343264..fc5e8b4 100644 --- a/frog/widgets/preferences_general_page.py +++ b/frog/widgets/preferences_general_page.py @@ -25,7 +25,7 @@ # holders shall not be used in advertising or otherwise to promote the sale, # use or other dealings in this Software without prior written # authorization. - +import posthog from gi.repository import Gtk, Adw, Gio from loguru import logger @@ -58,6 +58,9 @@ def __init__(self): self.extra_language_combo.set_selected(extra_language_index) self.extra_language_combo.connect('notify::selected-item', self._on_extra_language_changed) + def do_show(self, *args, **kwargs): + posthog.capture('', 'preferences general page opened') + def _on_extra_language_changed(self, combo_row: Adw.ComboRow, _param): lang_name = combo_row.get_selected_item().get_string() lang_code = language_manager.get_language_code(lang_name)