diff --git a/design/design.gaphor b/design/design.gaphor
new file mode 100644
index 0000000..adc8560
--- /dev/null
+++ b/design/design.gaphor
@@ -0,0 +1,1119 @@
+
+
+
+
+
+diagram {
+ /* line-style: sloppy 0.3; */
+}
+
+controlflow {
+ dash-style: 0;
+}
+
+
+
+
+
+Model Name Here
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1. Use Cases
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+2. Domain Analysis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+3. Architectural Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+4. Detailed Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Use Cases
+
+
+
+
+
+
+
+
+
+Analyze functional requirements by
+identifying user roles – actors – and
+associating them to their use cases.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 93.76953125, 79.1953125)
+
+
+(0.0, 0.0)
+
+
+258.0
+
+
+110.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+Use Case Scenarios
+
+
+
+
+
+
+
+
+
+Model abstract use case implementation by creating activity diagrams visualizing activity flows for primary and secondary use case scenarios.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 58.0, 79.0)
+
+
+(0.0, 0.0)
+
+
+364.0
+
+
+95.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+Domain Entities
+
+
+
+
+
+
+
+
+
+Perform domain analysis by modeling domain entities and their relationships using simplified class diagram. This diagram will serve as a visual dictionary of concepts. It will also be a starting point for your design-level data model.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 46.015625, 81.69921875)
+
+
+(0.0, 0.0)
+
+
+400.0
+
+
+100.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+Package Dependencies
+
+
+
+
+
+
+
+
+
+
+
+
+Interactions
+
+
+
+
+
+
+
+
+
+Interaction
+
+
+
+
+
+
+
+
+
+
+Prepare package dependencies diagram to group your implementation classes in appropriate way. This will help you maintain the code well structured and avoid design flaws such as cyclic dependencies or dependencies on unstable parts
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 106.71484375, 51.49999999999997)
+
+
+(0.0, 0.0)
+
+
+271.5703125
+
+
+144.0
+
+
+
+
+
+
+
+
+
+
+Model component interactions for use case scenarios in order to find out new methods in
+existing classes or even new classes with specific responsibilities.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 43.0, 73.0)
+
+
+(0.0, 0.0)
+
+
+322.0
+
+
+93.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+Detailed Class Design
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Create detailed class diagrams to capture your object-oriented data model.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 126.22541649148083, -111.56346769146282)
+
+
+(0.0, 0.0)
+
+
+215.0
+
+
+76.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+Implementation Architecture
+
+
+
+
+
+
+
+
+
+Define the major artifacts that manifest implementation of your components. Indicate how they are deployed on hardware nodes, their inter-dependencies and communication protocols.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, -7.59375, 75.08984375)
+
+
+(0.0, 0.0)
+
+
+271.0
+
+
+129.0
+
+
+
+
+
+
+
+
+
+
+Recommender
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 59.49042039678521, 676.7889605442139)
+
+
+(-4.473890692342593, 0.0)
+
+
+581.5334231350598
+
+
+103.7992092219963
+
+
+
+
+
+
+
+
+
+
+
+
+
+recommend
+
+
+
+
+
+
+
+
+
+
+
+
++ Recommender(history_file: string, cache_db_file: Optional(string) = None)
+
+
+
+
+in
+
+
+count
+
+
+
+
+
+int
+
+
+
+
+1
+
+
+History
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 186.63282775878895, 443.60939025878906)
+
+
+(0.0, 0.0)
+
+
+318.3008270263672
+
+
+164.75778198242188
+
+
+
+
+
+0
+
+
+
+
+
+
+
+
+
+
+1
+
+
+History
+
+
+
+
+
+
+
+
+
+in
+
+
+filename
+
+
+
+
+
+string
+
+
+
+
+
+
+
+
+
+
+0
+
+
+0
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 427.1573380812623, 679.4648742675781)
+
+
+[(0.37800127420644003, -2.6759137233642605), (0.37800127420644003, -71.09770202636719)]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1
+
+
+1
+
+
+
+
+composite
+
+
+
+
+
+
+
+
+
+
+
+*
+
+
+*
+
+
+
+
+YouTubeHistory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 86.18801116943362, 224.98699188232428)
+
+
+(0.0, 44.798164367675795)
+
+
+181.64712270100912
+
+
+58.35613250732423
+
+
+
+
+
+0
+
+
+0
+
+
+
+
+
+
+
+FreeTubeHistory
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 380.05679575602204, 226.81316375732425)
+
+
+(0.0, 43.58071645100908)
+
+
+249.7537180582683
+
+
+57.138684590657604
+
+
+
+
+
+0
+
+
+0
+
+
+
+
+
+
+
+
+
+
+0
+
+
+0
+
+
+(1.0, 0.0, 0.0, 1.0, 223.12159220377606, 442.6041793823242)
+
+
+[(0.0, 0.0), (0.6699211932502465, -114.46289062499994)]
+
+
+
+
+
+
+
+
+
+
+0
+
+
+0
+
+
+(1.0, 0.0, 0.0, 1.0, 438.54807535807294, 442.6823043823242)
+
+
+[(0.0, 0.0), (0.3684514898106386, -115.14973958333326)]
+
+
+
+
+
+
+
+
+
+
+1
+
+
++ parse_history(filename: string) -> History
+
+
+
+
+When parse_history() is called, it should identify and return the correct history type. It can leverage the is_this_type() function that the implementers of this interface should have to identify whether it's the correct type.
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 531.3502782185875, 411.48828125)
+
+
+(0.0, 0.0)
+
+
+170.39703369140614
+
+
+229.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+1
+
+
++ is_this_type(in filename: string) -> bool
+
+
+
+
+
+
+
+1
+
+
++ get_video(in index: int) -> Video
+
+
+
+
+
+
+
+1
+
+
+__iter__
+
+
+
+
+
+
+
+1
+
+
+__size__
+
+
+
+
+Video
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(1.0, 0.0, 0.0, 1.0, 863.6850618434581, 361.7811660068871)
+
+
+(0.0, 0.0)
+
+
+644.0
+
+
+161.64602675087428
+
+
+
+
+
+0
+
+
+
+
+
+
+
+
+
+
+0
+
+
++ getID() -> string
+
+
+
+
+
+
+
+0
+
+
++ getWatchTime() -> float
+
+
+
+
+
+
+
+0
+
+
++ getWatchProgress() -> float
+
+
+
+
+
+
+
+0
+
+
++ getTitle() -> string
+
+
+
+
+
+
+
+0
+
+
++ getDescription() -> string
+
+
+
+
+
+
+
+Video
+
+
+
+
+
+
+
+
+
+
+
+
+
+in
+
+
+id
+
+
+
+
+
+string
+
+
+
+
+in
+
+
+watch_time
+
+
+
+
+
+float
+
+
+
+
+in
+
+
+watch_progress
+
+
+
+
+
+float
+
+
+
+
+in
+
+
+title
+
+
+
+
+
+string
+
+
+
+
+in
+
+
+description
+
+
+
+
+
+string
+
+
+
+
\ No newline at end of file
diff --git a/shadowtube/types.py b/shadowtube/types.py
new file mode 100644
index 0000000..ff20f6a
--- /dev/null
+++ b/shadowtube/types.py
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2025 Fedir Kovalov.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, version 3.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+
+
+class Video:
+ def __init__(
+ self,
+ id: str,
+ title: str,
+ description: str,
+ watch_time: float,
+ watch_progress: float,
+ ):
+ self._id = id
+ self._title = title
+ self._description = description
+ self._watch_time = watch_time
+ self._watch_progress = watch_progress
+
+ @property
+ def title(self):
+ return self._title
+
+ @property
+ def id(self):
+ return self._id
+
+ @property
+ def description(self):
+ return self._description
+
+ @property
+ def watch_time(self):
+ return self._watch_time
+
+ @property
+ def watch_progress(self):
+ return self._watch_progress