papersearch 0.0.0-stage → 0.4.2
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.
- package/.env.example +208 -0
- package/LICENSE +21 -0
- package/README.md +213 -2
- package/README.zh.md +214 -0
- package/carsi/LICENSE +21 -0
- package/carsi/NOTICE +5 -0
- package/carsi/README.md +75 -0
- package/carsi/paper_search_carsi/__init__.py +6 -0
- package/carsi/paper_search_carsi/_core/__init__.py +26 -0
- package/carsi/paper_search_carsi/_core/racing.pyx +280 -0
- package/carsi/paper_search_carsi/adapters/__init__.py +26 -0
- package/carsi/paper_search_carsi/adapters/acm/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/acs/__init__.py +47 -0
- package/carsi/paper_search_carsi/adapters/aha_journals/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/ams/__init__.py +19 -0
- package/carsi/paper_search_carsi/adapters/annual_reviews/__init__.py +154 -0
- package/carsi/paper_search_carsi/adapters/aps/__init__.py +127 -0
- package/carsi/paper_search_carsi/adapters/asce/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/base.py +320 -0
- package/carsi/paper_search_carsi/adapters/bmj/__init__.py +32 -0
- package/carsi/paper_search_carsi/adapters/copernicus/__init__.py +20 -0
- package/carsi/paper_search_carsi/adapters/dovepress/__init__.py +43 -0
- package/carsi/paper_search_carsi/adapters/elsevier/__init__.py +302 -0
- package/carsi/paper_search_carsi/adapters/elsevier/journal_site.py +237 -0
- package/carsi/paper_search_carsi/adapters/elsevier/sciencedirect.py +138 -0
- package/carsi/paper_search_carsi/adapters/ieee/__init__.py +184 -0
- package/carsi/paper_search_carsi/adapters/iop/__init__.py +41 -0
- package/carsi/paper_search_carsi/adapters/jama/__init__.py +54 -0
- package/carsi/paper_search_carsi/adapters/karger/__init__.py +75 -0
- package/carsi/paper_search_carsi/adapters/lww/__init__.py +103 -0
- package/carsi/paper_search_carsi/adapters/lww/journals_lww.py +36 -0
- package/carsi/paper_search_carsi/adapters/lww/ovid.py +72 -0
- package/carsi/paper_search_carsi/adapters/mdpi/__init__.py +20 -0
- package/carsi/paper_search_carsi/adapters/nejm/__init__.py +18 -0
- package/carsi/paper_search_carsi/adapters/neurology/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/optica/__init__.py +33 -0
- package/carsi/paper_search_carsi/adapters/oup/__init__.py +366 -0
- package/carsi/paper_search_carsi/adapters/platforms/__init__.py +5 -0
- package/carsi/paper_search_carsi/adapters/platforms/atypon/__init__.py +149 -0
- package/carsi/paper_search_carsi/adapters/platforms/silverchair/__init__.py +83 -0
- package/carsi/paper_search_carsi/adapters/plos/__init__.py +20 -0
- package/carsi/paper_search_carsi/adapters/pnas/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/rsc/__init__.py +74 -0
- package/carsi/paper_search_carsi/adapters/sage/__init__.py +154 -0
- package/carsi/paper_search_carsi/adapters/science/__init__.py +13 -0
- package/carsi/paper_search_carsi/adapters/springer/__init__.py +62 -0
- package/carsi/paper_search_carsi/adapters/taylor_francis/__init__.py +46 -0
- package/carsi/paper_search_carsi/adapters/thieme/__init__.py +164 -0
- package/carsi/paper_search_carsi/adapters/wiley/__init__.py +145 -0
- package/carsi/paper_search_carsi/adapters/world_scientific/__init__.py +27 -0
- package/carsi/paper_search_carsi/assets/icon-32.png +0 -0
- package/carsi/paper_search_carsi/assets/icon-512.png +0 -0
- package/carsi/paper_search_carsi/assets/icon-64.png +0 -0
- package/carsi/paper_search_carsi/assets/icon.svg +43 -0
- package/carsi/paper_search_carsi/blocked_journals.py +63 -0
- package/carsi/paper_search_carsi/browser/__init__.py +1 -0
- package/carsi/paper_search_carsi/browser/backend.py +823 -0
- package/carsi/paper_search_carsi/browser/cookies.py +386 -0
- package/carsi/paper_search_carsi/browser/ego_relay.py +152 -0
- package/carsi/paper_search_carsi/browser/engine.py +927 -0
- package/carsi/paper_search_carsi/browser/login.py +336 -0
- package/carsi/paper_search_carsi/browser/preview.py +379 -0
- package/carsi/paper_search_carsi/browser/watchdog.py +193 -0
- package/carsi/paper_search_carsi/cache.py +62 -0
- package/carsi/paper_search_carsi/carsi_schools.py +109 -0
- package/carsi/paper_search_carsi/cli.py +479 -0
- package/carsi/paper_search_carsi/cold_start.py +251 -0
- package/carsi/paper_search_carsi/config.py +301 -0
- package/carsi/paper_search_carsi/data/institutional_identity_policy.json +165 -0
- package/carsi/paper_search_carsi/data/publisher_access_catalog.json +969 -0
- package/carsi/paper_search_carsi/data/publisher_browser_verification_matrix.json +625 -0
- package/carsi/paper_search_carsi/download_diagnostics.py +228 -0
- package/carsi/paper_search_carsi/engine/__init__.py +1 -0
- package/carsi/paper_search_carsi/engine/access_rules.py +345 -0
- package/carsi/paper_search_carsi/engine/batch.py +702 -0
- package/carsi/paper_search_carsi/engine/batch_access.py +483 -0
- package/carsi/paper_search_carsi/engine/batch_capture.py +1531 -0
- package/carsi/paper_search_carsi/engine/batch_common.py +427 -0
- package/carsi/paper_search_carsi/engine/batch_diagnostics.py +307 -0
- package/carsi/paper_search_carsi/engine/batch_institution.py +981 -0
- package/carsi/paper_search_carsi/engine/batch_login.py +1605 -0
- package/carsi/paper_search_carsi/engine/batch_pdf_urls.py +274 -0
- package/carsi/paper_search_carsi/engine/batch_runs.py +711 -0
- package/carsi/paper_search_carsi/engine/batch_user.py +173 -0
- package/carsi/paper_search_carsi/engine/batch_waits.py +441 -0
- package/carsi/paper_search_carsi/engine/bridge.py +666 -0
- package/carsi/paper_search_carsi/engine/pdf_guard.py +310 -0
- package/carsi/paper_search_carsi/engine/router.py +514 -0
- package/carsi/paper_search_carsi/engine/supplements.py +148 -0
- package/carsi/paper_search_carsi/entitlements.py +233 -0
- package/carsi/paper_search_carsi/extractors/__init__.py +0 -0
- package/carsi/paper_search_carsi/extractors/pdf_extractor.py +149 -0
- package/carsi/paper_search_carsi/identifiers.py +121 -0
- package/carsi/paper_search_carsi/issues.py +227 -0
- package/carsi/paper_search_carsi/log.py +84 -0
- package/carsi/paper_search_carsi/mcp_progress.py +82 -0
- package/carsi/paper_search_carsi/network.py +359 -0
- package/carsi/paper_search_carsi/orchestrator.py +130 -0
- package/carsi/paper_search_carsi/pdf_utils.py +279 -0
- package/carsi/paper_search_carsi/progress_bar.py +778 -0
- package/carsi/paper_search_carsi/progress_reporter.py +530 -0
- package/carsi/paper_search_carsi/progress_status.py +212 -0
- package/carsi/paper_search_carsi/publishers/__init__.py +10 -0
- package/carsi/paper_search_carsi/publishers/builtin/acm.json +65 -0
- package/carsi/paper_search_carsi/publishers/builtin/acs.json +73 -0
- package/carsi/paper_search_carsi/publishers/builtin/aha-journals.json +47 -0
- package/carsi/paper_search_carsi/publishers/builtin/aip.json +66 -0
- package/carsi/paper_search_carsi/publishers/builtin/ams.json +66 -0
- package/carsi/paper_search_carsi/publishers/builtin/annual-reviews.json +64 -0
- package/carsi/paper_search_carsi/publishers/builtin/aps.json +70 -0
- package/carsi/paper_search_carsi/publishers/builtin/asce.json +46 -0
- package/carsi/paper_search_carsi/publishers/builtin/bmj.json +46 -0
- package/carsi/paper_search_carsi/publishers/builtin/copernicus.json +45 -0
- package/carsi/paper_search_carsi/publishers/builtin/dovepress.json +35 -0
- package/carsi/paper_search_carsi/publishers/builtin/elsevier.json +77 -0
- package/carsi/paper_search_carsi/publishers/builtin/frontiers.json +62 -0
- package/carsi/paper_search_carsi/publishers/builtin/ieee.json +68 -0
- package/carsi/paper_search_carsi/publishers/builtin/iop.json +69 -0
- package/carsi/paper_search_carsi/publishers/builtin/jama.json +48 -0
- package/carsi/paper_search_carsi/publishers/builtin/karger.json +48 -0
- package/carsi/paper_search_carsi/publishers/builtin/lww.json +57 -0
- package/carsi/paper_search_carsi/publishers/builtin/mdpi.json +46 -0
- package/carsi/paper_search_carsi/publishers/builtin/nejm.json +46 -0
- package/carsi/paper_search_carsi/publishers/builtin/neurology.json +45 -0
- package/carsi/paper_search_carsi/publishers/builtin/optica.json +77 -0
- package/carsi/paper_search_carsi/publishers/builtin/oxfordacademic.json +64 -0
- package/carsi/paper_search_carsi/publishers/builtin/plos.json +46 -0
- package/carsi/paper_search_carsi/publishers/builtin/pnas.json +67 -0
- package/carsi/paper_search_carsi/publishers/builtin/royalsocietypublishing.json +62 -0
- package/carsi/paper_search_carsi/publishers/builtin/rsc.json +71 -0
- package/carsi/paper_search_carsi/publishers/builtin/sage.json +48 -0
- package/carsi/paper_search_carsi/publishers/builtin/science.json +68 -0
- package/carsi/paper_search_carsi/publishers/builtin/springer.json +92 -0
- package/carsi/paper_search_carsi/publishers/builtin/taylor-francis.json +52 -0
- package/carsi/paper_search_carsi/publishers/builtin/thieme.json +50 -0
- package/carsi/paper_search_carsi/publishers/builtin/wiley.json +77 -0
- package/carsi/paper_search_carsi/publishers/builtin/world-scientific.json +68 -0
- package/carsi/paper_search_carsi/publishers/extensions.py +241 -0
- package/carsi/paper_search_carsi/publishers/loader.py +93 -0
- package/carsi/paper_search_carsi/publishers/model.py +90 -0
- package/carsi/paper_search_carsi/publishers/profiles.py +127 -0
- package/carsi/paper_search_carsi/publishers/schema.json +129 -0
- package/carsi/paper_search_carsi/publishers/site.py +86 -0
- package/carsi/paper_search_carsi/rate_limit.py +51 -0
- package/carsi/paper_search_carsi/server.py +197 -0
- package/carsi/paper_search_carsi/session_broker.py +163 -0
- package/carsi/paper_search_carsi/tor.py +9 -0
- package/carsi/paper_search_carsi/user_settings.py +55 -0
- package/carsi/pyproject.toml +41 -0
- package/dist/capabilities/body-snippet-search/handler.d.ts +9 -0
- package/dist/capabilities/body-snippet-search/handler.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/handler.js +17 -0
- package/dist/capabilities/body-snippet-search/handler.js.map +1 -0
- package/dist/capabilities/body-snippet-search/index.d.ts +7 -0
- package/dist/capabilities/body-snippet-search/index.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/index.js +6 -0
- package/dist/capabilities/body-snippet-search/index.js.map +1 -0
- package/dist/capabilities/body-snippet-search/schemas.d.ts +36 -0
- package/dist/capabilities/body-snippet-search/schemas.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/schemas.js +16 -0
- package/dist/capabilities/body-snippet-search/schemas.js.map +1 -0
- package/dist/capabilities/body-snippet-search/service.d.ts +4 -0
- package/dist/capabilities/body-snippet-search/service.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/service.js +4 -0
- package/dist/capabilities/body-snippet-search/service.js.map +1 -0
- package/dist/capabilities/body-snippet-search/tools.d.ts +187 -0
- package/dist/capabilities/body-snippet-search/tools.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/tools.js +49 -0
- package/dist/capabilities/body-snippet-search/tools.js.map +1 -0
- package/dist/capabilities/body-snippet-search/types.d.ts +14 -0
- package/dist/capabilities/body-snippet-search/types.d.ts.map +1 -0
- package/dist/capabilities/body-snippet-search/types.js +2 -0
- package/dist/capabilities/body-snippet-search/types.js.map +1 -0
- package/dist/capabilities/citation-expansion/CitationService.d.ts +47 -0
- package/dist/capabilities/citation-expansion/CitationService.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/CitationService.js +243 -0
- package/dist/capabilities/citation-expansion/CitationService.js.map +1 -0
- package/dist/capabilities/citation-expansion/handler.d.ts +36 -0
- package/dist/capabilities/citation-expansion/handler.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/handler.js +44 -0
- package/dist/capabilities/citation-expansion/handler.js.map +1 -0
- package/dist/capabilities/citation-expansion/index.d.ts +6 -0
- package/dist/capabilities/citation-expansion/index.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/index.js +5 -0
- package/dist/capabilities/citation-expansion/index.js.map +1 -0
- package/dist/capabilities/citation-expansion/schemas.d.ts +28 -0
- package/dist/capabilities/citation-expansion/schemas.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/schemas.js +13 -0
- package/dist/capabilities/citation-expansion/schemas.js.map +1 -0
- package/dist/capabilities/citation-expansion/tools.d.ts +82 -0
- package/dist/capabilities/citation-expansion/tools.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/tools.js +48 -0
- package/dist/capabilities/citation-expansion/tools.js.map +1 -0
- package/dist/capabilities/citation-expansion/types.d.ts +22 -0
- package/dist/capabilities/citation-expansion/types.d.ts.map +1 -0
- package/dist/capabilities/citation-expansion/types.js +2 -0
- package/dist/capabilities/citation-expansion/types.js.map +1 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts +3 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.js +142 -0
- package/dist/capabilities/journal-metrics/JournalMetricsService.js.map +1 -0
- package/dist/capabilities/journal-metrics/handler.d.ts +12 -0
- package/dist/capabilities/journal-metrics/handler.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/handler.js +38 -0
- package/dist/capabilities/journal-metrics/handler.js.map +1 -0
- package/dist/capabilities/journal-metrics/index.d.ts +6 -0
- package/dist/capabilities/journal-metrics/index.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/index.js +5 -0
- package/dist/capabilities/journal-metrics/index.js.map +1 -0
- package/dist/capabilities/journal-metrics/schemas.d.ts +28 -0
- package/dist/capabilities/journal-metrics/schemas.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/schemas.js +13 -0
- package/dist/capabilities/journal-metrics/schemas.js.map +1 -0
- package/dist/capabilities/journal-metrics/tools.d.ts +67 -0
- package/dist/capabilities/journal-metrics/tools.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/tools.js +27 -0
- package/dist/capabilities/journal-metrics/tools.js.map +1 -0
- package/dist/capabilities/journal-metrics/types.d.ts +36 -0
- package/dist/capabilities/journal-metrics/types.d.ts.map +1 -0
- package/dist/capabilities/journal-metrics/types.js +2 -0
- package/dist/capabilities/journal-metrics/types.js.map +1 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts +9 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.js +81 -0
- package/dist/capabilities/metadata-search/MultiSourceSearchService.js.map +1 -0
- package/dist/capabilities/metadata-search/handler.d.ts +23 -0
- package/dist/capabilities/metadata-search/handler.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/handler.js +153 -0
- package/dist/capabilities/metadata-search/handler.js.map +1 -0
- package/dist/capabilities/metadata-search/index.d.ts +6 -0
- package/dist/capabilities/metadata-search/index.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/index.js +5 -0
- package/dist/capabilities/metadata-search/index.js.map +1 -0
- package/dist/capabilities/metadata-search/schemas.d.ts +83 -0
- package/dist/capabilities/metadata-search/schemas.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/schemas.js +80 -0
- package/dist/capabilities/metadata-search/schemas.js.map +1 -0
- package/dist/capabilities/metadata-search/tools.d.ts +178 -0
- package/dist/capabilities/metadata-search/tools.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/tools.js +75 -0
- package/dist/capabilities/metadata-search/tools.js.map +1 -0
- package/dist/capabilities/metadata-search/types.d.ts +13 -0
- package/dist/capabilities/metadata-search/types.d.ts.map +1 -0
- package/dist/capabilities/metadata-search/types.js +2 -0
- package/dist/capabilities/metadata-search/types.js.map +1 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.d.ts +43 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.js +2 -0
- package/dist/capabilities/pdf-discovery/DownloadTier.js.map +1 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts +16 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js +202 -0
- package/dist/capabilities/pdf-discovery/OpenAccessFallbackService.js.map +1 -0
- package/dist/capabilities/pdf-discovery/batch.d.ts +74 -0
- package/dist/capabilities/pdf-discovery/batch.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/batch.js +370 -0
- package/dist/capabilities/pdf-discovery/batch.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiAttempt.d.ts +7 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiAttempt.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiAttempt.js +46 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiAttempt.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiMcpClient.d.ts +35 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiMcpClient.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiMcpClient.js +689 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiMcpClient.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiProgress.d.ts +23 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiProgress.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiProgress.js +30 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiProgress.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiReadiness.d.ts +29 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiReadiness.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiReadiness.js +176 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiReadiness.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiResultNormalizer.d.ts +8 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiResultNormalizer.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiResultNormalizer.js +225 -0
- package/dist/capabilities/pdf-discovery/carsi/CarsiResultNormalizer.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/index.d.ts +8 -0
- package/dist/capabilities/pdf-discovery/carsi/index.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/index.js +11 -0
- package/dist/capabilities/pdf-discovery/carsi/index.js.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/types.d.ts +118 -0
- package/dist/capabilities/pdf-discovery/carsi/types.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/carsi/types.js +2 -0
- package/dist/capabilities/pdf-discovery/carsi/types.js.map +1 -0
- package/dist/capabilities/pdf-discovery/handler.d.ts +28 -0
- package/dist/capabilities/pdf-discovery/handler.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/handler.js +72 -0
- package/dist/capabilities/pdf-discovery/handler.js.map +1 -0
- package/dist/capabilities/pdf-discovery/identity.d.ts +8 -0
- package/dist/capabilities/pdf-discovery/identity.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/identity.js +24 -0
- package/dist/capabilities/pdf-discovery/identity.js.map +1 -0
- package/dist/capabilities/pdf-discovery/index.d.ts +8 -0
- package/dist/capabilities/pdf-discovery/index.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/index.js +6 -0
- package/dist/capabilities/pdf-discovery/index.js.map +1 -0
- package/dist/capabilities/pdf-discovery/oaHosts.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/oaHosts.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/oaHosts.js +37 -0
- package/dist/capabilities/pdf-discovery/oaHosts.js.map +1 -0
- package/dist/capabilities/pdf-discovery/pmcCloud.d.ts +6 -0
- package/dist/capabilities/pdf-discovery/pmcCloud.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/pmcCloud.js +95 -0
- package/dist/capabilities/pdf-discovery/pmcCloud.js.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/elsevier.d.ts +4 -0
- package/dist/capabilities/pdf-discovery/publisherApi/elsevier.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/elsevier.js +122 -0
- package/dist/capabilities/pdf-discovery/publisherApi/elsevier.js.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/index.d.ts +31 -0
- package/dist/capabilities/pdf-discovery/publisherApi/index.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/index.js +20 -0
- package/dist/capabilities/pdf-discovery/publisherApi/index.js.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/springer.d.ts +4 -0
- package/dist/capabilities/pdf-discovery/publisherApi/springer.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/publisherApi/springer.js +114 -0
- package/dist/capabilities/pdf-discovery/publisherApi/springer.js.map +1 -0
- package/dist/capabilities/pdf-discovery/schemas.d.ts +176 -0
- package/dist/capabilities/pdf-discovery/schemas.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/schemas.js +72 -0
- package/dist/capabilities/pdf-discovery/schemas.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts +5 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js +40 -0
- package/dist/capabilities/pdf-discovery/tiers/directPdfUrl.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/entitledAccess.d.ts +13 -0
- package/dist/capabilities/pdf-discovery/tiers/entitledAccess.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/entitledAccess.js +123 -0
- package/dist/capabilities/pdf-discovery/tiers/entitledAccess.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.js +21 -0
- package/dist/capabilities/pdf-discovery/tiers/primary.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/publisherApi.d.ts +12 -0
- package/dist/capabilities/pdf-discovery/tiers/publisherApi.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/publisherApi.js +109 -0
- package/dist/capabilities/pdf-discovery/tiers/publisherApi.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts +10 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.js +37 -0
- package/dist/capabilities/pdf-discovery/tiers/repositories.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.js +21 -0
- package/dist/capabilities/pdf-discovery/tiers/scihub.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts +3 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.js +76 -0
- package/dist/capabilities/pdf-discovery/tiers/unpaywall.js.map +1 -0
- package/dist/capabilities/pdf-discovery/tools.d.ts +337 -0
- package/dist/capabilities/pdf-discovery/tools.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/tools.js +144 -0
- package/dist/capabilities/pdf-discovery/tools.js.map +1 -0
- package/dist/capabilities/pdf-discovery/types.d.ts +86 -0
- package/dist/capabilities/pdf-discovery/types.d.ts.map +1 -0
- package/dist/capabilities/pdf-discovery/types.js +2 -0
- package/dist/capabilities/pdf-discovery/types.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +1196 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/ConfigService.d.ts +28 -0
- package/dist/config/ConfigService.d.ts.map +1 -0
- package/dist/config/ConfigService.js +204 -0
- package/dist/config/ConfigService.js.map +1 -0
- package/dist/config/ResultCaps.d.ts +4 -0
- package/dist/config/ResultCaps.d.ts.map +1 -0
- package/dist/config/ResultCaps.js +10 -0
- package/dist/config/ResultCaps.js.map +1 -0
- package/dist/config/constants.d.ts +158 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +102 -0
- package/dist/config/constants.js.map +1 -0
- package/dist/core/capabilityProfile.d.ts +2 -0
- package/dist/core/capabilityProfile.d.ts.map +1 -0
- package/dist/core/capabilityProfile.js +2 -0
- package/dist/core/capabilityProfile.js.map +1 -0
- package/dist/core/diagnostics.d.ts +2 -0
- package/dist/core/diagnostics.d.ts.map +1 -0
- package/dist/core/diagnostics.js +2 -0
- package/dist/core/diagnostics.js.map +1 -0
- package/dist/core/handleToolCall.d.ts +13 -0
- package/dist/core/handleToolCall.d.ts.map +1 -0
- package/dist/core/handleToolCall.js +304 -0
- package/dist/core/handleToolCall.js.map +1 -0
- package/dist/core/httpPolicies.d.ts +2 -0
- package/dist/core/httpPolicies.d.ts.map +1 -0
- package/dist/core/httpPolicies.js +2 -0
- package/dist/core/httpPolicies.js.map +1 -0
- package/dist/core/liveSmoke.d.ts +2 -0
- package/dist/core/liveSmoke.d.ts.map +1 -0
- package/dist/core/liveSmoke.js +2 -0
- package/dist/core/liveSmoke.js.map +1 -0
- package/dist/core/platformFactories.d.ts +2 -0
- package/dist/core/platformFactories.d.ts.map +1 -0
- package/dist/core/platformFactories.js +2 -0
- package/dist/core/platformFactories.js.map +1 -0
- package/dist/core/platformMetadata.d.ts +2 -0
- package/dist/core/platformMetadata.d.ts.map +1 -0
- package/dist/core/platformMetadata.js +2 -0
- package/dist/core/platformMetadata.js.map +1 -0
- package/dist/core/schemas.d.ts +365 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +256 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/searchers.d.ts +41 -0
- package/dist/core/searchers.d.ts.map +1 -0
- package/dist/core/searchers.js +24 -0
- package/dist/core/searchers.js.map +1 -0
- package/dist/core/textReports.d.ts +2 -0
- package/dist/core/textReports.d.ts.map +1 -0
- package/dist/core/textReports.js +2 -0
- package/dist/core/textReports.js.map +1 -0
- package/dist/core/tools.d.ts +7 -0
- package/dist/core/tools.d.ts.map +1 -0
- package/dist/core/tools.js +489 -0
- package/dist/core/tools.js.map +1 -0
- package/dist/infrastructure/cache/RequestCache.d.ts +26 -0
- package/dist/infrastructure/cache/RequestCache.d.ts.map +1 -0
- package/dist/infrastructure/cache/RequestCache.js +66 -0
- package/dist/infrastructure/cache/RequestCache.js.map +1 -0
- package/dist/infrastructure/http/ErrorHandler.d.ts +101 -0
- package/dist/infrastructure/http/ErrorHandler.d.ts.map +1 -0
- package/dist/infrastructure/http/ErrorHandler.js +278 -0
- package/dist/infrastructure/http/ErrorHandler.js.map +1 -0
- package/dist/infrastructure/http/HttpClient.d.ts +31 -0
- package/dist/infrastructure/http/HttpClient.d.ts.map +1 -0
- package/dist/infrastructure/http/HttpClient.js +52 -0
- package/dist/infrastructure/http/HttpClient.js.map +1 -0
- package/dist/infrastructure/pdf/PDFExtractor.d.ts +34 -0
- package/dist/infrastructure/pdf/PDFExtractor.d.ts.map +1 -0
- package/dist/infrastructure/pdf/PDFExtractor.js +130 -0
- package/dist/infrastructure/pdf/PDFExtractor.js.map +1 -0
- package/dist/infrastructure/pdf/PdfDownload.d.ts +16 -0
- package/dist/infrastructure/pdf/PdfDownload.d.ts.map +1 -0
- package/dist/infrastructure/pdf/PdfDownload.js +242 -0
- package/dist/infrastructure/pdf/PdfDownload.js.map +1 -0
- package/dist/infrastructure/pdf/PdfFirstPage.cjs +70 -0
- package/dist/infrastructure/pdf/PdfFirstPage.cjs.map +1 -0
- package/dist/infrastructure/pdf/PdfFirstPage.d.cts +16 -0
- package/dist/infrastructure/pdf/PdfFirstPage.d.cts.map +1 -0
- package/dist/infrastructure/pdf/PdfIdentity.d.ts +29 -0
- package/dist/infrastructure/pdf/PdfIdentity.d.ts.map +1 -0
- package/dist/infrastructure/pdf/PdfIdentity.js +283 -0
- package/dist/infrastructure/pdf/PdfIdentity.js.map +1 -0
- package/dist/infrastructure/rate-limit/RateLimiter.d.ts +50 -0
- package/dist/infrastructure/rate-limit/RateLimiter.d.ts.map +1 -0
- package/dist/infrastructure/rate-limit/RateLimiter.js +128 -0
- package/dist/infrastructure/rate-limit/RateLimiter.js.map +1 -0
- package/dist/infrastructure/runlog/RunLedger.d.ts +61 -0
- package/dist/infrastructure/runlog/RunLedger.d.ts.map +1 -0
- package/dist/infrastructure/runlog/RunLedger.js +284 -0
- package/dist/infrastructure/runlog/RunLedger.js.map +1 -0
- package/dist/infrastructure/runlog/failureClass.d.ts +26 -0
- package/dist/infrastructure/runlog/failureClass.d.ts.map +1 -0
- package/dist/infrastructure/runlog/failureClass.js +125 -0
- package/dist/infrastructure/runlog/failureClass.js.map +1 -0
- package/dist/infrastructure/security/SecurityUtils.d.ts +80 -0
- package/dist/infrastructure/security/SecurityUtils.d.ts.map +1 -0
- package/dist/infrastructure/security/SecurityUtils.js +357 -0
- package/dist/infrastructure/security/SecurityUtils.js.map +1 -0
- package/dist/management/capability-profile/carsiReadiness.d.ts +10 -0
- package/dist/management/capability-profile/carsiReadiness.d.ts.map +1 -0
- package/dist/management/capability-profile/carsiReadiness.js +13 -0
- package/dist/management/capability-profile/carsiReadiness.js.map +1 -0
- package/dist/management/capability-profile/index.d.ts +26 -0
- package/dist/management/capability-profile/index.d.ts.map +1 -0
- package/dist/management/capability-profile/index.js +183 -0
- package/dist/management/capability-profile/index.js.map +1 -0
- package/dist/management/carsi/host.d.ts +4 -0
- package/dist/management/carsi/host.d.ts.map +1 -0
- package/dist/management/carsi/host.js +65 -0
- package/dist/management/carsi/host.js.map +1 -0
- package/dist/management/carsi/installer.d.ts +146 -0
- package/dist/management/carsi/installer.d.ts.map +1 -0
- package/dist/management/carsi/installer.js +527 -0
- package/dist/management/carsi/installer.js.map +1 -0
- package/dist/management/carsi/runtime.d.ts +31 -0
- package/dist/management/carsi/runtime.d.ts.map +1 -0
- package/dist/management/carsi/runtime.js +67 -0
- package/dist/management/carsi/runtime.js.map +1 -0
- package/dist/management/config/index.d.ts +2 -0
- package/dist/management/config/index.d.ts.map +1 -0
- package/dist/management/config/index.js +2 -0
- package/dist/management/config/index.js.map +1 -0
- package/dist/management/diagnostics/index.d.ts +43 -0
- package/dist/management/diagnostics/index.d.ts.map +1 -0
- package/dist/management/diagnostics/index.js +610 -0
- package/dist/management/diagnostics/index.js.map +1 -0
- package/dist/management/failures/index.d.ts +47 -0
- package/dist/management/failures/index.d.ts.map +1 -0
- package/dist/management/failures/index.js +134 -0
- package/dist/management/failures/index.js.map +1 -0
- package/dist/management/reports/index.d.ts +32 -0
- package/dist/management/reports/index.d.ts.map +1 -0
- package/dist/management/reports/index.js +123 -0
- package/dist/management/reports/index.js.map +1 -0
- package/dist/management/skills/autoSync.d.ts +41 -0
- package/dist/management/skills/autoSync.d.ts.map +1 -0
- package/dist/management/skills/autoSync.js +142 -0
- package/dist/management/skills/autoSync.js.map +1 -0
- package/dist/management/skills/index.d.ts +3 -0
- package/dist/management/skills/index.d.ts.map +1 -0
- package/dist/management/skills/index.js +3 -0
- package/dist/management/skills/index.js.map +1 -0
- package/dist/management/smoke/index.d.ts +44 -0
- package/dist/management/smoke/index.d.ts.map +1 -0
- package/dist/management/smoke/index.js +254 -0
- package/dist/management/smoke/index.js.map +1 -0
- package/dist/models/Paper.d.ts +64 -0
- package/dist/models/Paper.d.ts.map +1 -0
- package/dist/models/Paper.js +70 -0
- package/dist/models/Paper.js.map +1 -0
- package/dist/platforms/ACMSearcher.d.ts +16 -0
- package/dist/platforms/ACMSearcher.d.ts.map +1 -0
- package/dist/platforms/ACMSearcher.js +125 -0
- package/dist/platforms/ACMSearcher.js.map +1 -0
- package/dist/platforms/BioRxivSearcher.d.ts +47 -0
- package/dist/platforms/BioRxivSearcher.d.ts.map +1 -0
- package/dist/platforms/BioRxivSearcher.js +215 -0
- package/dist/platforms/BioRxivSearcher.js.map +1 -0
- package/dist/platforms/CORESearcher.d.ts +17 -0
- package/dist/platforms/CORESearcher.d.ts.map +1 -0
- package/dist/platforms/CORESearcher.js +185 -0
- package/dist/platforms/CORESearcher.js.map +1 -0
- package/dist/platforms/CrossrefSearcher.d.ts +34 -0
- package/dist/platforms/CrossrefSearcher.d.ts.map +1 -0
- package/dist/platforms/CrossrefSearcher.js +339 -0
- package/dist/platforms/CrossrefSearcher.js.map +1 -0
- package/dist/platforms/DBLPSearcher.d.ts +16 -0
- package/dist/platforms/DBLPSearcher.d.ts.map +1 -0
- package/dist/platforms/DBLPSearcher.js +116 -0
- package/dist/platforms/DBLPSearcher.js.map +1 -0
- package/dist/platforms/EuropePMCSearcher.d.ts +20 -0
- package/dist/platforms/EuropePMCSearcher.d.ts.map +1 -0
- package/dist/platforms/EuropePMCSearcher.js +173 -0
- package/dist/platforms/EuropePMCSearcher.js.map +1 -0
- package/dist/platforms/GoogleScholarSearcher.d.ts +142 -0
- package/dist/platforms/GoogleScholarSearcher.d.ts.map +1 -0
- package/dist/platforms/GoogleScholarSearcher.js +648 -0
- package/dist/platforms/GoogleScholarSearcher.js.map +1 -0
- package/dist/platforms/IACRSearcher.d.ts +51 -0
- package/dist/platforms/IACRSearcher.d.ts.map +1 -0
- package/dist/platforms/IACRSearcher.js +339 -0
- package/dist/platforms/IACRSearcher.js.map +1 -0
- package/dist/platforms/IEEESearcher.d.ts +15 -0
- package/dist/platforms/IEEESearcher.d.ts.map +1 -0
- package/dist/platforms/IEEESearcher.js +123 -0
- package/dist/platforms/IEEESearcher.js.map +1 -0
- package/dist/platforms/OpenAIRESearcher.d.ts +22 -0
- package/dist/platforms/OpenAIRESearcher.d.ts.map +1 -0
- package/dist/platforms/OpenAIRESearcher.js +235 -0
- package/dist/platforms/OpenAIRESearcher.js.map +1 -0
- package/dist/platforms/OpenAlexSearcher.d.ts +14 -0
- package/dist/platforms/OpenAlexSearcher.d.ts.map +1 -0
- package/dist/platforms/OpenAlexSearcher.js +114 -0
- package/dist/platforms/OpenAlexSearcher.js.map +1 -0
- package/dist/platforms/OpenReviewSearcher.d.ts +19 -0
- package/dist/platforms/OpenReviewSearcher.d.ts.map +1 -0
- package/dist/platforms/OpenReviewSearcher.js +141 -0
- package/dist/platforms/OpenReviewSearcher.js.map +1 -0
- package/dist/platforms/PMCSearcher.d.ts +20 -0
- package/dist/platforms/PMCSearcher.d.ts.map +1 -0
- package/dist/platforms/PMCSearcher.js +177 -0
- package/dist/platforms/PMCSearcher.js.map +1 -0
- package/dist/platforms/PaperSource.d.ts +149 -0
- package/dist/platforms/PaperSource.d.ts.map +1 -0
- package/dist/platforms/PaperSource.js +125 -0
- package/dist/platforms/PaperSource.js.map +1 -0
- package/dist/platforms/PubMedSearcher.d.ts +104 -0
- package/dist/platforms/PubMedSearcher.d.ts.map +1 -0
- package/dist/platforms/PubMedSearcher.js +430 -0
- package/dist/platforms/PubMedSearcher.js.map +1 -0
- package/dist/platforms/SciHubSearcher.d.ts +66 -0
- package/dist/platforms/SciHubSearcher.d.ts.map +1 -0
- package/dist/platforms/SciHubSearcher.js +398 -0
- package/dist/platforms/SciHubSearcher.js.map +1 -0
- package/dist/platforms/ScienceDirectSearcher.d.ts +42 -0
- package/dist/platforms/ScienceDirectSearcher.d.ts.map +1 -0
- package/dist/platforms/ScienceDirectSearcher.js +334 -0
- package/dist/platforms/ScienceDirectSearcher.js.map +1 -0
- package/dist/platforms/ScopusSearcher.d.ts +43 -0
- package/dist/platforms/ScopusSearcher.d.ts.map +1 -0
- package/dist/platforms/ScopusSearcher.js +377 -0
- package/dist/platforms/ScopusSearcher.js.map +1 -0
- package/dist/platforms/SemanticScholarSearcher.d.ts +96 -0
- package/dist/platforms/SemanticScholarSearcher.d.ts.map +1 -0
- package/dist/platforms/SemanticScholarSearcher.js +419 -0
- package/dist/platforms/SemanticScholarSearcher.js.map +1 -0
- package/dist/platforms/SpringerSearcher.d.ts +54 -0
- package/dist/platforms/SpringerSearcher.d.ts.map +1 -0
- package/dist/platforms/SpringerSearcher.js +387 -0
- package/dist/platforms/SpringerSearcher.js.map +1 -0
- package/dist/platforms/USENIXSearcher.d.ts +14 -0
- package/dist/platforms/USENIXSearcher.d.ts.map +1 -0
- package/dist/platforms/USENIXSearcher.js +75 -0
- package/dist/platforms/USENIXSearcher.js.map +1 -0
- package/dist/platforms/UnpaywallSearcher.d.ts +29 -0
- package/dist/platforms/UnpaywallSearcher.d.ts.map +1 -0
- package/dist/platforms/UnpaywallSearcher.js +135 -0
- package/dist/platforms/UnpaywallSearcher.js.map +1 -0
- package/dist/platforms/WebOfScienceSearcher.d.ts +111 -0
- package/dist/platforms/WebOfScienceSearcher.d.ts.map +1 -0
- package/dist/platforms/WebOfScienceSearcher.js +500 -0
- package/dist/platforms/WebOfScienceSearcher.js.map +1 -0
- package/dist/registry/aliases.d.ts +2 -0
- package/dist/registry/aliases.d.ts.map +1 -0
- package/dist/registry/aliases.js +2 -0
- package/dist/registry/aliases.js.map +1 -0
- package/dist/registry/httpPolicies.d.ts +3 -0
- package/dist/registry/httpPolicies.d.ts.map +1 -0
- package/dist/registry/httpPolicies.js +13 -0
- package/dist/registry/httpPolicies.js.map +1 -0
- package/dist/registry/platformFactories.d.ts +8 -0
- package/dist/registry/platformFactories.d.ts.map +1 -0
- package/dist/registry/platformFactories.js +51 -0
- package/dist/registry/platformFactories.js.map +1 -0
- package/dist/registry/platformMetadata.d.ts +55 -0
- package/dist/registry/platformMetadata.d.ts.map +1 -0
- package/dist/registry/platformMetadata.js +438 -0
- package/dist/registry/platformMetadata.js.map +1 -0
- package/dist/services/CitationService.d.ts +3 -0
- package/dist/services/CitationService.d.ts.map +1 -0
- package/dist/services/CitationService.js +2 -0
- package/dist/services/CitationService.js.map +1 -0
- package/dist/services/JournalMetricsService.d.ts +3 -0
- package/dist/services/JournalMetricsService.d.ts.map +1 -0
- package/dist/services/JournalMetricsService.js +2 -0
- package/dist/services/JournalMetricsService.js.map +1 -0
- package/dist/services/MultiSourceSearchService.d.ts +3 -0
- package/dist/services/MultiSourceSearchService.d.ts.map +1 -0
- package/dist/services/MultiSourceSearchService.js +2 -0
- package/dist/services/MultiSourceSearchService.js.map +1 -0
- package/dist/services/OpenAccessFallbackService.d.ts +4 -0
- package/dist/services/OpenAccessFallbackService.d.ts.map +1 -0
- package/dist/services/OpenAccessFallbackService.js +2 -0
- package/dist/services/OpenAccessFallbackService.js.map +1 -0
- package/dist/skills/SkillInstaller.d.ts +110 -0
- package/dist/skills/SkillInstaller.d.ts.map +1 -0
- package/dist/skills/SkillInstaller.js +393 -0
- package/dist/skills/SkillInstaller.js.map +1 -0
- package/dist/utils/ErrorHandler.d.ts +3 -0
- package/dist/utils/ErrorHandler.d.ts.map +1 -0
- package/dist/utils/ErrorHandler.js +3 -0
- package/dist/utils/ErrorHandler.js.map +1 -0
- package/dist/utils/HttpClient.d.ts +2 -0
- package/dist/utils/HttpClient.d.ts.map +1 -0
- package/dist/utils/HttpClient.js +2 -0
- package/dist/utils/HttpClient.js.map +1 -0
- package/dist/utils/Logger.d.ts +6 -0
- package/dist/utils/Logger.d.ts.map +1 -0
- package/dist/utils/Logger.js +26 -0
- package/dist/utils/Logger.js.map +1 -0
- package/dist/utils/PDFExtractor.d.ts +3 -0
- package/dist/utils/PDFExtractor.d.ts.map +1 -0
- package/dist/utils/PDFExtractor.js +3 -0
- package/dist/utils/PDFExtractor.js.map +1 -0
- package/dist/utils/PdfDownload.d.ts +2 -0
- package/dist/utils/PdfDownload.d.ts.map +1 -0
- package/dist/utils/PdfDownload.js +2 -0
- package/dist/utils/PdfDownload.js.map +1 -0
- package/dist/utils/QuotaManager.d.ts +32 -0
- package/dist/utils/QuotaManager.d.ts.map +1 -0
- package/dist/utils/QuotaManager.js +95 -0
- package/dist/utils/QuotaManager.js.map +1 -0
- package/dist/utils/RateLimiter.d.ts +2 -0
- package/dist/utils/RateLimiter.d.ts.map +1 -0
- package/dist/utils/RateLimiter.js +2 -0
- package/dist/utils/RateLimiter.js.map +1 -0
- package/dist/utils/RequestCache.d.ts +3 -0
- package/dist/utils/RequestCache.d.ts.map +1 -0
- package/dist/utils/RequestCache.js +3 -0
- package/dist/utils/RequestCache.js.map +1 -0
- package/dist/utils/SecurityUtils.d.ts +3 -0
- package/dist/utils/SecurityUtils.d.ts.map +1 -0
- package/dist/utils/SecurityUtils.js +3 -0
- package/dist/utils/SecurityUtils.js.map +1 -0
- package/package.json +118 -4
- package/skills/paper-search/SKILL.md +151 -0
- package/skills/paper-search/references/browser-download.md +101 -0
- package/skills/paper-search/references/capability-routing.md +174 -0
- package/skills/paper-search/references/carsi-setup.md +69 -0
- package/skills/paper-search/references/cli-contract.md +200 -0
- package/skills/paper-search/references/management-layer.md +149 -0
- package/skills/paper-search/references/publisher-support.md +72 -0
- package/skills/paper-search/references/troubleshooting.md +15 -0
package/README.zh.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# PaperSearch
|
|
2
|
+
|
|
3
|
+
简体中文 | [English](README.md)
|
|
4
|
+
|
|
5
|
+
PaperSearch 是给 AI 工具和终端用的学术文献命令 `paper-search`,随包附带一份 Skill,教 Claude Code、Codex、Cursor 等 AI 工具怎么调用它。它能检索论文、核验 DOI/PMID、查施引文献和参考文献、查期刊影响因子和分区、在正文片段里找方法学写法,以及下载论文 PDF 和补充材料。输出默认是 JSON,方便 AI 和脚本读取。
|
|
6
|
+
|
|
7
|
+
默认是开放版本:装好就能检索和下载开放获取的论文。需要用学校订阅下载时,可以另装机构下载扩展。
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+
[](https://linux.do)
|
|
13
|
+
|
|
14
|
+
[整体逻辑](#整体逻辑) | [快速开始](#快速开始) | [两种下载方式](#两种下载方式) | [检索来源](#检索来源) | [配置](#配置) | [Agent Skill](#agent-skill) | [命令](#命令) | [排障](#排障)
|
|
15
|
+
|
|
16
|
+
## 整体逻辑
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
用户的文献请求
|
|
20
|
+
│
|
|
21
|
+
├─ 找论文、核验 DOI/PMID → paper-search search(Crossref、PubMed、OpenAlex 等)
|
|
22
|
+
│ └─ 确认条目、需要全文 → 转到下面的“下载”
|
|
23
|
+
├─ 查施引文献、参考文献 → paper-search run get_paper_citations / get_paper_references
|
|
24
|
+
├─ 查影响因子、分区 → paper-search journal-metrics(需要 EasyScholar key)
|
|
25
|
+
├─ 找 Methods 写法、参数 → paper-search run search_semantic_snippets(需要 Semantic Scholar key)
|
|
26
|
+
│
|
|
27
|
+
└─ 下载正文、补充材料 → paper-search download / run download_with_fallback / run download_batch
|
|
28
|
+
同一个下载命令,按顺序尝试:
|
|
29
|
+
├─ ① 开放下载(默认就有):来源自带的下载、PMC、Unpaywall、出版社接口
|
|
30
|
+
├─ ② Sci-Hub 兜底(默认开启,可关闭)
|
|
31
|
+
├─ ③ 机构下载(可选扩展):浏览器经 CARSI 登录你的学校,在出版社网站取 PDF 和补充材料
|
|
32
|
+
├─ 每一步拿到文件都核对首页的 DOI 和题名;通过就保存,后面的步骤不再试
|
|
33
|
+
└─ 都没拿到 → paper-search failures 说明原因
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 快速开始
|
|
37
|
+
|
|
38
|
+
要求 Node.js 18 及以上和 npm。
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install -g papersearch
|
|
42
|
+
paper-search setup
|
|
43
|
+
paper-search doctor --format text
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`paper-search setup` 会依次问三件事:API key 和邮箱;要把 Skill 装到哪些 AI 工具(Claude Code、Codex、Cursor 等);要不要安装机构下载扩展。每一步都可以跳过。`doctor` 显示现在能用哪些功能、还缺什么配置。
|
|
47
|
+
|
|
48
|
+
Skill 是教 AI 工具调用 `paper-search` 的说明文件,用 AI 工具做文献任务时要装。跳过了可以随时补装,`--targets` 换成你用的工具(`claude`、`codex`、`cursor`、`gemini`、`agents`,或 `all`):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
paper-search skills update --targets claude
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
也可以把下面这段话发给你的 AI 工具,让它帮你装:
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
请帮我安装 PaperSearch:运行 npm install -g papersearch,再运行 paper-search skills update --targets <你自己对应的目标:Claude Code 用 claude,Codex 用 codex,Cursor 用 cursor>,最后运行 paper-search doctor --format text,告诉我哪些功能能用、还缺哪些 key。API key 我会自己在终端运行 paper-search setup 输入,不要让我发到聊天里。
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**从旧包 `paper-search-cli` 升级**:先运行 `npm uninstall -g paper-search-cli`,再 `npm install -g papersearch`。两个包提供同一个 `paper-search` 命令,不能同时装;配置、Skill、学校登录和下载记录都会保留。
|
|
61
|
+
|
|
62
|
+
**以后升级**:`npm install -g papersearch@latest`。升级后第一次运行 `paper-search` 时,它会自动把你装过的 Skill 更新到新版本。
|
|
63
|
+
|
|
64
|
+
试一下各个功能:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
paper-search search "machine learning clinical prediction" --platform crossref --max-results 3 --pretty
|
|
68
|
+
paper-search search "large language models" --sources no-key --max-results 5 --pretty
|
|
69
|
+
paper-search run get_paper_citations --arg doi="10.1038/nature12373" --arg limit=5 --pretty
|
|
70
|
+
paper-search journal-metrics "Nature" "BMJ" --pretty
|
|
71
|
+
paper-search download PMC11466435 --platform pmc --save-path ./downloads
|
|
72
|
+
paper-search run search_semantic_snippets --arg query="propensity score matching" --arg limit=3 --pretty
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 两种下载方式
|
|
76
|
+
|
|
77
|
+
| | 开放下载(默认) | 机构下载(可选扩展) |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| 能不能直接用 | 装好就能用 | 要另外安装:`paper-search carsi install` |
|
|
80
|
+
| 能拿到什么 | 开放获取的正文 | 你的学校订阅的正文;部分出版社还能取补充材料 |
|
|
81
|
+
| 怎么拿 | 程序直接下载,通常几秒,不用登录:来源自带的下载、元数据里的 PDF 地址、PubMed Central、Unpaywall、出版社接口(你自己的 Elsevier/Springer key);最后是默认开启的 Sci-Hub 兜底 | 打开一个浏览器,经 CARSI 登录你的学校,在出版社网站上取 PDF |
|
|
82
|
+
| 你要做的事 | 无 | 第一次在浏览器里输入学校账号密码、遇到人机验证时点一下;选学校由程序完成 |
|
|
83
|
+
|
|
84
|
+
两种方式用同一个下载命令,不需要分开调用:先试开放下载,拿不到时,装了机构下载才继续用学校权限。
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
paper-search download "<DOI>" --platform crossref --save-path ./downloads
|
|
88
|
+
paper-search run download_batch --json-args '{"items":[{"doi":"<DOI-1>"},{"doi":"<DOI-2>"}],"savePath":"./downloads"}'
|
|
89
|
+
paper-search failures --format text
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
- 几十到几百篇用一次 `download_batch`;结束后 `paper-search failures` 把没下载到的篇目分成四类说明:没权限(附页面原话等依据)、需要你处理(登录、验证、等待)、暂不支持的网站、原因不明。
|
|
93
|
+
- 不想用 Sci-Hub 时,在 `download_with_fallback` / `download_batch` 里设 `"useSciHub": false`。
|
|
94
|
+
- 每个保存的 PDF 都核对首页的 DOI 和题名,不是这篇文章的不保存。
|
|
95
|
+
|
|
96
|
+
### 机构下载扩展
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
paper-search carsi install
|
|
100
|
+
paper-search carsi status --format text
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- 安装时会问你的学校(CARSI 成员学校,中文名、英文名或域名都可以),并下载专用浏览器 Camoufox,共约 3 GB;macOS 上 `--browser ego` 改用 ego lite,约 0.5 GB。`--skip-school` 可以以后再选学校。
|
|
104
|
+
- 目前用 CARSI(中国高校身份联盟)登录学校;出版社的机构列表里没有 CARSI 或你的学校时,程序会立即说明,建议在校园网或学校 VPN 下下载。
|
|
105
|
+
- 下载时会出现进度窗口:可以跳过本篇、标记本刊或出版社无权限、终止整个任务,右上角齿轮可以调整等待时间。停在学校登录页默认最多等 3 分钟,停在其他页面(人机验证、出版社页面等)默认 1 分钟后结束这一篇。
|
|
106
|
+
- `paper-search carsi update` 在 PaperSearch 升级后更新扩展,`paper-search carsi uninstall` 卸载(默认保留浏览器和学校配置)。
|
|
107
|
+
- Windows:PowerShell 拦住 `npm.ps1` 时改用 `npm.cmd` 或命令提示符;下载要在桌面会话里运行,经 SSH 或系统服务启动时浏览器窗口打不开。
|
|
108
|
+
|
|
109
|
+
### 补充材料
|
|
110
|
+
|
|
111
|
+
`download_with_fallback` / `download_batch` 的 `content` 选择下载内容:`main`(默认,只要正文)、`both`(正文加补充材料)、`supplements`(只要补充材料)。补充材料只经机构下载取得,存在 `<保存目录>/<DOI>_supplements/`,附 `manifest.json` 写明每个文件的状态。
|
|
112
|
+
|
|
113
|
+
各出版社能不能下正文、能不能下补充材料,见 [出版社支持表](skills/paper-search/references/publisher-support.md)。正文和补充材料都实测取得的有 Elsevier、Wiley、Springer Nature、OUP、Wolters Kluwer、Taylor & Francis、Sage、ACS、NEJM、ASCE、Dove 等;IEEE、Thieme 等目前只取正文;表里没有的网站按通用规则尝试。
|
|
114
|
+
|
|
115
|
+
## 检索来源
|
|
116
|
+
|
|
117
|
+
| 类别 | 来源 | 需要的配置 |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| 综合学术元数据 | Crossref、OpenAlex、Semantic Scholar、Google Scholar | 不需要;Semantic Scholar 的正文片段检索需要 key;Google Scholar 要明确指定 |
|
|
120
|
+
| 生物医学 | PubMed、PubMed Central、Europe PMC | 可选 PubMed key |
|
|
121
|
+
| 预印本和会议稿 | bioRxiv、medRxiv、OpenReview、IACR ePrint | 不需要 |
|
|
122
|
+
| 计算机和工程 | DBLP、ACM、USENIX、IEEE Xplore | IEEE 需要 key |
|
|
123
|
+
| 开放获取和仓储 | CORE、OpenAIRE、Unpaywall | Unpaywall 需要邮箱;CORE key 可选 |
|
|
124
|
+
| 引文库和出版社 | Web of Science、Scopus、ScienceDirect、Springer Nature | 需要各自的 key;只提供元数据(Elsevier、Springer 的 key 也用于出版社接口取全文) |
|
|
125
|
+
| 期刊指标 | EasyScholar | 需要 EasyScholar key |
|
|
126
|
+
|
|
127
|
+
- 单个来源用 `--platform`,多个用 `--sources a,b,c`;`--sources no-key` 是不需要任何 key 的组合(Crossref、PubMed、Europe PMC、OpenReview)。
|
|
128
|
+
- Google Scholar 是网页解析,容易触发验证,不在 `--sources all` 里;需要时用 `--platform googlescholar`。
|
|
129
|
+
- Sci-Hub 不是检索来源,只在下载时按 DOI 兜底。
|
|
130
|
+
|
|
131
|
+
## 配置
|
|
132
|
+
|
|
133
|
+
多数免费来源不需要配置。建议先运行 `paper-search setup`,把 key 写入用户配置:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
paper-search setup
|
|
137
|
+
paper-search config list --pretty
|
|
138
|
+
paper-search config set SEMANTIC_SCHOLAR_API_KEY <你的 key>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
配置文件在 `~/.config/paper-search-cli/config.json`(权限 `0600`;文件夹沿用旧名,升级不丢设置),`config list` 和 `doctor` 会把 key 脱敏显示。
|
|
142
|
+
|
|
143
|
+
| 配置项 | 用途 | 什么时候配置 |
|
|
144
|
+
|---|---|---|
|
|
145
|
+
| `SEMANTIC_SCHOLAR_API_KEY` | 正文片段检索,更稳定的 Semantic Scholar 请求 | 要查方法细节,或经常用 Semantic Scholar |
|
|
146
|
+
| `UNPAYWALL_EMAIL` | 按 DOI 找开放获取 PDF | 推荐配置;填邮箱即可 |
|
|
147
|
+
| `CROSSREF_MAILTO` | Crossref 优先通道 | 长任务或高频检索 |
|
|
148
|
+
| `CORE_API_KEY` | CORE 仓储检索 | 经常用 CORE 或遇到限流 |
|
|
149
|
+
| `EASYSCHOLAR_KEY` | 期刊指标 | 要查影响因子、分区;用 `paper-search setup EASYSCHOLAR_KEY` 隐藏输入 |
|
|
150
|
+
| `PUBMED_API_KEY`、`NCBI_EMAIL` | PubMed 更高限额 | 经常用 PubMed |
|
|
151
|
+
| `WOS_API_KEY`、`IEEE_API_KEY`、`ELSEVIER_API_KEY`、`SPRINGER_API_KEY` | 各自的元数据;Elsevier、Springer 的 key 也用于出版社接口取全文(权限跟随你的网络或 key) | 要用对应来源时 |
|
|
152
|
+
| `ELSEVIER_INSTTOKEN` | 校外经 Elsevier 接口取全文 | 校外需要全文时;校园网不需要 |
|
|
153
|
+
| `GOOGLE_SCHOLAR_PROXY_URL` | Google Scholar 的出口代理 | 直连反复被拦时,用有授权的代理 |
|
|
154
|
+
| `PAPER_SEARCH_CARSI_ENABLED` | 机构下载扩展的开关 | `paper-search carsi install` 自动设置 |
|
|
155
|
+
| `PAPER_SEARCH_SKILL_AUTO_UPDATE` | 设为 `false` 时,升级后不再自动更新已安装的 Skill | 默认开启,想自己管理 Skill 时设置 |
|
|
156
|
+
|
|
157
|
+
申请入口:[EasyScholar](https://www.easyscholar.cc/console/user/open) · [Semantic Scholar](https://www.semanticscholar.org/product/api) · [Unpaywall](https://unpaywall.org/products/api) · [CORE](https://core.ac.uk/services/api) · [NCBI](https://ncbiinsights.ncbi.nlm.nih.gov/2017/11/02/new-api-keys-for-the-e-utilities/) · [Web of Science](https://developer.clarivate.com/apis) · [IEEE Xplore](https://developer.ieee.org/docs/read/Searching_the_IEEE_Xplore_Metadata_API) · [Elsevier](https://dev.elsevier.com/apikey/manage) · [Springer Nature](https://dev.springernature.com/) · [OpenAIRE](https://develop.openaire.eu/)
|
|
158
|
+
|
|
159
|
+
## Agent Skill
|
|
160
|
+
|
|
161
|
+
Skill 随 npm 包发布(`skills/paper-search/`),全中文,开头有整体逻辑图,按需读这些参考文件:功能路由与开放下载的各个渠道、命令约定、机构下载的安装和使用、[出版社支持表](skills/paper-search/references/publisher-support.md)、排障。它只告诉 AI 怎么调用 `paper-search`,不保存 key、Cookie 或账号。
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
paper-search skills status --pretty
|
|
165
|
+
paper-search skills update --targets claude
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
- 支持的目标:`agents`、`codex`、`claude`、`cursor`、`gemini`、`antigravity`、`all`。更新会覆盖包里管理的文件,保留你在 Skill 目录里自己加的文件。
|
|
169
|
+
- **升级后自动更新**:升级 PaperSearch 后第一次运行 `paper-search`(`skills`、`setup` 除外)时,它把你已经装过的 Skill 更新到新版本:只更新原来装过的位置;被替换的旧文件备份在 `~/.local/share/paper-search-cli/skill-backups/`;并在 stderr 写一行说明。一个都没装时只提示一次怎么装。不想自动更新:`paper-search config set PAPER_SEARCH_SKILL_AUTO_UPDATE false`。
|
|
170
|
+
- `paper-search doctor` 显示 Skill 装在哪里、是否最新。
|
|
171
|
+
|
|
172
|
+
## 命令
|
|
173
|
+
|
|
174
|
+
| 命令 | 用途 |
|
|
175
|
+
|---|---|
|
|
176
|
+
| `paper-search search` | 检索论文元数据 |
|
|
177
|
+
| `paper-search journal-metrics` | 期刊指标(EasyScholar) |
|
|
178
|
+
| `paper-search download` | 下载已核验论文的 PDF |
|
|
179
|
+
| `paper-search run <工具>` | 精确调用某个工具,参数用 `--arg` 或 `--json-args` |
|
|
180
|
+
| `paper-search failures` | 汇总下载失败的原因 |
|
|
181
|
+
| `paper-search carsi` | 机构下载扩展的安装、状态、更新、卸载 |
|
|
182
|
+
| `paper-search setup` / `config` | 配置 key、Skill 和扩展 |
|
|
183
|
+
| `paper-search doctor` | 健康检查:配置、可用功能、Skill 和扩展的状态 |
|
|
184
|
+
| `paper-search skills` | Skill 的状态、差异和更新 |
|
|
185
|
+
| `paper-search smoke` | 离线或真实的自检 |
|
|
186
|
+
| `paper-search tools` | 列出所有工具名和参数 |
|
|
187
|
+
|
|
188
|
+
命令默认输出 JSON,`--pretty` 排版,`--format text` 输出给人看的报告。完整命令见 `paper-search tools --pretty` 或 [命令约定](skills/paper-search/references/cli-contract.md)。
|
|
189
|
+
|
|
190
|
+
## 排障
|
|
191
|
+
|
|
192
|
+
| 问题 | 怎么办 |
|
|
193
|
+
|---|---|
|
|
194
|
+
| 找不到 `paper-search` 命令 | `npm install -g papersearch` 重新安装 |
|
|
195
|
+
| 安装时报 `EEXIST` | 旧包还在:先 `npm uninstall -g paper-search-cli` |
|
|
196
|
+
| 某个功能不能用 | `paper-search doctor --format text` 看缺什么,再 `paper-search setup` 配置 |
|
|
197
|
+
| 学校订阅的文章下载不到 | `paper-search carsi status --format text` 看扩展是否装好;`paper-search failures --format text` 看每篇的原因 |
|
|
198
|
+
| 来源限流 | 减小 `--max-results`、配置对应 key,或换来源 |
|
|
199
|
+
| Google Scholar 出验证页 | 等一会儿再试,或改用 `--sources no-key` |
|
|
200
|
+
| AI 读到的 Skill 是旧的 | `paper-search skills status --pretty`,再 `paper-search skills update --targets <工具>`;新开一个 AI 会话 |
|
|
201
|
+
|
|
202
|
+
## 使用边界
|
|
203
|
+
|
|
204
|
+
部分来源受平台条款、机构订阅或当地法律约束,只在你有相应访问权时使用。机构下载用的是你自己的学校账号和订阅;结果里的来源标记只用于诊断,不能当作授权证明。
|
|
205
|
+
|
|
206
|
+
## 项目来源
|
|
207
|
+
|
|
208
|
+
- 感谢 [LinuxDo](https://linux.do) 社区:命令 + Skill 的路线和工作流改进来自社区交流与开源分享。
|
|
209
|
+
- [openags/paper-search-mcp](https://github.com/openags/paper-search-mcp):本项目参考了它的思路,并改成独立的命令行工具。
|
|
210
|
+
- [Rimagination/scansci-pdf](https://github.com/Rimagination/scansci-pdf)(MIT):机构下载后端(`carsi/`)由它裁出,只保留机构访问这一段(CARSI 等联盟登录、出版社网站抓取、会话复用、PDF 捕获),再逐家补充出版社规则;原项目的版权声明保留在 `carsi/NOTICE`。
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
package/carsi/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 scansci-pdf contributors
|
|
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.
|
package/carsi/NOTICE
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
paper-search-carsi
|
|
2
|
+
Derived from scansci-pdf (https://github.com/Rimagination/scansci-pdf), MIT License,
|
|
3
|
+
copyright (c) 2024-2026 scansci-pdf contributors. Base: upstream commit f3dbb66 plus the
|
|
4
|
+
maintainer's single-download candidate patches of 2026-10-27/28. Only the institutional
|
|
5
|
+
access phase was kept; public/OA/grey sources, search, batch, Tor and Zotero were removed.
|
package/carsi/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# paper-search-carsi
|
|
2
|
+
|
|
3
|
+
PaperSearch 的机构授权 PDF 下载后端,从 scansci-pdf 裁出,只保留"机构访问"这一段:CARSI 等联盟入口、出版社浏览器抓取、会话复用、PDF 捕获。公开/OA 来源、灰色来源、搜索、批量、Tor、Zotero 都不在这里,那些由 PaperSearch 自己负责。WebVPN、EZProxy(经学校的网关或代理用学校 IP)也不在这里:代码暂存在仓库根目录 `campus-proxy/`,未接入。
|
|
4
|
+
|
|
5
|
+
状态:**MCP server、编排和 CLI 已接通,PaperSearch `doctor` 握手通过;真实机构下载尚待逐出版社验收。**
|
|
6
|
+
|
|
7
|
+
## 安装与浏览器后端
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
python3 -m venv .venv
|
|
11
|
+
.venv/bin/pip install -e ".[camoufox]"
|
|
12
|
+
.venv/bin/python -m camoufox fetch # 下载 Camoufox 浏览器本体(约 0.5 GB 压缩包)
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`bin/paper-search-carsi` 优先使用仓库内的 `.venv`(可用 `CARSI_PYTHON` 指定其他解释器)。
|
|
16
|
+
|
|
17
|
+
浏览器后端二选一,配置键 `browser_backend`:
|
|
18
|
+
|
|
19
|
+
- `camoufox`(默认):开源反指纹 Firefox,经 Playwright 自动化,全部浏览器路线都用它。持久化配置目录是原目录旁的 `-camoufox` 兄弟目录,首次使用需要重新登录一次机构。
|
|
20
|
+
- `ego`(需要 agent 接手你正在用的浏览器时选用):直接使用你日常运行的 ego-lite(Chromium 内核),Playwright 经 CDP 接管,沿用其中已有的登录;规则与适配器和 camoufox 同一套。在 ego 里打开 `chrome://inspect/#remote-debugging` 勾选 "Allow remote debugging for this browser instance",勾选一次即保存在 ego 设置中,重启后仍有效;程序只操作并关闭自己开的标签页,不关闭浏览器,也不写入 Cookie。ego 的数据目录可用 `ego_user_data_dir` 指定;未安装 ego-lite 时自动回到 camoufox。
|
|
21
|
+
|
|
22
|
+
旧值 `patchright`、`cloakbrowser` 会记一条警告并按 `camoufox` 处理。
|
|
23
|
+
|
|
24
|
+
## 使用
|
|
25
|
+
|
|
26
|
+
等待用户操作:停在学校登录页(以及没配置学校时的选校页)每篇最多 3 分钟(配置键 `browser_login_timeout`,秒,默认 180);停在其他页面(人机验证、出版社页面、选机构页、取 PDF 时等待处理)连续超过 1 分钟就结束这一篇(`browser_page_wait_timeout`,默认 60)。两项和每家出版社每小时最多下载篇数都能在进度窗口右上角的设置(齿轮)里改。浏览器某一步 90 秒没有响应时,这一篇以 `browser_unresponsive` 结束。进度窗口的按钮:跳过本篇、本刊无权限、出版社无权限、终止任务(整批停下,剩余篇目记为 `batch_stopped`)、⚑ 报告问题。
|
|
27
|
+
|
|
28
|
+
浏览器调用超过 4 分钟没有返回时,后端会取消它并把这一篇记为 `browser_unresponsive`(日志里记下是哪个调用、从哪里调用),批量继续下一篇。后端一直停着不动(CPU 为 0、进度不再更新)时,`kill -USR1 <后端进程号>` 会把它所有线程的 Python 调用栈追加到 `<数据目录>/logs/stacks-<日期>.txt`,用来看它在等哪个浏览器调用;进程不会因此退出。
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# 1. 选择机构入口:用 --institution 配置自己的学校(CARSI 成员学校的中文名、英文名或域名,在 CARSI 学校列表里查找后保存中英文名和 entityID),之后各出版社的选校页由程序自动选中(只点与它对应的那一项);不配置则在登录窗口里手选
|
|
32
|
+
paper-search-carsi setup --carsi # 或 --carsi --institution "学校名"
|
|
33
|
+
paper-search-carsi setup --list-carsi-schools 关键词 # 查 CARSI 成员学校
|
|
34
|
+
paper-search-carsi setup --check # 环境检查:数据目录、浏览器后端、入口是否配置
|
|
35
|
+
|
|
36
|
+
# 2. 在弹出的浏览器窗口完成一次机构登录(凭证只在窗口里输入,CLI 不经手)
|
|
37
|
+
paper-search-carsi login --doi 10.1016/... # 打开这篇文章的出版社页面,在出版社的机构登录里选学校(CARSI)
|
|
38
|
+
paper-search-carsi login --publisher elsevier # 没有 DOI 时打开出版社首页
|
|
39
|
+
|
|
40
|
+
# 3. 让 PaperSearch 用它(专属数据目录与上面保持一致)
|
|
41
|
+
paper-search config set PAPER_SEARCH_CARSI_EXECUTABLE /path/to/paper-search-carsi
|
|
42
|
+
paper-search config set PAPER_SEARCH_CARSI_ENABLED true
|
|
43
|
+
paper-search doctor --pretty
|
|
44
|
+
|
|
45
|
+
# 另一个终端里查看当前任务进度(只读)
|
|
46
|
+
paper-search-carsi progress --json --watch
|
|
47
|
+
|
|
48
|
+
# 贡献者自检:跑一篇受限 DOI 并输出脱敏报告
|
|
49
|
+
paper-search-carsi publisher-check --doi 10.1016/...
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`CARSI_DATA_DIR` 决定数据目录;PaperSearch 默认用 `$XDG_DATA_HOME/paper-search-cli/carsi`,运行上面的 setup/login 时要导出同一个值。
|
|
53
|
+
|
|
54
|
+
## 三级结构
|
|
55
|
+
|
|
56
|
+
```text
|
|
57
|
+
paper_search_carsi/
|
|
58
|
+
├── publishers/ tier 1 声明式出版社规则:builtin/*.json + schema.json + 用户 publisher_profiles_file
|
|
59
|
+
├── adapters/ tier 2 出版社适配器(Python):一家一个目录,只写通用流程判断不了的钩子;platforms/ 是网站平台的共同规则(Atypon、Silverchair),出版社继承它;base.py 是基类与默认值
|
|
60
|
+
├── engine/ tier 3 机构入口:bridge(调度)/ batch(出版社浏览器抓取,含 CARSI 选校)/ router
|
|
61
|
+
├── browser/ 浏览器引擎、后端选择、登录等待、Cookie、预览
|
|
62
|
+
├── extractors/ PDF 响应提取
|
|
63
|
+
├── server.py MCP stdio:download / cache_clear / list_publishers
|
|
64
|
+
└── cli.py setup / login / publisher-check
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
谁可以贡献什么:
|
|
68
|
+
|
|
69
|
+
| 层 | 需要会什么 | 合并条件 |
|
|
70
|
+
| --- | --- | --- |
|
|
71
|
+
| tier 1 `publishers/builtin/<name>.json` | 不需要写代码 | 通过 `schema.json` 校验;附脱敏页面快照到 `tests/fixtures/publishers/<name>/` |
|
|
72
|
+
| tier 2 `adapters/<name>/` | Python,`PublisherAdapter` 子类 | 离线夹具测试;`publisher-check` 报告贴在 PR |
|
|
73
|
+
| tier 3 `engine/` | 熟悉学校认证流程 | 维护者审核 |
|
|
74
|
+
|
|
75
|
+
详见 CONTRIBUTING.md。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Optional Cython-accelerated core modules.
|
|
2
|
+
|
|
3
|
+
The .pyx sources live in this package and are MIT licensed. When Cython
|
|
4
|
+
is available they are compiled to .pyd/.so at build time; pure Python fallbacks
|
|
5
|
+
exist in the original modules.
|
|
6
|
+
|
|
7
|
+
Usage in other modules:
|
|
8
|
+
try:
|
|
9
|
+
from .racing import run_parallel_race
|
|
10
|
+
except ImportError:
|
|
11
|
+
# Pure Python fallback is used inline
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
# Individual compiled modules are imported directly by their callers via
|
|
15
|
+
# try/except; there is intentionally no package-level re-export layer.
|
|
16
|
+
|
|
17
|
+
def _check_availability() -> dict[str, bool]:
|
|
18
|
+
"""Check which compiled modules are available."""
|
|
19
|
+
status = {}
|
|
20
|
+
for mod_name in ("racing", "scihub_core"):
|
|
21
|
+
try:
|
|
22
|
+
__import__(f"paper_search_carsi._core.{mod_name}")
|
|
23
|
+
status[mod_name] = True
|
|
24
|
+
except ImportError:
|
|
25
|
+
status[mod_name] = False
|
|
26
|
+
return status
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# cython: language_level=3
|
|
2
|
+
"""Tiered parallel racing download engine.
|
|
3
|
+
|
|
4
|
+
This module implements the multi-source download strategy:
|
|
5
|
+
- 5-tier download architecture with tuned timeouts
|
|
6
|
+
- Fully parallel cross-tier racing with Event-based instant notification
|
|
7
|
+
- Thread-safe result publication and batch orchestration
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import threading
|
|
11
|
+
import time
|
|
12
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
# Tier definitions with tuned timeouts (seconds)
|
|
17
|
+
cdef int TIER_FLASH_TIMEOUT = 4
|
|
18
|
+
cdef int TIER_FAST_TIMEOUT = 5
|
|
19
|
+
cdef int TIER_OA_TIMEOUT = 8
|
|
20
|
+
cdef int TIER_GREY_TIMEOUT = 25
|
|
21
|
+
cdef int TIER_WEBVPN_TIMEOUT = 20
|
|
22
|
+
|
|
23
|
+
# Batch download tuning
|
|
24
|
+
cdef double BATCH_STAGGER_DELAY = 0.3
|
|
25
|
+
cdef int DEFAULT_BATCH_WORKERS = 10
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def run_parallel_race(
|
|
29
|
+
list all_sources,
|
|
30
|
+
str doi,
|
|
31
|
+
object target_dir,
|
|
32
|
+
object output_path,
|
|
33
|
+
dict config,
|
|
34
|
+
bint use_tor,
|
|
35
|
+
int overall_timeout,
|
|
36
|
+
try_source_fn,
|
|
37
|
+
safe_filename_fn,
|
|
38
|
+
logger,
|
|
39
|
+
) -> dict | None:
|
|
40
|
+
"""Race all sources in parallel across tiers. First success wins.
|
|
41
|
+
|
|
42
|
+
Uses a shared result dict with threading.Event for instant notification
|
|
43
|
+
when any source succeeds, even from nested parallel calls.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
all_sources: List of (fn, label, tier_label, timeout) tuples
|
|
47
|
+
doi: Paper DOI
|
|
48
|
+
target_dir: Directory for temp files
|
|
49
|
+
output_path: Final output path
|
|
50
|
+
config: Configuration dict
|
|
51
|
+
use_tor: Whether to use Tor
|
|
52
|
+
overall_timeout: Max seconds to wait
|
|
53
|
+
try_source_fn: Function to try a single source
|
|
54
|
+
safe_filename_fn: Function to create safe filename
|
|
55
|
+
logger: Logger instance
|
|
56
|
+
"""
|
|
57
|
+
if not all_sources:
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
cdef int n = len(all_sources)
|
|
61
|
+
|
|
62
|
+
# Single source - run directly without pool overhead
|
|
63
|
+
if n == 1:
|
|
64
|
+
fn, label, tier_label, timeout = all_sources[0]
|
|
65
|
+
src_output = target_dir / f"{safe_filename_fn(doi)}_{label}.pdf"
|
|
66
|
+
result = try_source_fn(fn, doi, src_output, config, label, use_tor=use_tor)
|
|
67
|
+
if result and result.get("success"):
|
|
68
|
+
_move_to_output(result, output_path)
|
|
69
|
+
return result
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
# Shared state for cross-thread result publication
|
|
73
|
+
result_lock = threading.Lock()
|
|
74
|
+
success_event = threading.Event()
|
|
75
|
+
cancel_event = threading.Event()
|
|
76
|
+
all_done_event = threading.Event()
|
|
77
|
+
done_counter = [0]
|
|
78
|
+
done_counter_lock = threading.Lock()
|
|
79
|
+
shared_result = {"result": None}
|
|
80
|
+
|
|
81
|
+
def _try_and_publish(fn, label, src_output):
|
|
82
|
+
if cancel_event.is_set():
|
|
83
|
+
return None
|
|
84
|
+
result = try_source_fn(fn, doi, src_output, config, label, use_tor=use_tor)
|
|
85
|
+
if result and result.get("success"):
|
|
86
|
+
with result_lock:
|
|
87
|
+
if shared_result["result"] is None:
|
|
88
|
+
shared_result["result"] = (result, label, src_output)
|
|
89
|
+
cancel_event.set()
|
|
90
|
+
success_event.set()
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
def _wait_any(timeout):
|
|
94
|
+
deadline = time.monotonic() + timeout
|
|
95
|
+
while time.monotonic() < deadline:
|
|
96
|
+
if success_event.is_set() or all_done_event.is_set():
|
|
97
|
+
return True
|
|
98
|
+
time.sleep(0.05)
|
|
99
|
+
return success_event.is_set() or all_done_event.is_set()
|
|
100
|
+
|
|
101
|
+
def _on_future_done(fut):
|
|
102
|
+
with done_counter_lock:
|
|
103
|
+
done_counter[0] += 1
|
|
104
|
+
if done_counter[0] >= n:
|
|
105
|
+
all_done_event.set()
|
|
106
|
+
|
|
107
|
+
logger.info(f" Racing {n} sources across multiple tiers (parallel)...")
|
|
108
|
+
|
|
109
|
+
pool = ThreadPoolExecutor(max_workers=n)
|
|
110
|
+
futures = {}
|
|
111
|
+
try:
|
|
112
|
+
for fn, label, tier_label, tier_timeout in all_sources:
|
|
113
|
+
src_output = target_dir / f"{safe_filename_fn(doi)}_{label}.pdf"
|
|
114
|
+
fut = pool.submit(_try_and_publish, fn, label, src_output)
|
|
115
|
+
futures[fut] = (label, src_output)
|
|
116
|
+
for fut in futures:
|
|
117
|
+
fut.add_done_callback(_on_future_done)
|
|
118
|
+
|
|
119
|
+
# Wait for first success, all sources done, or the overall timeout.
|
|
120
|
+
# all_done lets a full fast-failure return immediately instead of
|
|
121
|
+
# burning the whole timeout + grace period.
|
|
122
|
+
_wait_any(overall_timeout + 5)
|
|
123
|
+
|
|
124
|
+
if shared_result["result"] is not None:
|
|
125
|
+
result, label, src_output = shared_result["result"]
|
|
126
|
+
_move_to_output(result, output_path)
|
|
127
|
+
logger.info(f" OK {label}")
|
|
128
|
+
return result
|
|
129
|
+
if all_done_event.is_set():
|
|
130
|
+
logger.info(" All sources failed")
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
# Timeout reached — give late-finishing threads a grace period.
|
|
134
|
+
# Visible browser login can take 60-300s (browser launch + SSO + redirect),
|
|
135
|
+
# so we wait much longer if browser-based sources are in the pool.
|
|
136
|
+
has_browser = any("Browser" in lbl for _, lbl, _, _ in all_sources)
|
|
137
|
+
has_carsi = any("CARSI" in lbl for _, lbl, _, _ in all_sources)
|
|
138
|
+
if has_carsi:
|
|
139
|
+
grace = 300
|
|
140
|
+
elif has_browser:
|
|
141
|
+
grace = 180
|
|
142
|
+
else:
|
|
143
|
+
grace = 15
|
|
144
|
+
logger.info(f" Racing timed out after {overall_timeout + 5}s, waiting up to {grace}s for late results...")
|
|
145
|
+
_wait_any(grace)
|
|
146
|
+
if shared_result["result"] is not None:
|
|
147
|
+
result, label, src_output = shared_result["result"]
|
|
148
|
+
_move_to_output(result, output_path)
|
|
149
|
+
logger.info(f" OK {label} (late)")
|
|
150
|
+
return result
|
|
151
|
+
if all_done_event.is_set():
|
|
152
|
+
logger.info(" All sources failed")
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
# Final scan: check if any source wrote a valid PDF file despite timeout
|
|
156
|
+
for label, src_output in futures.values():
|
|
157
|
+
if src_output.exists():
|
|
158
|
+
_move_to_output({"success": True, "identifier": doi, "doi": doi,
|
|
159
|
+
"file": str(src_output), "source": label}, output_path)
|
|
160
|
+
if output_path.exists():
|
|
161
|
+
logger.info(f" OK {label} (file scan)")
|
|
162
|
+
return {"success": True, "identifier": doi, "doi": doi,
|
|
163
|
+
"file": str(output_path), "source": label}
|
|
164
|
+
|
|
165
|
+
logger.info(" All sources failed")
|
|
166
|
+
finally:
|
|
167
|
+
# Never block termination on sources that refuse to return: cancel
|
|
168
|
+
# pending futures and waive stragglers. Their own I/O deadlines
|
|
169
|
+
# (connect/read timeouts, stream deadline in pdf_utils) bound how long
|
|
170
|
+
# an abandoned worker thread can outlive the race.
|
|
171
|
+
alive = [f for f in futures if not f.done()]
|
|
172
|
+
if alive:
|
|
173
|
+
logger.info(f" Racing finished with {len(alive)} source(s) still running (waived)")
|
|
174
|
+
pool.shutdown(wait=False, cancel_futures=True)
|
|
175
|
+
_cleanup_temps(futures, output_path)
|
|
176
|
+
|
|
177
|
+
return None
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
cdef void _move_to_output(dict result, object output_path):
|
|
181
|
+
"""Move downloaded file to final output path."""
|
|
182
|
+
final_path = Path(result.get("file", ""))
|
|
183
|
+
if final_path != output_path and final_path.exists():
|
|
184
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
185
|
+
if output_path.exists():
|
|
186
|
+
output_path.unlink()
|
|
187
|
+
final_path.rename(output_path)
|
|
188
|
+
result["file"] = str(output_path)
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
cdef void _cleanup_temps(dict futures, object output_path):
|
|
192
|
+
"""Remove temporary files from failed downloads."""
|
|
193
|
+
for _, other_path in futures.values():
|
|
194
|
+
if other_path != output_path and other_path.exists():
|
|
195
|
+
try:
|
|
196
|
+
other_path.unlink(missing_ok=True)
|
|
197
|
+
except OSError:
|
|
198
|
+
pass
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def build_tiers(
|
|
202
|
+
list publisher_fast,
|
|
203
|
+
list publisher_oa,
|
|
204
|
+
list tier3_libgen,
|
|
205
|
+
list tier4_scihub,
|
|
206
|
+
list tier5_instsci,
|
|
207
|
+
str strategy,
|
|
208
|
+
) -> list:
|
|
209
|
+
"""Build tier structure based on download strategy.
|
|
210
|
+
|
|
211
|
+
Returns list of (sources, label, timeout) tuples.
|
|
212
|
+
"""
|
|
213
|
+
if strategy == "legal_only":
|
|
214
|
+
return [
|
|
215
|
+
(publisher_fast, "Flash", TIER_FLASH_TIMEOUT),
|
|
216
|
+
(publisher_oa, "OA", TIER_OA_TIMEOUT),
|
|
217
|
+
]
|
|
218
|
+
elif strategy == "scihub_only":
|
|
219
|
+
return [(tier4_scihub, "Sci-Hub", TIER_WEBVPN_TIMEOUT)]
|
|
220
|
+
elif strategy == "oa_first":
|
|
221
|
+
return [
|
|
222
|
+
(publisher_fast, "Flash", TIER_FLASH_TIMEOUT),
|
|
223
|
+
(publisher_oa, "OA", TIER_OA_TIMEOUT),
|
|
224
|
+
(tier3_libgen + tier4_scihub, "Grey", TIER_GREY_TIMEOUT),
|
|
225
|
+
]
|
|
226
|
+
else:
|
|
227
|
+
# "fastest" (default): all tiers race in parallel
|
|
228
|
+
tier2_fast = publisher_oa[:3] if len(publisher_oa) > 3 else publisher_oa
|
|
229
|
+
tier3_oa = publisher_oa[3:] if len(publisher_oa) > 3 else []
|
|
230
|
+
tiers = [
|
|
231
|
+
(publisher_fast, "Flash", TIER_FLASH_TIMEOUT),
|
|
232
|
+
(tier2_fast, "Fast", TIER_FAST_TIMEOUT),
|
|
233
|
+
(tier3_oa, "OA", TIER_OA_TIMEOUT),
|
|
234
|
+
(tier3_libgen + tier4_scihub, "Grey", TIER_GREY_TIMEOUT),
|
|
235
|
+
]
|
|
236
|
+
if tier5_instsci:
|
|
237
|
+
tiers.append((tier5_instsci, "WebVPN", TIER_WEBVPN_TIMEOUT))
|
|
238
|
+
return tiers
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def batch_download(
|
|
242
|
+
list dois,
|
|
243
|
+
object output_dir,
|
|
244
|
+
dict config,
|
|
245
|
+
download_fn,
|
|
246
|
+
int workers = DEFAULT_BATCH_WORKERS,
|
|
247
|
+
) -> list:
|
|
248
|
+
"""Download multiple papers with staggered parallel execution.
|
|
249
|
+
|
|
250
|
+
Deduplicates DOIs, then runs downloads with rate-limiting stagger.
|
|
251
|
+
"""
|
|
252
|
+
# Deduplicate preserving order
|
|
253
|
+
cdef list seen = set()
|
|
254
|
+
cdef list unique_dois = []
|
|
255
|
+
for doi in dois:
|
|
256
|
+
if doi not in seen:
|
|
257
|
+
seen.add(doi)
|
|
258
|
+
unique_dois.append(doi)
|
|
259
|
+
|
|
260
|
+
cdef list results = []
|
|
261
|
+
cdef double delay = BATCH_STAGGER_DELAY
|
|
262
|
+
stagger_lock = threading.Lock()
|
|
263
|
+
|
|
264
|
+
def _download_one(doi):
|
|
265
|
+
# Stagger start to avoid burst requests
|
|
266
|
+
with stagger_lock:
|
|
267
|
+
time.sleep(delay)
|
|
268
|
+
return download_fn(doi, output_dir, config=config)
|
|
269
|
+
|
|
270
|
+
with ThreadPoolExecutor(max_workers=workers) as pool:
|
|
271
|
+
futures = {pool.submit(_download_one, doi): doi for doi in unique_dois}
|
|
272
|
+
for future in as_completed(futures):
|
|
273
|
+
doi = futures[future]
|
|
274
|
+
try:
|
|
275
|
+
result = future.result()
|
|
276
|
+
results.append(result)
|
|
277
|
+
except Exception as e:
|
|
278
|
+
results.append({"doi": doi, "success": False, "error": str(e)})
|
|
279
|
+
|
|
280
|
+
return results
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Per-publisher adapters for the publisher browser driver.
|
|
2
|
+
|
|
3
|
+
The shared engine (``PublisherBatchDownloader``) owns navigation, waits for
|
|
4
|
+
human verification, the PDF capture channels and the run records. An adapter
|
|
5
|
+
answers only its publisher's questions: is this reader signed in, where is
|
|
6
|
+
the institution entry, which URL is the article PDF, which links are its
|
|
7
|
+
supplementary files. Every hook returns ``None`` for "no opinion", and the
|
|
8
|
+
engine then applies its generic behaviour, so publishers without an adapter
|
|
9
|
+
keep working unchanged.
|
|
10
|
+
|
|
11
|
+
Each publisher, and each platform shared by several publishers (``atypon``,
|
|
12
|
+
``silverchair``), has its own folder here: its rules in ``<name>/__init__.py``,
|
|
13
|
+
and one more module per site type when it has several (``elsevier/``,
|
|
14
|
+
``lww/``). ``base.py`` holds the shared base class and its defaults.
|
|
15
|
+
|
|
16
|
+
Adding a publisher: subclass :class:`PublisherAdapter` in ``<name>/__init__.py``,
|
|
17
|
+
decorate it with :func:`register`, and import the package below.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from .base import PublisherAdapter, SupplementLink, adapter_class, adapter_for, register
|
|
21
|
+
from . import ( # noqa: F401 (register the adapters)
|
|
22
|
+
acm, acs, aha_journals, ams, annual_reviews, aps, asce, bmj, copernicus, dovepress, elsevier, ieee, iop,
|
|
23
|
+
jama, karger, lww, mdpi, nejm, neurology, optica, oup, plos, pnas, rsc, sage, science, springer,
|
|
24
|
+
taylor_francis, thieme, wiley, world_scientific)
|
|
25
|
+
|
|
26
|
+
__all__ = ["PublisherAdapter", "SupplementLink", "adapter_class", "adapter_for", "register"]
|