Add initial project structure with Knuddels API integration
Introduced the foundational codebase for a new Python wrapper to interact with the Knuddels.de API. This includes a .gitignore file to exclude virtual environments and compiled Python files, basic project metadata in pyproject.toml, and license information. Core functionality is added in the `api.py` file within a `Knuddels` class, enabling login, session handling, and GraphQL queries for message management. Accompanying `users.py` and `messages.py` modules define relevant data classes. Also set up a test script to verify login and data retrieval flows.
This commit is contained in:
commit
3473e6ed6d
10 changed files with 321 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
venv/
|
||||
*.pyc
|
||||
__pycache__/
|
0
LICENSE
Normal file
0
LICENSE
Normal file
0
README.md
Normal file
0
README.md
Normal file
23
pyproject.toml
Normal file
23
pyproject.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "pyknuddels"
|
||||
version = "0.1.0"
|
||||
authors = [
|
||||
{ name="Kumi", email="pyknuddels@kumi.email" },
|
||||
]
|
||||
description = "Simple Python wrapper to fetch data from Knuddels.de"
|
||||
readme = "README.md"
|
||||
license = { file="LICENSE" }
|
||||
requires-python = ">=3.10"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
"Homepage" = "https://kumig.it/kumitterer/pyknuddels"
|
||||
"Bug Tracker" = "https://kumig.it/kumitterer/pyknuddels/issues"
|
0
src/pyknuddels/__init__.py
Normal file
0
src/pyknuddels/__init__.py
Normal file
0
src/pyknuddels/classes/__init__.py
Normal file
0
src/pyknuddels/classes/__init__.py
Normal file
147
src/pyknuddels/classes/api.py
Normal file
147
src/pyknuddels/classes/api.py
Normal file
File diff suppressed because one or more lines are too long
86
src/pyknuddels/classes/messages.py
Normal file
86
src/pyknuddels/classes/messages.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
from .users import User
|
||||
|
||||
from typing import List, Optional
|
||||
|
||||
|
||||
class MessageContent:
|
||||
text: str
|
||||
|
||||
def __init__(self, formatted_text: dict) -> None:
|
||||
self.formatted_text = formatted_text
|
||||
|
||||
def get_text(self) -> str:
|
||||
return self.formatted_text["text"]["text"]
|
||||
|
||||
def get_formatted_text(self) -> str:
|
||||
return self.formatted_text
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
obj = cls(data["formattedText"])
|
||||
return obj
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<MessageContent formatted_text={self.formatted_text}>"
|
||||
|
||||
|
||||
class Message:
|
||||
sender: User
|
||||
content: dict
|
||||
|
||||
def __init__(self, sender: User, content: MessageContent) -> None:
|
||||
self.sender = sender
|
||||
self.content = content
|
||||
|
||||
def get_sender(self) -> User:
|
||||
return self.sender
|
||||
|
||||
def get_content(self) -> dict:
|
||||
return self.content
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
obj = cls(User.from_dict(data["sender"]), MessageContent.from_dict(data["content"]))
|
||||
|
||||
return obj
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Message sender={self.sender} content={self.content}>"
|
||||
|
||||
class Conversation:
|
||||
id: int
|
||||
visibility: str
|
||||
messages: List[Message] = []
|
||||
otherParticipants: List[User] = []
|
||||
|
||||
def __init__(
|
||||
self, id: int, messages: List[Message], other_participants: List[User]
|
||||
) -> None:
|
||||
self.id = id
|
||||
self.messages = messages
|
||||
self.other_participants = other_participants
|
||||
|
||||
def get_messages(self) -> List[Message]:
|
||||
return self.messages
|
||||
|
||||
def get_other_participants(self) -> List[User]:
|
||||
return self.other_participants
|
||||
|
||||
def get_other_participant(self) -> User:
|
||||
return self.other_participants[0]
|
||||
|
||||
def get_message_count(self) -> int:
|
||||
return len(self.messages)
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
obj = cls(data["id"], [], [])
|
||||
obj.visibility = data["visibility"]
|
||||
|
||||
for participant in data["otherParticipants"]:
|
||||
obj.other_participants.append(User.from_dict(participant))
|
||||
|
||||
return obj
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"<Conversation id={self.id} visibility={self.visibility} other_participants={self.other_participants}>"
|
40
src/pyknuddels/classes/users.py
Normal file
40
src/pyknuddels/classes/users.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from typing import Optional
|
||||
|
||||
class User:
|
||||
id: int
|
||||
nick: str
|
||||
isOnline: bool
|
||||
canSendImages: bool
|
||||
menteeStatus: str
|
||||
age: int
|
||||
albumPhotosUrl: str
|
||||
canReceiveMessages: bool
|
||||
city: str
|
||||
distance: Optional[int]
|
||||
gender: str
|
||||
currentOnlineChannelName: str
|
||||
latestOnlineChannelName: str
|
||||
lastOnlineTime: int
|
||||
profilePicture: str
|
||||
readMe: dict
|
||||
relationshipStatus: str
|
||||
sexualOrientation: str
|
||||
onlineMinutes: int
|
||||
isAppBot: bool
|
||||
isLockedByAutomaticComplaint: bool
|
||||
automaticComplaintCommand: str
|
||||
isReportable: bool
|
||||
interest: Optional[str]
|
||||
latestClient: Optional[str] #?
|
||||
authenticityClassification: str
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, data: dict):
|
||||
obj = cls()
|
||||
for key, value in data.items():
|
||||
setattr(obj, key, value)
|
||||
|
||||
return obj
|
||||
|
||||
def __repr__(self):
|
||||
return f"<User id={self.id} nick={self.nick}>"
|
22
test.py
Normal file
22
test.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
import logging
|
||||
import os
|
||||
|
||||
logging.basicConfig(
|
||||
format="[%(asctime)s] [%(levelname)s] %(message)s",
|
||||
datefmt="%d.%m.%Y %H:%M:%S",
|
||||
level=logging.INFO
|
||||
)
|
||||
|
||||
from pyknuddels.classes.api import Knuddels
|
||||
from pyknuddels.classes.messages import Conversation, Message
|
||||
|
||||
knuddels = Knuddels(os.environ["KN_USER"], os.environ["KN_PASSWORD"])
|
||||
|
||||
knuddels.login()
|
||||
|
||||
conversations = knuddels.messenger_overview(1)
|
||||
|
||||
for conversation in conversations:
|
||||
obj = knuddels.get_conversation(conversation["id"])
|
||||
obj = Conversation.from_dict(conversation)
|
||||
print(obj)
|
Loading…
Reference in a new issue