instapaper-scraper 1.1.0rc1__tar.gz → 1.2.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.
Files changed (26) hide show
  1. {instapaper_scraper-1.1.0rc1/src/instapaper_scraper.egg-info → instapaper_scraper-1.2.0}/PKG-INFO +156 -65
  2. instapaper_scraper-1.2.0/README.md +336 -0
  3. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/pyproject.toml +24 -8
  4. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/api.py +75 -20
  5. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/auth.py +5 -4
  6. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/cli.py +36 -11
  7. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/constants.py +1 -0
  8. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/output.py +69 -17
  9. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0/src/instapaper_scraper.egg-info}/PKG-INFO +156 -65
  10. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper.egg-info/SOURCES.txt +1 -0
  11. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper.egg-info/requires.txt +4 -2
  12. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_api.py +165 -9
  13. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_auth.py +44 -0
  14. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_cli.py +74 -30
  15. instapaper_scraper-1.2.0/tests/test_cli_config_flags.py +367 -0
  16. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_output.py +80 -16
  17. instapaper_scraper-1.1.0rc1/README.md +0 -247
  18. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/LICENSE +0 -0
  19. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/setup.cfg +0 -0
  20. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/__init__.py +0 -0
  21. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper/exceptions.py +0 -0
  22. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper.egg-info/dependency_links.txt +0 -0
  23. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper.egg-info/entry_points.txt +0 -0
  24. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/src/instapaper_scraper.egg-info/top_level.txt +0 -0
  25. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_cli_priority.py +0 -0
  26. {instapaper_scraper-1.1.0rc1 → instapaper_scraper-1.2.0}/tests/test_init.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: instapaper-scraper
3
- Version: 1.1.0rc1
3
+ Version: 1.2.0
4
4
  Summary: A tool to scrape articles from Instapaper.
5
5
  Project-URL: Homepage, https://github.com/chriskyfung/InstapaperScraper
6
6
  Project-URL: Source, https://github.com/chriskyfung/InstapaperScraper
@@ -21,7 +21,7 @@ Requires-Python: >=3.9
21
21
  Description-Content-Type: text/markdown
22
22
  License-File: LICENSE
23
23
  Requires-Dist: beautifulsoup4~=4.14.2
24
- Requires-Dist: certifi~=2025.11.12
24
+ Requires-Dist: certifi<2026.2.0,>=2025.11.12
25
25
  Requires-Dist: charset-normalizer~=3.4.3
26
26
  Requires-Dist: cryptography~=46.0.3
27
27
  Requires-Dist: guara~=0.0.14
@@ -35,30 +35,58 @@ Requires-Dist: tomli~=2.0.1; python_version < "3.11"
35
35
  Provides-Extra: dev
36
36
  Requires-Dist: pytest; extra == "dev"
37
37
  Requires-Dist: pytest-cov; extra == "dev"
38
- Requires-Dist: black; extra == "dev"
39
38
  Requires-Dist: ruff; extra == "dev"
40
39
  Requires-Dist: types-requests; extra == "dev"
41
40
  Requires-Dist: types-beautifulsoup4; extra == "dev"
42
41
  Requires-Dist: requests-mock; extra == "dev"
43
42
  Requires-Dist: build; extra == "dev"
44
43
  Requires-Dist: twine; extra == "dev"
44
+ Requires-Dist: mypy; extra == "dev"
45
+ Requires-Dist: pre-commit; extra == "dev"
46
+ Requires-Dist: licensecheck; extra == "dev"
45
47
  Dynamic: license-file
46
48
 
47
49
  # Instapaper Scraper
48
50
 
49
- ![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fchriskyfung%2FInstapaperScraper%2Frefs%2Fheads%2Fmaster%2Fpyproject.toml)
50
- [![CI](https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml/badge.svg)](https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml)
51
- [![PyPI version](https://img.shields.io/pypi/v/instapaper-scraper.svg)](https://pypi.org/project/instapaper-scraper/)
52
- [![PyPI Downloads](https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads)](https://pepy.tech/projects/instapaper-scraper)
53
- [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
54
- [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
55
- [![GitHub License](https://img.shields.io/github/license/chriskyfung/InstapaperScraper)
56
- ](https://www.gnu.org/licenses/gpl-3.0.en.html)
57
- [![codecov](https://codecov.io/gh/chriskyfung/InstapaperScraper/graph/badge.svg)](https://codecov.io/gh/chriskyfung/InstapaperScraper)
58
-
59
- A Python tool to scrape all your saved Instapaper bookmarks and export them to various formats.
60
-
61
- ## Features
51
+ <!-- Badges -->
52
+ <p align="center">
53
+ <a href="https://pypi.org/project/instapaper-scraper/">
54
+ <img src="https://img.shields.io/pypi/v/instapaper-scraper.svg" alt="PyPI version">
55
+ </a>
56
+ <a href="https://pepy.tech/projects/instapaper-scraper">
57
+ <img src="https://static.pepy.tech/personalized-badge/instapaper-scraper?period=total&left_text=downloads" alt="PyPI Downloads">
58
+ </a>
59
+ <a href="https://github.com/chriskyfung/InstapaperScraper">
60
+ <img src="https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fchriskyfung%2FInstapaperScraper%2Frefs%2Fheads%2Fmaster%2Fpyproject.toml" alt="Python Version from PEP 621 TOML">
61
+ </a>
62
+ <a href="https://github.com/astral-sh/ruff">
63
+ <img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fraw.githubusercontent.com%2Fastral-sh%2Fruff%2Fmain%2Fassets%2Fbadge%2Fv2.json" alt="Ruff">
64
+ </a>
65
+ <a href="https://codecov.io/gh/chriskyfung/InstapaperScraper">
66
+ <img src="https://codecov.io/gh/chriskyfung/InstapaperScraper/graph/badge.svg" alt="Code Coverage">
67
+ </a>
68
+ <wbr />
69
+ <a href="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml">
70
+ <img src="https://github.com/chriskyfung/InstapaperScraper/actions/workflows/ci.yml/badge.svg" alt="CI Status">
71
+ </a>
72
+ <a href="https://www.gnu.org/licenses/gpl-3.0.en.html">
73
+ <img src="https://img.shields.io/github/license/chriskyfung/InstapaperScraper" alt="GitHub License">
74
+ </a>
75
+ </p>
76
+
77
+ A powerful and reliable Python tool to automate the export of all your saved Instapaper bookmarks into various formats, giving you full ownership of your data.
78
+
79
+ <!-- Sponsors -->
80
+ <p align="center">
81
+ <a href="https://github.com/sponsors/chriskyfung" title="Sponsor on GitHub">
82
+ <img src="https://img.shields.io/badge/Sponsor-GitHub-blue?style=for-the-badge&logo=github-sponsors&colorA=263238&colorB=EC407A" alt="GitHub Sponsors Default">
83
+ </a>
84
+ <a href="https://www.buymeacoffee.com/chriskyfung" title="Support Coffee">
85
+ <img src="https://img.shields.io/badge/Support-Coffee-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=ffdd00&colorA=263238" alt="Buy Me A Coffee">
86
+ </a>
87
+ </p>
88
+
89
+ ## ✨ Features
62
90
 
63
91
  - Scrapes all bookmarks from your Instapaper account.
64
92
  - Supports scraping from specific folders.
@@ -66,13 +94,13 @@ A Python tool to scrape all your saved Instapaper bookmarks and export them to v
66
94
  - Securely stores your session for future runs.
67
95
  - Modern, modular, and tested architecture.
68
96
 
69
- ## Getting Started
97
+ ## 🚀 Getting Started
70
98
 
71
- ### 1. Requirements
99
+ ### 📋 1. Requirements
72
100
 
73
101
  - Python 3.9+
74
102
 
75
- ### 2. Installation
103
+ ### 📦 2. Installation
76
104
 
77
105
  This package is available on PyPI and can be installed with pip:
78
106
 
@@ -80,7 +108,7 @@ This package is available on PyPI and can be installed with pip:
80
108
  pip install instapaper-scraper
81
109
  ```
82
110
 
83
- ### 3. Usage
111
+ ### 💻 3. Usage
84
112
 
85
113
  Run the tool from the command line, specifying your desired output format:
86
114
 
@@ -95,35 +123,35 @@ instapaper-scraper --format json
95
123
  instapaper-scraper --format sqlite --output my_articles.db
96
124
  ```
97
125
 
98
- ## Configuration
126
+ ## ⚙️ Configuration
99
127
 
100
- ### Authentication
128
+ ### 🔐 Authentication
101
129
 
102
130
  The script authenticates using one of the following methods, in order of priority:
103
131
 
104
- 1. **Command-line Arguments**: Provide your username and password directly when running the script:
132
+ 1. **Command-line Arguments**: Provide your username and password directly when running the script:
105
133
 
106
134
  ```sh
107
135
  instapaper-scraper --username your_username --password your_password
108
136
  ```
109
137
 
110
- 2. **Session Files (`.session_key`, `.instapaper_session`)**: The script attempts to load these files in the following order:
138
+ 2. **Session Files (`.session_key`, `.instapaper_session`)**: The script attempts to load these files in the following order:
111
139
  a. Path specified by `--session-file` or `--key-file` arguments.
112
140
  b. Files in the current working directory (e.g., `./.session_key`).
113
141
  c. Files in the user's configuration directory (`~/.config/instapaper-scraper/`).
114
142
  After the first successful login, the script creates an encrypted `.instapaper_session` file and a `.session_key` file to reuse your session securely.
115
143
 
116
- 3. **Interactive Prompt**: If no other method is available, the script will prompt you for your username and password.
144
+ 3. **Interactive Prompt**: If no other method is available, the script will prompt you for your username and password.
117
145
 
118
146
  > **Note on Security:** Your session file (`.instapaper_session`) and the encryption key (`.session_key`) are stored with secure permissions (read/write for the owner only) to protect your credentials.
119
147
 
120
- ### Folder Configuration
148
+ ### 📁 Folder and Field Configuration
121
149
 
122
- You can define and quickly access your Instapaper folders using a `config.toml` file. The scraper will look for this file in the following locations (in order of precedence):
150
+ You can define and quickly access your Instapaper folders and set default output fields using a `config.toml` file. The scraper will look for this file in the following locations (in order of precedence):
123
151
 
124
- 1. The path specified by the `--config-path` argument.
125
- 2. `config.toml` in the current working directory.
126
- 3. `~/.config/instapaper-scraper/config.toml`
152
+ 1. The path specified by the `--config-path` argument.
153
+ 2. `config.toml` in the current working directory.
154
+ 3. `~/.config/instapaper-scraper/config.toml`
127
155
 
128
156
  Here is an example of `config.toml`:
129
157
 
@@ -131,6 +159,12 @@ Here is an example of `config.toml`:
131
159
  # Default output filename for non-folder mode
132
160
  output_filename = "home-articles.csv"
133
161
 
162
+ # Optional fields to include in the output.
163
+ # These can be overridden by command-line flags.
164
+ [fields]
165
+ read_url = false
166
+ article_preview = false
167
+
134
168
  [[folders]]
135
169
  key = "ml"
136
170
  id = "1234567"
@@ -145,14 +179,18 @@ output_filename = "python-articles.db"
145
179
  ```
146
180
 
147
181
  - **output_filename (top-level)**: The default output filename to use when not in folder mode.
148
- - **key**: A short alias for the folder.
149
- - **id**: The folder ID from the Instapaper URL.
150
- - **slug**: The human-readable part of the folder URL.
151
- - **output_filename (folder-specific)**: A preset output filename for scraped articles from this specific folder.
182
+ - **[fields]**: A section to control which optional data fields are included in the output.
183
+ - `read_url`: Set to `true` to include the Instapaper read URL for each article.
184
+ - `article_preview`: Set to `true` to include the article's text preview.
185
+ - **[[folders]]**: Each `[[folders]]` block defines a specific folder.
186
+ - **key**: A short alias for the folder.
187
+ - **id**: The folder ID from the Instapaper URL.
188
+ - **slug**: The human-readable part of the folder URL.
189
+ - **output_filename (folder-specific)**: A preset output filename for scraped articles from this specific folder.
152
190
 
153
191
  When a `config.toml` file is present and no `--folder` argument is provided, the scraper will prompt you to select a folder. You can also specify a folder directly using the `--folder` argument with its key, ID, or slug. Use `--folder=none` to explicitly disable folder mode and scrape all articles.
154
192
 
155
- ### Command-line Arguments
193
+ ### 💻 Command-line Arguments
156
194
 
157
195
  | Argument | Description |
158
196
  | --- | --- |
@@ -162,9 +200,10 @@ When a `config.toml` file is present and no `--folder` argument is provided, the
162
200
  | `--output <filename>` | Specify a custom output filename. The file extension will be automatically corrected to match the selected format. |
163
201
  | `--username <user>` | Your Instapaper account username. |
164
202
  | `--password <pass>` | Your Instapaper account password. |
165
- | `--add-instapaper-url` | Adds a `instapaper_url` column to the output, containing a full, clickable URL for each article. |
203
+ | `--[no-]read-url` | Includes the Instapaper read URL. (Old flag `--add-instapaper-url` is deprecated but supported). Can be set in `config.toml`. Overrides config. |
204
+ | `--[no-]article-preview` | Includes the article preview text. (Old flag `--add-article-preview` is deprecated but supported). Can be set in `config.toml`. Overrides config. |
166
205
 
167
- ### Output Formats
206
+ ### 📄 Output Formats
168
207
 
169
208
  You can control the output format using the `--format` argument. The supported formats are:
170
209
 
@@ -176,19 +215,19 @@ If the `--format` flag is omitted, the script will default to `csv`.
176
215
 
177
216
  When using `--output <filename>`, the file extension is automatically corrected to match the chosen format. For example, `instapaper-scraper --format json --output my_articles.txt` will create `my_articles.json`.
178
217
 
179
- #### Opening Articles in Instapaper
218
+ #### 📖 Opening Articles in Instapaper
180
219
 
181
220
  The output data includes a unique `id` for each article. You can use this ID to construct a URL to the article's reader view: `https://www.instapaper.com/read/<article_id>`.
182
221
 
183
- For convenience, you can use the `--add-instapaper-url` flag to have the script include a full, clickable URL in the output.
222
+ For convenience, you can use the `--read-url` flag to have the script include a full, clickable URL in the output.
184
223
 
185
224
  ```sh
186
- instapaper-scraper --add-instapaper-url
225
+ instapaper-scraper --read-url
187
226
  ```
188
227
 
189
228
  This adds a `instapaper_url` field to each article in the JSON output and a `instapaper_url` column in the CSV and SQLite outputs. The original `id` field is preserved.
190
229
 
191
- ## How It Works
230
+ ## 🛠️ How It Works
192
231
 
193
232
  The tool is designed with a modular architecture for reliability and maintainability.
194
233
 
@@ -197,17 +236,17 @@ The tool is designed with a modular architecture for reliability and maintainabi
197
236
  3. **Data Collection**: All fetched articles are aggregated into a single list.
198
237
  4. **Export**: Finally, the collected data is written to a file in your chosen format (`.csv`, `.json`, or `.db`).
199
238
 
200
- ## Example Output
239
+ ## 📊 Example Output
201
240
 
202
- ### CSV (`output/bookmarks.csv`) (with --add-instapaper-url)
241
+ ### 📄 CSV (`output/bookmarks.csv`) (with --add-instapaper-url and --add-article-preview)
203
242
 
204
243
  ```csv
205
- "id","instapaper_url","title","url"
206
- "999901234","https://www.instapaper.com/read/999901234","Article 1","https://www.example.com/page-1/"
207
- "999002345","https://www.instapaper.com/read/999002345","Article 2","https://www.example.com/page-2/"
244
+ "id","instapaper_url","title","url","article_preview"
245
+ "999901234","https://www.instapaper.com/read/999901234","Article 1","https://www.example.com/page-1/","This is a preview of article 1."
246
+ "999002345","https://www.instapaper.com/read/999002345","Article 2","https://www.example.com/page-2/","This is a preview of article 2."
208
247
  ```
209
248
 
210
- ### JSON (`output/bookmarks.json`) (with --add-instapaper-url)
249
+ ### 📄 JSON (`output/bookmarks.json`) (with --add-instapaper-url and --add-article-preview)
211
250
 
212
251
  ```json
213
252
  [
@@ -215,26 +254,57 @@ The tool is designed with a modular architecture for reliability and maintainabi
215
254
  "id": "999901234",
216
255
  "title": "Article 1",
217
256
  "url": "https://www.example.com/page-1/",
218
- "instapaper_url": "https://www.instapaper.com/read/999901234"
257
+ "instapaper_url": "https://www.instapaper.com/read/999901234",
258
+ "article_preview": "This is a preview of article 1."
219
259
  },
220
260
  {
221
261
  "id": "999002345",
222
262
  "title": "Article 2",
223
263
  "url": "https://www.example.com/page-2/",
224
- "instapaper_url": "https://www.instapaper.com/read/999002345"
264
+ "instapaper_url": "https://www.instapaper.com/read/999002345",
265
+ "article_preview": "This is a preview of article 2."
225
266
  }
226
267
  ]
227
268
  ```
228
269
 
229
- ### SQLite (`output/bookmarks.db`)
270
+ ### 🗄️ SQLite (`output/bookmarks.db`)
230
271
 
231
272
  A SQLite database file is created with an `articles` table. The table includes `id`, `title`, and `url` columns. If the `--add-instapaper-url` flag is used, a `instapaper_url` column is also included. This feature is fully backward-compatible and will automatically adapt to the user's installed SQLite version, using an efficient generated column on modern versions (3.31.0+) and a fallback for older versions.
232
273
 
233
- ## Development & Testing
274
+ ## 🤗 Support and Community
275
+
276
+ - **🐛 Bug Reports:** For any bugs or unexpected behavior, please [open an issue on GitHub](https://github.com/chriskyfung/InstapaperScraper/issues).
277
+ - **💬 Questions & General Discussion:** For questions, feature requests, or general discussion, please use our [GitHub Discussions](https://github.com/chriskyfung/InstapaperScraper/discussions).
278
+
279
+ ## 🙏 Support the Project
280
+
281
+ `Instapaper Scraper` is a free and open-source project that requires significant time and effort to maintain and improve. If you find this tool useful, please consider supporting its development. Your contribution helps ensure the project stays healthy, active, and continuously updated.
282
+
283
+ - **[Sponsor on GitHub](https://github.com/sponsors/chriskyfung):** The best way to support the project with recurring monthly donations. Tiers with special rewards like priority support are available!
284
+ - **[Buy Me a Coffee](https://www.buymeacoffee.com/chriskyfung):** Perfect for a one-time thank you.
285
+
286
+ ## 🤝 Contributing
287
+
288
+ Contributions are welcome! Whether it's a bug fix, a new feature, or documentation improvements, please feel free to open a pull request.
289
+
290
+ Please read the **[Contribution Guidelines](CONTRIBUTING.md)** before you start.
291
+
292
+ ## 🧑‍💻 Development & Testing
293
+
294
+ This project uses `pytest` for testing, `ruff` for code formatting and linting, and `mypy` for static type checking. A `Makefile` is provided to simplify common development tasks.
295
+
296
+ ### 🚀 Using the Makefile
297
+
298
+ The most common commands are:
299
+ - `make install`: Installs development dependencies.
300
+ - `make format`: Formats the entire codebase.
301
+ - `make check`: Runs the linter, type checker, and test suite.
302
+ - `make test`: Runs the test suite.
303
+ - `make build`: Builds the distributable packages.
234
304
 
235
- This project uses `pytest` for testing, `black` for code formatting, and `ruff` for linting.
305
+ Run `make help` to see all available commands.
236
306
 
237
- ### Setup
307
+ ### 🔧 Setup
238
308
 
239
309
  To install the development dependencies:
240
310
 
@@ -242,7 +312,13 @@ To install the development dependencies:
242
312
  pip install -e .[dev]
243
313
  ```
244
314
 
245
- ### Running the Scraper
315
+ To set up the pre-commit hooks:
316
+
317
+ ```sh
318
+ pre-commit install
319
+ ```
320
+
321
+ ### ▶️ Running the Scraper
246
322
 
247
323
  To run the scraper directly without installing the package:
248
324
 
@@ -250,26 +326,28 @@ To run the scraper directly without installing the package:
250
326
  python -m src.instapaper_scraper.cli
251
327
  ```
252
328
 
253
- ### Testing
329
+ ### Testing
254
330
 
255
- To run the tests, execute the following command from the project root:
331
+ To run the tests, execute the following command from the project root (or use `make test`):
256
332
 
257
333
  ```sh
258
334
  pytest
259
335
  ```
260
336
 
261
- To check test coverage:
337
+ To check test coverage (or use `make test-cov`):
262
338
 
263
339
  ```sh
264
340
  pytest --cov=src/instapaper_scraper --cov-report=term-missing
265
341
  ```
266
342
 
267
- ### Code Quality
343
+ ### Code Quality
268
344
 
269
- To format the code with `black`:
345
+ You can use the `Makefile` for convenience (e.g., `make format`, `make lint`).
346
+
347
+ To format the code with `ruff`:
270
348
 
271
349
  ```sh
272
- black .
350
+ ruff format .
273
351
  ```
274
352
 
275
353
  To check for linting errors with `ruff`:
@@ -278,16 +356,29 @@ To check for linting errors with `ruff`:
278
356
  ruff check .
279
357
  ```
280
358
 
281
- To automatically fix linting errors:
359
+ To run static type checking with `mypy`:
282
360
 
283
361
  ```sh
284
- ruff check . --fix
362
+ mypy src
285
363
  ```
286
364
 
287
- ## Disclaimer
365
+ To run license checks:
366
+
367
+ ```sh
368
+ licensecheck --zero
369
+ ```
370
+
371
+
372
+ ## 📜 Disclaimer
288
373
 
289
374
  This script requires valid Instapaper credentials. Use it responsibly and in accordance with Instapaper’s Terms of Service.
290
375
 
291
- ## License
376
+ ## 📄 License
377
+
378
+ This project is licensed under the terms of the **GNU General Public License v3.0**. See the [LICENSE](LICENSE) file for the full license text.
379
+
380
+ ## Contributors
381
+
382
+ [![Contributors](https://contrib.rocks/image?repo=chriskyfung/InstapaperScraper)](https://github.com/chriskyfung/InstapaperScraper/graphs/contributors)
292
383
 
293
- This project is licensed under the terms of the GNU General Public License v3.0. See the [LICENSE](LICENSE) file for the full license text.
384
+ Made with [contrib.rocks](https://contrib.rocks).