threadstractormf 1.4.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 (52) hide show
  1. threadstractormf-1.4.0/.dockerignore +18 -0
  2. threadstractormf-1.4.0/.github/workflows/ci.yml +36 -0
  3. threadstractormf-1.4.0/.github/workflows/docker.yml +65 -0
  4. threadstractormf-1.4.0/.github/workflows/release.yml +134 -0
  5. threadstractormf-1.4.0/.gitignore +38 -0
  6. threadstractormf-1.4.0/Dockerfile +35 -0
  7. threadstractormf-1.4.0/LICENSE +674 -0
  8. threadstractormf-1.4.0/PKG-INFO +163 -0
  9. threadstractormf-1.4.0/README.md +126 -0
  10. threadstractormf-1.4.0/pyproject.toml +100 -0
  11. threadstractormf-1.4.0/scripts/sniff.py +179 -0
  12. threadstractormf-1.4.0/tests/conftest.py +161 -0
  13. threadstractormf-1.4.0/tests/test_adaptive_rate_limit.py +284 -0
  14. threadstractormf-1.4.0/tests/test_archive.py +557 -0
  15. threadstractormf-1.4.0/tests/test_auth.py +30 -0
  16. threadstractormf-1.4.0/tests/test_backend.py +155 -0
  17. threadstractormf-1.4.0/tests/test_brave_variants.py +127 -0
  18. threadstractormf-1.4.0/tests/test_cdn_allowlist.py +184 -0
  19. threadstractormf-1.4.0/tests/test_cookie_loading.py +302 -0
  20. threadstractormf-1.4.0/tests/test_directory_safety.py +202 -0
  21. threadstractormf-1.4.0/tests/test_discovery.py +981 -0
  22. threadstractormf-1.4.0/tests/test_download_retry.py +130 -0
  23. threadstractormf-1.4.0/tests/test_downloader.py +11 -0
  24. threadstractormf-1.4.0/tests/test_errors.py +264 -0
  25. threadstractormf-1.4.0/tests/test_extraction.py +245 -0
  26. threadstractormf-1.4.0/tests/test_fixtures.py +84 -0
  27. threadstractormf-1.4.0/tests/test_get_urls.py +251 -0
  28. threadstractormf-1.4.0/tests/test_impersonate.py +206 -0
  29. threadstractormf-1.4.0/tests/test_models.py +29 -0
  30. threadstractormf-1.4.0/tests/test_pagination.py +186 -0
  31. threadstractormf-1.4.0/tests/test_profile_fallback_cookies.py +301 -0
  32. threadstractormf-1.4.0/tests/test_rate_limit.py +61 -0
  33. threadstractormf-1.4.0/tests/test_retry_4xx.py +117 -0
  34. threadstractormf-1.4.0/tests/test_scrape_report.py +688 -0
  35. threadstractormf-1.4.0/tests/test_subfolders.py +134 -0
  36. threadstractormf-1.4.0/tests/test_user_id.py +227 -0
  37. threadstractormf-1.4.0/tests/test_video_url_fix.py +32 -0
  38. threadstractormf-1.4.0/tests/test_video_versions_fix.py +55 -0
  39. threadstractormf-1.4.0/threadstractormf/__init__.py +7 -0
  40. threadstractormf-1.4.0/threadstractormf/_backend.py +283 -0
  41. threadstractormf-1.4.0/threadstractormf/_discovery.py +445 -0
  42. threadstractormf-1.4.0/threadstractormf/_parsing.py +244 -0
  43. threadstractormf-1.4.0/threadstractormf/api.py +1269 -0
  44. threadstractormf-1.4.0/threadstractormf/archive.py +262 -0
  45. threadstractormf-1.4.0/threadstractormf/auth.py +319 -0
  46. threadstractormf-1.4.0/threadstractormf/cli.py +426 -0
  47. threadstractormf-1.4.0/threadstractormf/client.py +221 -0
  48. threadstractormf-1.4.0/threadstractormf/downloader.py +353 -0
  49. threadstractormf-1.4.0/threadstractormf/models.py +123 -0
  50. threadstractormf-1.4.0/threadstractormf/rate_limit.py +201 -0
  51. threadstractormf-1.4.0/threadstractormf/template.py +123 -0
  52. threadstractormf-1.4.0/uv.lock +1779 -0
@@ -0,0 +1,18 @@
1
+ .git
2
+ .venv
3
+ __pycache__
4
+ *.pyc
5
+ *.pyo
6
+ *.pyd
7
+ .pytest_cache
8
+ .mypy_cache
9
+ .ruff_cache
10
+ tests
11
+ docs
12
+ # *.md excluded except README.md (needed by hatchling build)
13
+ .env
14
+ .env.*
15
+ cookies.txt
16
+ *cookies*.txt
17
+ scripts/sniff_log.json
18
+ scripts/*_requests*.json
@@ -0,0 +1,36 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ name: Test (Python ${{ matrix.python-version }})
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ python-version: ["3.10", "3.12", "3.14"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: "Sync dependencies (all extras)"
25
+ run: uv sync --all-extras
26
+
27
+ - name: Lint (ruff)
28
+ run: uv run ruff check .
29
+
30
+ # mypy pins python_version=3.10 (see [tool.mypy]) but runs on the matrix
31
+ # interpreter; the checks are version-independent for this codebase.
32
+ - name: Types (mypy)
33
+ run: uv run mypy threadstractormf scripts
34
+
35
+ - name: Tests (pytest)
36
+ run: uv run pytest -q
@@ -0,0 +1,65 @@
1
+ name: Docker
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ tags: ["v*"]
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+ packages: write
12
+
13
+ jobs:
14
+ build:
15
+ name: Build & push (${{ matrix.variant }})
16
+ runs-on: ubuntu-latest
17
+ strategy:
18
+ fail-fast: false
19
+ matrix:
20
+ variant: [slim, full]
21
+ steps:
22
+ - name: Checkout
23
+ uses: actions/checkout@v4
24
+
25
+ - name: Set up QEMU
26
+ uses: docker/setup-qemu-action@v3
27
+
28
+ - name: Set up Docker Buildx
29
+ uses: docker/setup-buildx-action@v3
30
+
31
+ - name: Log in to GHCR
32
+ uses: docker/login-action@v3
33
+ with:
34
+ registry: ghcr.io
35
+ username: ${{ github.actor }}
36
+ password: ${{ secrets.GITHUB_TOKEN }}
37
+
38
+ - name: Docker metadata
39
+ id: meta
40
+ uses: docker/metadata-action@v5
41
+ with:
42
+ images: ghcr.io/extractorsmf/threadstractormf
43
+ tags: |
44
+ type=raw,value=${{ matrix.variant }}
45
+ type=raw,value=latest,enable=${{ matrix.variant == 'full' }}
46
+ type=semver,pattern={{version}},enable=${{ matrix.variant == 'full' }}
47
+ type=sha,prefix=sha-,enable=${{ matrix.variant == 'full' }}
48
+
49
+ - name: Build and push
50
+ uses: docker/build-push-action@v6
51
+ with:
52
+ context: .
53
+ file: ./Dockerfile
54
+ target: ${{ matrix.variant }}
55
+ platforms: linux/amd64,linux/arm64
56
+ push: true
57
+ tags: ${{ steps.meta.outputs.tags }}
58
+ labels: ${{ steps.meta.outputs.labels }}
59
+ build-args: |
60
+ VARIANT=${{ matrix.variant }}
61
+
62
+ - name: Smoke test (slim)
63
+ if: matrix.variant == 'slim'
64
+ run: |
65
+ docker run --rm ghcr.io/extractorsmf/threadstractormf:slim --version
@@ -0,0 +1,134 @@
1
+ name: Release
2
+
3
+ # python-semantic-release: analyzes conventional commits on main.
4
+ # feat -> minor | fix/perf -> patch | feat!/BREAKING CHANGE -> major
5
+ # If there are no new relevant commits, it does nothing (released=false).
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ workflow_dispatch:
11
+
12
+ permissions:
13
+ contents: write # commit de version + tag + GitHub Release
14
+
15
+ jobs:
16
+ release:
17
+ name: Semantic Release
18
+ runs-on: ubuntu-latest
19
+ outputs:
20
+ released: ${{ steps.out.outputs.released }}
21
+ tag: ${{ steps.out.outputs.tag }}
22
+ concurrency:
23
+ group: semantic-release
24
+ cancel-in-progress: false
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ with:
28
+ fetch-depth: 0 # PSR needs full history for commit analysis
29
+ token: ${{ secrets.GITHUB_TOKEN }}
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@v5
33
+
34
+ - name: Sync dependencies
35
+ run: uv sync --all-extras
36
+
37
+ - name: Configure git (bot identity for the version commit)
38
+ run: |
39
+ git config user.name "semantic-release-bot"
40
+ git config user.email "semantic-release-bot@users.noreply.github.com"
41
+
42
+ # PSR invoked directly with explicit flags:
43
+ # --no-changelog : this project has NO CHANGELOG.md
44
+ # --push : pushes commit + tag
45
+ # --vcs-release : creates the GitHub Release with notes from commits
46
+ # NOTE: no --strict, because when the version was already released
47
+ # (e.g. first push with tag v1.0.0 at HEAD) PSR would exit with code 2.
48
+ # NOTE: PSR v9 reads the token from GH_TOKEN (not GITHUB_TOKEN)
49
+ - name: Semantic Release (bump + tag + release, no changelog)
50
+ id: release
51
+ run: |
52
+ uv run semantic-release \
53
+ version \
54
+ --no-changelog \
55
+ --commit --tag --push \
56
+ --vcs-release \
57
+ --skip-build
58
+ env:
59
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60
+
61
+ # PSR CLI outputs: uses GITHUB_OUTPUT for the following steps
62
+ - name: Set outputs
63
+ if: always()
64
+ id: out
65
+ run: |
66
+ if git describe --exact-match --tags HEAD 2>/dev/null; then
67
+ echo "released=true" >> "$GITHUB_OUTPUT"
68
+ echo "tag=$(git describe --exact-match --tags HEAD)" >> "$GITHUB_OUTPUT"
69
+ else
70
+ echo "released=false" >> "$GITHUB_OUTPUT"
71
+ fi
72
+
73
+ - name: Build distributions
74
+ if: steps.out.outputs.released == 'true'
75
+ run: uv build
76
+
77
+ - name: Upload distributions
78
+ if: steps.out.outputs.released == 'true'
79
+ uses: actions/upload-artifact@v4
80
+ with:
81
+ name: dist
82
+ path: dist/*
83
+
84
+ - name: Attach wheel + sdist to GitHub Release
85
+ if: steps.out.outputs.released == 'true'
86
+ uses: softprops/action-gh-release@v2
87
+ with:
88
+ tag_name: ${{ steps.out.outputs.tag }}
89
+ # explicit patterns: uv build drops a dist/.gitignore that a bare
90
+ # "dist/*" glob would upload as a bogus "default.gitignore" asset
91
+ files: |
92
+ dist/*.whl
93
+ dist/*.tar.gz
94
+
95
+
96
+ publish-pypi:
97
+ name: Publish to PyPI
98
+ needs: release
99
+ if: needs.release.outputs.released == 'true'
100
+ runs-on: ubuntu-latest
101
+ environment: pypi
102
+ permissions:
103
+ id-token: write
104
+ steps:
105
+ - name: Download distributions
106
+ uses: actions/download-artifact@v4
107
+ with:
108
+ name: dist
109
+ path: dist
110
+ - name: Publish to PyPI
111
+ uses: pypa/gh-action-pypi-publish@release/v1
112
+ with:
113
+ skip-existing: true
114
+
115
+
116
+ publish-testpypi:
117
+ name: Publish to TestPyPI
118
+ if: github.event_name == 'workflow_dispatch'
119
+ runs-on: ubuntu-latest
120
+ environment: testpypi
121
+ permissions:
122
+ id-token: write
123
+ steps:
124
+ - name: Checkout
125
+ uses: actions/checkout@v4
126
+ - name: Set up uv
127
+ uses: astral-sh/setup-uv@v5
128
+ - name: Build
129
+ run: uv build
130
+ - name: Publish to TestPyPI
131
+ uses: pypa/gh-action-pypi-publish@release/v1
132
+ with:
133
+ repository-url: https://test.pypi.org/legacy/
134
+ skip-existing: true
@@ -0,0 +1,38 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ .venv/
7
+ venv/
8
+ .pytest_cache/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+ *.egg-info/
12
+ dist/
13
+ build/
14
+ # cookies / secrets
15
+ cookies.txt
16
+ *cookies*.txt
17
+ # environment / secrets
18
+ .env
19
+ .env.*
20
+ !.env.example
21
+ scripts/sniff_log.json
22
+ scripts/*_requests*.json
23
+ # Frozen pre-refactor cookie loader, used as the oracle in
24
+ # tests/test_cookie_loading.py. Not part of the package.
25
+ .old_auth_for_tests.py
26
+ # Project memory / agent instructions (local, not shipped)
27
+ docs/
28
+ AGENTS.md
29
+ llms.txt
30
+ llms-full.txt
31
+ review.md
32
+
33
+ # OS
34
+ .DS_Store
35
+ Thumbs.db
36
+ # IDE
37
+ .vscode/
38
+ .idea/
@@ -0,0 +1,35 @@
1
+ # syntax=docker/dockerfile:1
2
+ ARG PYTHON_VERSION=3.12
3
+
4
+ # ---- base ----
5
+ FROM python:${PYTHON_VERSION}-slim AS base
6
+ ENV PYTHONDONTWRITEBYTECODE=1 \
7
+ PYTHONUNBUFFERED=1 \
8
+ UV_LINK_MODE=copy
9
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
10
+ WORKDIR /app
11
+
12
+ # ---- slim (core only) ----
13
+ FROM base AS slim
14
+ COPY pyproject.toml uv.lock README.md ./
15
+ COPY threadstractormf ./threadstractormf
16
+ RUN uv sync --frozen --no-dev
17
+ ENV PATH="/app/.venv/bin:$PATH"
18
+ USER 1000
19
+ ENTRYPOINT ["threadstractormf"]
20
+
21
+ # ---- full (slim + antibot + browser) ----
22
+ FROM slim AS full
23
+ USER root
24
+ RUN apt-get update && apt-get install -y --no-install-recommends \
25
+ libnss3 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
26
+ libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
27
+ libgbm1 libasound2 libpango-1.0-0 libcairo2 \
28
+ && rm -rf /var/lib/apt/lists/*
29
+ RUN uv sync --frozen --no-dev --extra browser --extra antibot
30
+ ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
31
+ RUN uv run playwright install chromium && chmod -R 755 /ms-playwright
32
+ ENV THREADS_USE_SANDBOX=1
33
+ ENV PATH="/app/.venv/bin:$PATH"
34
+ USER 1000
35
+ ENTRYPOINT ["threadstractormf"]