refactored to be simpler
This commit is contained in:
parent
75d3d5f1aa
commit
61536240f3
@ -4,73 +4,4 @@ import logging
|
|||||||
|
|
||||||
import toml
|
import toml
|
||||||
|
|
||||||
from .utils import Paths, PROGRAM_NAME
|
from .utils import config
|
||||||
from .feeds.mastodon_feed import MastodonFeed
|
|
||||||
from .feeds.twitter_feed import TwitterFeed
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
NAME_TO_FEED = {
|
|
||||||
"mastodon": MastodonFeed,
|
|
||||||
"twitter": TwitterFeed,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class PublishMeetups:
|
|
||||||
def __init__(self):
|
|
||||||
self.config_file: Path = Path(Paths.CONFIG_PATH, "publish-meetups.toml")
|
|
||||||
print(self.config_file)
|
|
||||||
self.config = {}
|
|
||||||
|
|
||||||
self.config = {
|
|
||||||
"active_feeds": [
|
|
||||||
"mastodon",
|
|
||||||
"twitter",
|
|
||||||
],
|
|
||||||
"mastodon": {},
|
|
||||||
"twitter": {},
|
|
||||||
}
|
|
||||||
|
|
||||||
self.logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
if self.config_file.exists():
|
|
||||||
with self.config_file.open("r", encoding="utf-8") as f:
|
|
||||||
self.config.update(toml.load(f))
|
|
||||||
|
|
||||||
return self
|
|
||||||
|
|
||||||
def run(self):
|
|
||||||
for feed in self.config['active_feeds']:
|
|
||||||
self.run_feed(feed)
|
|
||||||
|
|
||||||
def run_feed(self, feed: str):
|
|
||||||
if feed not in NAME_TO_FEED:
|
|
||||||
self.logger.error(f"Feed {feed} is not implemented.")
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
feed_config = self.config.get(feed, {})
|
|
||||||
feed_class = NAME_TO_FEED[feed]
|
|
||||||
|
|
||||||
if not len(feed_config):
|
|
||||||
feed_config.update(feed_class.prompt_auth(feed_config))
|
|
||||||
self.config[feed] = feed_config
|
|
||||||
|
|
||||||
with self.config_file.open("w", encoding="utf-8") as f:
|
|
||||||
toml.dump(self.config, f)
|
|
||||||
|
|
||||||
|
|
||||||
with feed_class(**feed_config, config=feed_config) as feed_instance:
|
|
||||||
self.config[feed].update(feed_instance.config)
|
|
||||||
|
|
||||||
with self.config_file.open("w", encoding="utf-8") as f:
|
|
||||||
toml.dump(self.config, f)
|
|
||||||
|
|
||||||
feed_instance.run()
|
|
||||||
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
||||||
print("Exiting")
|
|
||||||
with self.config_file.open("w", encoding="utf-8") as f:
|
|
||||||
toml.dump(self.config, f)
|
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
from . import PublishMeetups
|
from .routines.development import Development
|
||||||
|
|
||||||
|
|
||||||
def cli():
|
def cli():
|
||||||
with PublishMeetups() as p:
|
Development().run()
|
||||||
p.run()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
@ -1,23 +1,11 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from .interface import Feed
|
||||||
|
from .mastodon_feed import MastodonFeed
|
||||||
|
from .twitter_feed import TwitterFeed
|
||||||
|
|
||||||
class Feed:
|
|
||||||
@classmethod
|
|
||||||
def prompt_auth(cls, existing_config: dict) -> dict:
|
|
||||||
return existing_config
|
|
||||||
|
|
||||||
def __init__(self, config: dict = None, **kwargs):
|
|
||||||
self.logger = logging.getLogger(self.__class__.__name__)
|
|
||||||
self.config = config or {}
|
|
||||||
|
|
||||||
def __enter__(self):
|
|
||||||
return self
|
|
||||||
|
|
||||||
def post(self, message: str, **kwargs):
|
|
||||||
print(f"Posting {message}")
|
|
||||||
|
|
||||||
def run(self):
|
__all__ = ["Feed", "MastodonFeed", "TwitterFeed"]
|
||||||
self.post("Hello, World!")
|
|
||||||
|
|
||||||
def __exit__(self, exc_type, exc_value, traceback):
|
|
||||||
pass
|
|
||||||
|
17
publish_meetups/feeds/interface.py
Normal file
17
publish_meetups/feeds/interface.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
|
class Feed:
|
||||||
|
__config_name__ = "feed"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prompt_auth(cls, existing_config: dict) -> dict:
|
||||||
|
return existing_config
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.logger = logging.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def post(self, message: str):
|
||||||
|
self.logger.info(f"Posting message to {self.__class__.__name__}: {message}")
|
||||||
|
pass
|
@ -3,14 +3,15 @@ from pathlib import Path
|
|||||||
from mastodon import Mastodon
|
from mastodon import Mastodon
|
||||||
|
|
||||||
from . import Feed
|
from . import Feed
|
||||||
from ..utils import Paths, PROGRAM_NAME, prompt
|
from ..utils import PROGRAM_NAME, prompt, config
|
||||||
|
|
||||||
|
|
||||||
class MastodonFeed(Feed):
|
class MastodonFeed(Feed):
|
||||||
CLIENTCRED_PATH: Path = Paths.CONFIG_PATH.joinpath("mastodon_clientcred.secret")
|
__config_name__ = "mastodon"
|
||||||
|
CLIENTCRED_PATH: Path = config.CONFIG_PATH.joinpath("mastodon_clientcred.secret")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prompt_auth(cls, existing_config: dict) -> dict:
|
def prompt_auth(cls) -> dict:
|
||||||
"""
|
"""
|
||||||
mastodon needs:
|
mastodon needs:
|
||||||
- the instance used
|
- the instance used
|
||||||
@ -18,7 +19,6 @@ class MastodonFeed(Feed):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return {
|
return {
|
||||||
**existing_config,
|
|
||||||
"api_base_url": prompt.for_string("The instance you use", "https://mastodon.social"),
|
"api_base_url": prompt.for_string("The instance you use", "https://mastodon.social"),
|
||||||
"access_token": prompt.for_password("Access token"),
|
"access_token": prompt.for_password("Access token"),
|
||||||
}
|
}
|
||||||
@ -30,11 +30,9 @@ class MastodonFeed(Feed):
|
|||||||
access_token=access_token,
|
access_token=access_token,
|
||||||
)
|
)
|
||||||
|
|
||||||
super().__init__(**kwargs)
|
super().__init__()
|
||||||
|
|
||||||
def post(self, message: str):
|
def post(self, message: str):
|
||||||
kwargs = locals().copy()
|
|
||||||
|
|
||||||
self.mastodon.toot(message)
|
self.mastodon.toot(message)
|
||||||
|
|
||||||
Feed.post(**kwargs)
|
super().post(message)
|
||||||
|
@ -4,14 +4,14 @@ from twikit import Client
|
|||||||
from twikit.errors import Forbidden, Unauthorized
|
from twikit.errors import Forbidden, Unauthorized
|
||||||
|
|
||||||
from . import Feed
|
from . import Feed
|
||||||
from ..utils import Paths, PROGRAM_NAME, prompt
|
from ..utils import config, PROGRAM_NAME, prompt
|
||||||
|
|
||||||
|
|
||||||
class TwitterFeed(Feed):
|
class TwitterFeed(Feed):
|
||||||
CLIENTCRED_PATH: Path = Paths.CONFIG_PATH.joinpath("mastodon_clientcred.secret")
|
__config_name__ = "twitter"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def prompt_auth(cls, existing_config: dict) -> dict:
|
def prompt_auth(cls) -> dict:
|
||||||
"""
|
"""
|
||||||
client.login(
|
client.login(
|
||||||
auth_info_1=USERNAME ,
|
auth_info_1=USERNAME ,
|
||||||
@ -28,13 +28,12 @@ class TwitterFeed(Feed):
|
|||||||
|
|
||||||
# https://github.com/d60/twikit
|
# https://github.com/d60/twikit
|
||||||
def __init__(self, auth_info_1: str, auth_info_2: str, password: str, cookies: dict = None, **kwargs):
|
def __init__(self, auth_info_1: str, auth_info_2: str, password: str, cookies: dict = None, **kwargs):
|
||||||
super().__init__(**kwargs)
|
super().__init__()
|
||||||
|
|
||||||
self.client = Client('en-US')
|
self.client = Client('en-US')
|
||||||
|
|
||||||
logged_in = False
|
logged_in = False
|
||||||
|
|
||||||
cookies = cookies or {}
|
|
||||||
if cookies is not None:
|
if cookies is not None:
|
||||||
self.client.http.client.cookies = cookies
|
self.client.http.client.cookies = cookies
|
||||||
try:
|
try:
|
||||||
@ -53,16 +52,14 @@ class TwitterFeed(Feed):
|
|||||||
)
|
)
|
||||||
logged_in = True
|
logged_in = True
|
||||||
|
|
||||||
self.config['cookies'] = dict(self.client.http.client.cookies)
|
config.set_field(self.__config_name__, {
|
||||||
print(self.client.user_id())
|
'cookies': dict(self.client.http.client.cookies)
|
||||||
print(self.client._base_headers)
|
}, update_dict=True)
|
||||||
|
|
||||||
|
|
||||||
def post(self, message: str):
|
def post(self, message: str):
|
||||||
kwargs = locals().copy()
|
|
||||||
|
|
||||||
self.client.create_tweet(
|
self.client.create_tweet(
|
||||||
text=message,
|
text=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
Feed.post(**kwargs)
|
super().post(message)
|
||||||
|
41
publish_meetups/routines/__init__.py
Normal file
41
publish_meetups/routines/__init__.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
from typing import Generator, Type, Dict
|
||||||
|
|
||||||
|
from ..utils import config, error
|
||||||
|
from ..feeds import *
|
||||||
|
|
||||||
|
|
||||||
|
NAME_TO_FEED: Dict[str, Type[Feed]] = {
|
||||||
|
"mastodon": MastodonFeed,
|
||||||
|
"twitter": TwitterFeed,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Routine:
|
||||||
|
@staticmethod
|
||||||
|
def iter_feeds() -> Generator[Type[Feed], None, None]:
|
||||||
|
for feed in config.get_field("active_feeds", []):
|
||||||
|
if feed not in NAME_TO_FEED:
|
||||||
|
raise ValueError(f"Feed {feed} is not implemented.")
|
||||||
|
|
||||||
|
yield NAME_TO_FEED[feed]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init_feed(feed: Type[Feed]) -> Feed:
|
||||||
|
feed_config = config.get_field(feed.__config_name__, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
feed_instance = feed(**feed_config)
|
||||||
|
except (TypeError, error.InvalidCredential) as e:
|
||||||
|
print(feed_config)
|
||||||
|
raise e
|
||||||
|
config.set_field(feed.__name__, feed.prompt_auth(), update_dict=True)
|
||||||
|
feed_config = config.get_field(feed.__config_name__, {})
|
||||||
|
|
||||||
|
try:
|
||||||
|
return feed(**feed_config)
|
||||||
|
except (TypeError, error.InvalidCredential):
|
||||||
|
raise error.InvalidCredential(f"Invalid credentials for {feed.__name__}.")
|
||||||
|
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
pass
|
10
publish_meetups/routines/development.py
Normal file
10
publish_meetups/routines/development.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from . import Routine
|
||||||
|
from ..feeds import Feed
|
||||||
|
|
||||||
|
|
||||||
|
class Development(Routine):
|
||||||
|
def run(self):
|
||||||
|
for feed_class in self.iter_feeds():
|
||||||
|
feed: Feed = self.init_feed(feed_class)
|
||||||
|
|
||||||
|
feed.post(message="This worked second try!")
|
@ -1,19 +1,9 @@
|
|||||||
from pathlib import Path
|
import logging
|
||||||
|
|
||||||
import platformdirs
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
PROGRAM_NAME: str = "publish-meetups"
|
PROGRAM_NAME: str = "publish-meetups"
|
||||||
|
|
||||||
|
__all__ = ["prompt", "CONFIG_PATH", "PROGRAM_NAME", "errors", "config"]
|
||||||
class Paths:
|
|
||||||
CONFIG_PATH: Path = Path(platformdirs.user_config_path(appname=PROGRAM_NAME))
|
|
||||||
|
|
||||||
|
|
||||||
Paths.CONFIG_PATH.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["prompt", "CONFIG_PATH", "PROGRAM_NAME", "errors"]
|
|
||||||
|
|
||||||
|
|
||||||
|
57
publish_meetups/utils/config.py
Normal file
57
publish_meetups/utils/config.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
import toml
|
||||||
|
import platformdirs
|
||||||
|
|
||||||
|
from . import PROGRAM_NAME
|
||||||
|
|
||||||
|
logger = logging.getLogger("config")
|
||||||
|
_config: dict = {
|
||||||
|
"active_feeds": [
|
||||||
|
"mastodon",
|
||||||
|
"twitter",
|
||||||
|
],
|
||||||
|
"mastodon": {},
|
||||||
|
"twitter": {},
|
||||||
|
"lemmy": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CONFIG_PATH = platformdirs.user_config_path(appname=PROGRAM_NAME)
|
||||||
|
CONFIG_PATH.mkdir(parents=True, exist_ok=True)
|
||||||
|
CONFIG_FILE = CONFIG_PATH / f"{PROGRAM_NAME}.toml"
|
||||||
|
|
||||||
|
|
||||||
|
logger.info(f"Config file: {CONFIG_FILE}")
|
||||||
|
|
||||||
|
|
||||||
|
def read():
|
||||||
|
global _config, CONFIG_FILE
|
||||||
|
if CONFIG_FILE.exists():
|
||||||
|
with CONFIG_FILE.open("r", encoding="utf-8") as f:
|
||||||
|
_config.update(toml.load(f))
|
||||||
|
|
||||||
|
|
||||||
|
def write():
|
||||||
|
global _config, CONFIG_FILE
|
||||||
|
with CONFIG_FILE.open("w", encoding="utf-8") as f:
|
||||||
|
toml.dump(_config, f)
|
||||||
|
|
||||||
|
|
||||||
|
def get_field(__name: str, default=None):
|
||||||
|
global _config
|
||||||
|
return _config.get(__name, default)
|
||||||
|
|
||||||
|
|
||||||
|
def set_field(__name: str, __value, update_dict=False):
|
||||||
|
global _config
|
||||||
|
|
||||||
|
if update_dict and isinstance(__value, dict) and isinstance(_config.get(__name), dict):
|
||||||
|
_config[__name].update(__value)
|
||||||
|
else:
|
||||||
|
_config[__name] = __value
|
||||||
|
|
||||||
|
write()
|
||||||
|
|
||||||
|
|
||||||
|
read()
|
Loading…
Reference in New Issue
Block a user