telepress 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 zoidberg-xgd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: telepress
3
+ Version: 0.1.0
4
+ Summary: Publish Markdown, images and zip archives to Telegraph
5
+ Home-page: https://github.com/zoidberg-xgd/telepress
6
+ Author: zoidberg-xgd
7
+ Author-email:
8
+ Project-URL: Bug Reports, https://github.com/zoidberg-xgd/telepress/issues
9
+ Project-URL: Source, https://github.com/zoidberg-xgd/telepress
10
+ Keywords: telegraph,markdown,publishing,gallery
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.7
16
+ Classifier: Programming Language :: Python :: 3.8
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Requires-Python: >=3.7
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: telegraph
25
+ Requires-Dist: markdown
26
+ Requires-Dist: requests
27
+ Provides-Extra: api
28
+ Requires-Dist: fastapi; extra == "api"
29
+ Requires-Dist: uvicorn; extra == "api"
30
+ Requires-Dist: python-multipart; extra == "api"
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest; extra == "dev"
33
+ Requires-Dist: pytest-cov; extra == "dev"
34
+ Requires-Dist: httpx; extra == "dev"
35
+ Dynamic: author
36
+ Dynamic: classifier
37
+ Dynamic: description
38
+ Dynamic: description-content-type
39
+ Dynamic: home-page
40
+ Dynamic: keywords
41
+ Dynamic: license-file
42
+ Dynamic: project-url
43
+ Dynamic: provides-extra
44
+ Dynamic: requires-dist
45
+ Dynamic: requires-python
46
+ Dynamic: summary
47
+
48
+ # TelePress
49
+
50
+ [中文文档](README_CN.md)
51
+
52
+ Publish Markdown, images and zip archives to [Telegraph](https://telegra.ph). Handles large files by auto-splitting into multiple linked pages.
53
+
54
+ ## Install
55
+
56
+ ```bash
57
+ pip install telepress
58
+
59
+ # with REST API
60
+ pip install telepress[api]
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ```python
66
+ from telepress import publish, publish_text
67
+
68
+ url = publish("article.md")
69
+ url = publish_text("# Hello\n\nWorld!", title="Test")
70
+ ```
71
+
72
+ CLI:
73
+ ```bash
74
+ telepress article.md --title "My Post"
75
+ telepress photos.zip --title "Album"
76
+ ```
77
+
78
+ REST API:
79
+ ```bash
80
+ telepress-server --port 8000
81
+
82
+ curl -X POST localhost:8000/publish/text \
83
+ -H "Content-Type: application/json" \
84
+ -d '{"content": "# Title\n\nBody", "title": "Test"}'
85
+ ```
86
+
87
+ ## How it works
88
+
89
+ Text files are converted to Telegraph format (Markdown supported). Large content is split at ~40KB boundaries into multiple pages with prev/next navigation.
90
+
91
+ Zip files are treated as image galleries. Images are sorted naturally (1, 2, 10 not 1, 10, 2) and paginated at 100 per page.
92
+
93
+ Token is auto-created on first run and saved to `~/.telegraph_token`.
94
+
95
+ ## Limits
96
+
97
+ - 100MB max file size
98
+ - 100 pages max (~4M chars text, or 5000 images)
99
+ - 5MB per image (Telegraph limit)
100
+
101
+ Supported: `.txt` `.md` `.markdown` `.rst` `.jpg` `.png` `.gif` `.webp` `.zip`
102
+
103
+ Not supported: PDF, DOCX (convert first)
104
+
105
+ ## Project structure
106
+
107
+ ```
108
+ telepress/
109
+ ├── core.py # TelegraphPublisher
110
+ ├── auth.py # token management
111
+ ├── converter.py # markdown to telegraph nodes
112
+ ├── uploader.py # image upload with retry
113
+ ├── server.py # FastAPI service
114
+ └── cli.py # command line
115
+ ```
116
+
117
+ ## Error handling
118
+
119
+ ```python
120
+ from telepress import publish, ValidationError, TelePressError
121
+
122
+ try:
123
+ url = publish("file.md")
124
+ except ValidationError as e:
125
+ # bad input: wrong format, too large, etc
126
+ print(e)
127
+ except TelePressError as e:
128
+ # other errors: upload failed, auth failed, etc
129
+ print(e)
130
+ ```
131
+
132
+ ## Integration
133
+
134
+ ```python
135
+ # Flask
136
+ @app.route('/publish', methods=['POST'])
137
+ def api_publish():
138
+ url = publish_text(request.json['content'], title=request.json['title'])
139
+ return {'url': url}
140
+
141
+ # async
142
+ async def async_publish(content, title):
143
+ return await asyncio.to_thread(publish_text, content, title)
144
+ ```
145
+
146
+ ## Dev
147
+
148
+ ```bash
149
+ git clone https://github.com/zoidberg-xgd/telepress
150
+ cd telepress && pip install -e .[dev]
151
+ pytest tests/ -v
152
+ ```
153
+
154
+ ## License
155
+
156
+ MIT
@@ -0,0 +1,109 @@
1
+ # TelePress
2
+
3
+ [中文文档](README_CN.md)
4
+
5
+ Publish Markdown, images and zip archives to [Telegraph](https://telegra.ph). Handles large files by auto-splitting into multiple linked pages.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install telepress
11
+
12
+ # with REST API
13
+ pip install telepress[api]
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ```python
19
+ from telepress import publish, publish_text
20
+
21
+ url = publish("article.md")
22
+ url = publish_text("# Hello\n\nWorld!", title="Test")
23
+ ```
24
+
25
+ CLI:
26
+ ```bash
27
+ telepress article.md --title "My Post"
28
+ telepress photos.zip --title "Album"
29
+ ```
30
+
31
+ REST API:
32
+ ```bash
33
+ telepress-server --port 8000
34
+
35
+ curl -X POST localhost:8000/publish/text \
36
+ -H "Content-Type: application/json" \
37
+ -d '{"content": "# Title\n\nBody", "title": "Test"}'
38
+ ```
39
+
40
+ ## How it works
41
+
42
+ Text files are converted to Telegraph format (Markdown supported). Large content is split at ~40KB boundaries into multiple pages with prev/next navigation.
43
+
44
+ Zip files are treated as image galleries. Images are sorted naturally (1, 2, 10 not 1, 10, 2) and paginated at 100 per page.
45
+
46
+ Token is auto-created on first run and saved to `~/.telegraph_token`.
47
+
48
+ ## Limits
49
+
50
+ - 100MB max file size
51
+ - 100 pages max (~4M chars text, or 5000 images)
52
+ - 5MB per image (Telegraph limit)
53
+
54
+ Supported: `.txt` `.md` `.markdown` `.rst` `.jpg` `.png` `.gif` `.webp` `.zip`
55
+
56
+ Not supported: PDF, DOCX (convert first)
57
+
58
+ ## Project structure
59
+
60
+ ```
61
+ telepress/
62
+ ├── core.py # TelegraphPublisher
63
+ ├── auth.py # token management
64
+ ├── converter.py # markdown to telegraph nodes
65
+ ├── uploader.py # image upload with retry
66
+ ├── server.py # FastAPI service
67
+ └── cli.py # command line
68
+ ```
69
+
70
+ ## Error handling
71
+
72
+ ```python
73
+ from telepress import publish, ValidationError, TelePressError
74
+
75
+ try:
76
+ url = publish("file.md")
77
+ except ValidationError as e:
78
+ # bad input: wrong format, too large, etc
79
+ print(e)
80
+ except TelePressError as e:
81
+ # other errors: upload failed, auth failed, etc
82
+ print(e)
83
+ ```
84
+
85
+ ## Integration
86
+
87
+ ```python
88
+ # Flask
89
+ @app.route('/publish', methods=['POST'])
90
+ def api_publish():
91
+ url = publish_text(request.json['content'], title=request.json['title'])
92
+ return {'url': url}
93
+
94
+ # async
95
+ async def async_publish(content, title):
96
+ return await asyncio.to_thread(publish_text, content, title)
97
+ ```
98
+
99
+ ## Dev
100
+
101
+ ```bash
102
+ git clone https://github.com/zoidberg-xgd/telepress
103
+ cd telepress && pip install -e .[dev]
104
+ pytest tests/ -v
105
+ ```
106
+
107
+ ## License
108
+
109
+ MIT
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,55 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="telepress",
5
+ version="0.1.0",
6
+ package_dir={"": "src"},
7
+ packages=find_packages(where="src"),
8
+ install_requires=[
9
+ "telegraph",
10
+ "markdown",
11
+ "requests"
12
+ ],
13
+ extras_require={
14
+ "api": [
15
+ "fastapi",
16
+ "uvicorn",
17
+ "python-multipart"
18
+ ],
19
+ "dev": [
20
+ "pytest",
21
+ "pytest-cov",
22
+ "httpx" # For FastAPI TestClient
23
+ ]
24
+ },
25
+ entry_points={
26
+ 'console_scripts': [
27
+ 'telepress=telepress.cli:main',
28
+ 'telepress-server=telepress.server:main',
29
+ ],
30
+ },
31
+ author="zoidberg-xgd",
32
+ author_email="",
33
+ description="Publish Markdown, images and zip archives to Telegraph",
34
+ long_description=open("README.md").read(),
35
+ long_description_content_type="text/markdown",
36
+ python_requires=">=3.7",
37
+ classifiers=[
38
+ "Development Status :: 4 - Beta",
39
+ "Intended Audience :: Developers",
40
+ "License :: OSI Approved :: MIT License",
41
+ "Programming Language :: Python :: 3",
42
+ "Programming Language :: Python :: 3.7",
43
+ "Programming Language :: Python :: 3.8",
44
+ "Programming Language :: Python :: 3.9",
45
+ "Programming Language :: Python :: 3.10",
46
+ "Programming Language :: Python :: 3.11",
47
+ "Programming Language :: Python :: 3.12",
48
+ ],
49
+ url="https://github.com/zoidberg-xgd/telepress",
50
+ project_urls={
51
+ "Bug Reports": "https://github.com/zoidberg-xgd/telepress/issues",
52
+ "Source": "https://github.com/zoidberg-xgd/telepress",
53
+ },
54
+ keywords=["telegraph", "markdown", "publishing", "gallery"],
55
+ )
@@ -0,0 +1,116 @@
1
+ """
2
+ TelePress - Publish content to Telegraph easily.
3
+
4
+ Basic usage:
5
+ >>> from telepress import publish, TelegraphPublisher
6
+ >>>
7
+ >>> # Quick publish (one-liner)
8
+ >>> url = publish("article.md", title="My Article")
9
+ >>>
10
+ >>> # Or use the class for more control
11
+ >>> publisher = TelegraphPublisher()
12
+ >>> url = publisher.publish("article.md")
13
+ >>> url = publisher.publish_text("# Hello\n\nWorld!", title="Test")
14
+ """
15
+
16
+ from .core import TelegraphPublisher
17
+ from .exceptions import (
18
+ TelePressError,
19
+ ValidationError,
20
+ UploadError,
21
+ AuthenticationError,
22
+ SecurityError,
23
+ DependencyError,
24
+ ConversionError
25
+ )
26
+ from .utils import (
27
+ MAX_FILE_SIZE,
28
+ MAX_PAGES,
29
+ MAX_TOTAL_IMAGES,
30
+ MAX_IMAGES_PER_PAGE,
31
+ ALLOWED_TEXT_EXTENSIONS,
32
+ ALLOWED_IMAGE_EXTENSIONS,
33
+ ALLOWED_ARCHIVE_EXTENSIONS
34
+ )
35
+
36
+ __version__ = "0.1.0"
37
+ __all__ = [
38
+ # Main class
39
+ 'TelegraphPublisher',
40
+
41
+ # Convenience function
42
+ 'publish',
43
+ 'publish_text',
44
+
45
+ # Exceptions
46
+ 'TelePressError',
47
+ 'ValidationError',
48
+ 'UploadError',
49
+ 'AuthenticationError',
50
+ 'SecurityError',
51
+ 'DependencyError',
52
+ 'ConversionError',
53
+
54
+ # Constants
55
+ 'MAX_FILE_SIZE',
56
+ 'MAX_PAGES',
57
+ 'MAX_TOTAL_IMAGES',
58
+ 'MAX_IMAGES_PER_PAGE',
59
+ 'ALLOWED_TEXT_EXTENSIONS',
60
+ 'ALLOWED_IMAGE_EXTENSIONS',
61
+ 'ALLOWED_ARCHIVE_EXTENSIONS',
62
+ ]
63
+
64
+ # Singleton publisher for convenience functions
65
+ _default_publisher = None
66
+
67
+ def _get_publisher(token=None):
68
+ """Get or create default publisher instance."""
69
+ global _default_publisher
70
+ if token:
71
+ return TelegraphPublisher(token=token)
72
+ if _default_publisher is None:
73
+ _default_publisher = TelegraphPublisher()
74
+ return _default_publisher
75
+
76
+
77
+ def publish(file_path: str, title: str = None, token: str = None) -> str:
78
+ """
79
+ Convenience function to publish a file to Telegraph.
80
+
81
+ Args:
82
+ file_path: Path to file (.md, .txt, .jpg, .png, .zip, etc.)
83
+ title: Optional title (defaults to filename)
84
+ token: Optional Telegraph token (uses cached token if not provided)
85
+
86
+ Returns:
87
+ str: URL of the published Telegraph page
88
+
89
+ Example:
90
+ >>> from telepress import publish
91
+ >>> url = publish("article.md", title="My Article")
92
+ >>> print(url)
93
+ https://telegra.ph/My-Article-12-07
94
+ """
95
+ return _get_publisher(token).publish(file_path, title=title)
96
+
97
+
98
+ def publish_text(content: str, title: str, token: str = None) -> str:
99
+ """
100
+ Convenience function to publish text content directly to Telegraph.
101
+
102
+ Args:
103
+ content: Markdown or plain text content
104
+ title: Page title (required)
105
+ token: Optional Telegraph token
106
+
107
+ Returns:
108
+ str: URL of the published Telegraph page
109
+
110
+ Example:
111
+ >>> from telepress import publish_text
112
+ >>> url = publish_text("# Hello\n\nThis is my article.", title="Hello World")
113
+ >>> print(url)
114
+ https://telegra.ph/Hello-World-12-07
115
+ """
116
+ return _get_publisher(token).publish_text(content, title=title)
@@ -0,0 +1,57 @@
1
+ import os
2
+ from typing import Optional
3
+ from .exceptions import DependencyError, AuthenticationError
4
+
5
+ try:
6
+ from telegraph import Telegraph
7
+ except ImportError:
8
+ Telegraph = None
9
+
10
+ DEFAULT_TOKEN_FILE = os.path.expanduser("~/.telegraph_token")
11
+
12
+ class TelegraphAuth:
13
+ def __init__(self, token_file: str = DEFAULT_TOKEN_FILE):
14
+ if Telegraph is None:
15
+ raise DependencyError("telegraph library is required")
16
+ self.token_file = token_file
17
+
18
+ def get_client(self, token: Optional[str] = None, short_name: str = "TelegraphClient") -> Telegraph:
19
+ """
20
+ Returns an authenticated Telegraph client.
21
+ Priorities:
22
+ 1. Explicit token argument
23
+ 2. Stored token in file
24
+ 3. Create new account and store token
25
+ """
26
+ # 1. Explicit token
27
+ if token:
28
+ return Telegraph(access_token=token)
29
+
30
+ # 2. Stored token
31
+ if os.path.exists(self.token_file):
32
+ try:
33
+ with open(self.token_file, 'r') as f:
34
+ stored_token = f.read().strip()
35
+ client = Telegraph(access_token=stored_token)
36
+ # Verify token
37
+ client.get_account_info(['short_name'])
38
+ return client
39
+ except Exception:
40
+ # Log or just proceed to create new
41
+ pass
42
+
43
+ # 3. Create new
44
+ try:
45
+ client = Telegraph()
46
+ response = client.create_account(short_name=short_name)
47
+ new_token = response['access_token']
48
+
49
+ # Ensure directory exists
50
+ os.makedirs(os.path.dirname(self.token_file), exist_ok=True)
51
+
52
+ with open(self.token_file, 'w') as f:
53
+ f.write(new_token)
54
+
55
+ return Telegraph(access_token=new_token)
56
+ except Exception as e:
57
+ raise AuthenticationError(f"Failed to create new Telegraph account: {e}")
@@ -0,0 +1,26 @@
1
+ import argparse
2
+ import sys
3
+ from .core import TelegraphPublisher
4
+ from .exceptions import TelePressError
5
+
6
+ def main():
7
+ parser = argparse.ArgumentParser(description="TelePress: Publish files (txt, md, images, zip) to Telegraph.")
8
+ parser.add_argument("file", help="Path to the file to convert")
9
+ parser.add_argument("--title", help="Custom title for the page", default=None)
10
+ parser.add_argument("--token", help="Telegraph access token (optional)", default=None)
11
+
12
+ args = parser.parse_args()
13
+
14
+ try:
15
+ publisher = TelegraphPublisher(token=args.token)
16
+ url = publisher.publish(args.file, title=args.title)
17
+ print(f"\n✅ Success! Page created: {url}")
18
+ except TelePressError as e:
19
+ print(f"\n❌ Error: {e}")
20
+ sys.exit(1)
21
+ except Exception as e:
22
+ print(f"\n❌ Unexpected Error: {e}")
23
+ sys.exit(1)
24
+
25
+ if __name__ == "__main__":
26
+ main()
@@ -0,0 +1,36 @@
1
+ import re
2
+ from typing import List, Dict, Union
3
+ from .utils import sanitize_nodes
4
+ from .exceptions import DependencyError
5
+
6
+ try:
7
+ import markdown
8
+ from telegraph.utils import html_to_nodes
9
+ except ImportError:
10
+ markdown = None
11
+ html_to_nodes = None
12
+
13
+ class MarkdownConverter:
14
+ def __init__(self):
15
+ if markdown is None:
16
+ raise DependencyError("markdown library is required")
17
+
18
+ def convert(self, md_content: str) -> List[Dict]:
19
+ """Converts Markdown content to Telegraph DOM nodes."""
20
+ html_content = markdown.markdown(md_content)
21
+
22
+ # Pre-process HTML string for headers
23
+ # Telegraph doesn't support h1/h2
24
+ html_content = re.sub(r'<h1', '<h3', html_content)
25
+ html_content = re.sub(r'</h1>', '</h3>', html_content)
26
+ html_content = re.sub(r'<h2', '<h4', html_content)
27
+ html_content = re.sub(r'</h2>', '</h4>', html_content)
28
+ html_content = re.sub(r'<h[56]', '<h4', html_content)
29
+ html_content = re.sub(r'</h[56]>', '</h4>', html_content)
30
+
31
+ if html_to_nodes:
32
+ nodes = html_to_nodes(html_content)
33
+ return sanitize_nodes(nodes)
34
+ else:
35
+ # Fallback (though utils should be present if telegraph is installed)
36
+ return [{'tag': 'p', 'children': [md_content]}]