webscout 8.2.9__py3-none-any.whl → 2026.1.19__py3-none-any.whl
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.
- webscout/AIauto.py +524 -251
- webscout/AIbase.py +247 -319
- webscout/AIutel.py +68 -703
- webscout/Bard.py +1072 -1026
- webscout/Extra/GitToolkit/__init__.py +10 -10
- webscout/Extra/GitToolkit/gitapi/__init__.py +20 -12
- webscout/Extra/GitToolkit/gitapi/gist.py +142 -0
- webscout/Extra/GitToolkit/gitapi/organization.py +91 -0
- webscout/Extra/GitToolkit/gitapi/repository.py +308 -195
- webscout/Extra/GitToolkit/gitapi/search.py +162 -0
- webscout/Extra/GitToolkit/gitapi/trending.py +236 -0
- webscout/Extra/GitToolkit/gitapi/user.py +128 -96
- webscout/Extra/GitToolkit/gitapi/utils.py +82 -62
- webscout/Extra/YTToolkit/README.md +443 -375
- webscout/Extra/YTToolkit/YTdownloader.py +953 -957
- webscout/Extra/YTToolkit/__init__.py +3 -3
- webscout/Extra/YTToolkit/transcriber.py +595 -476
- webscout/Extra/YTToolkit/ytapi/README.md +230 -44
- webscout/Extra/YTToolkit/ytapi/__init__.py +22 -6
- webscout/Extra/YTToolkit/ytapi/captions.py +190 -0
- webscout/Extra/YTToolkit/ytapi/channel.py +302 -307
- webscout/Extra/YTToolkit/ytapi/errors.py +13 -13
- webscout/Extra/YTToolkit/ytapi/extras.py +178 -118
- webscout/Extra/YTToolkit/ytapi/hashtag.py +120 -0
- webscout/Extra/YTToolkit/ytapi/https.py +89 -88
- webscout/Extra/YTToolkit/ytapi/patterns.py +61 -61
- webscout/Extra/YTToolkit/ytapi/playlist.py +59 -59
- webscout/Extra/YTToolkit/ytapi/pool.py +8 -8
- webscout/Extra/YTToolkit/ytapi/query.py +143 -40
- webscout/Extra/YTToolkit/ytapi/shorts.py +122 -0
- webscout/Extra/YTToolkit/ytapi/stream.py +68 -63
- webscout/Extra/YTToolkit/ytapi/suggestions.py +97 -0
- webscout/Extra/YTToolkit/ytapi/utils.py +66 -62
- webscout/Extra/YTToolkit/ytapi/video.py +403 -232
- webscout/Extra/__init__.py +2 -3
- webscout/Extra/gguf.py +1298 -684
- webscout/Extra/tempmail/README.md +487 -487
- webscout/Extra/tempmail/__init__.py +28 -28
- webscout/Extra/tempmail/async_utils.py +143 -141
- webscout/Extra/tempmail/base.py +172 -161
- webscout/Extra/tempmail/cli.py +191 -187
- webscout/Extra/tempmail/emailnator.py +88 -84
- webscout/Extra/tempmail/mail_tm.py +378 -361
- webscout/Extra/tempmail/temp_mail_io.py +304 -292
- webscout/Extra/weather.py +196 -194
- webscout/Extra/weather_ascii.py +17 -15
- webscout/Provider/AISEARCH/PERPLEXED_search.py +175 -0
- webscout/Provider/AISEARCH/Perplexity.py +292 -333
- webscout/Provider/AISEARCH/README.md +106 -279
- webscout/Provider/AISEARCH/__init__.py +16 -9
- webscout/Provider/AISEARCH/brave_search.py +298 -0
- webscout/Provider/AISEARCH/iask_search.py +357 -410
- webscout/Provider/AISEARCH/monica_search.py +200 -220
- webscout/Provider/AISEARCH/webpilotai_search.py +242 -255
- webscout/Provider/Algion.py +413 -0
- webscout/Provider/Andi.py +74 -69
- webscout/Provider/Apriel.py +313 -0
- webscout/Provider/Ayle.py +323 -0
- webscout/Provider/ChatSandbox.py +329 -342
- webscout/Provider/ClaudeOnline.py +365 -0
- webscout/Provider/Cohere.py +232 -208
- webscout/Provider/DeepAI.py +367 -0
- webscout/Provider/Deepinfra.py +467 -340
- webscout/Provider/EssentialAI.py +217 -0
- webscout/Provider/ExaAI.py +274 -261
- webscout/Provider/Gemini.py +175 -169
- webscout/Provider/GithubChat.py +385 -369
- webscout/Provider/Gradient.py +286 -0
- webscout/Provider/Groq.py +556 -801
- webscout/Provider/HadadXYZ.py +323 -0
- webscout/Provider/HeckAI.py +392 -375
- webscout/Provider/HuggingFace.py +387 -0
- webscout/Provider/IBM.py +340 -0
- webscout/Provider/Jadve.py +317 -291
- webscout/Provider/K2Think.py +306 -0
- webscout/Provider/Koboldai.py +221 -384
- webscout/Provider/Netwrck.py +273 -270
- webscout/Provider/Nvidia.py +310 -0
- webscout/Provider/OPENAI/DeepAI.py +489 -0
- webscout/Provider/OPENAI/K2Think.py +423 -0
- webscout/Provider/OPENAI/PI.py +463 -0
- webscout/Provider/OPENAI/README.md +890 -952
- webscout/Provider/OPENAI/TogetherAI.py +405 -0
- webscout/Provider/OPENAI/TwoAI.py +255 -357
- webscout/Provider/OPENAI/__init__.py +148 -40
- webscout/Provider/OPENAI/ai4chat.py +348 -293
- webscout/Provider/OPENAI/akashgpt.py +436 -0
- webscout/Provider/OPENAI/algion.py +303 -0
- webscout/Provider/OPENAI/{exachat.py → ayle.py} +365 -444
- webscout/Provider/OPENAI/base.py +253 -249
- webscout/Provider/OPENAI/cerebras.py +296 -0
- webscout/Provider/OPENAI/chatgpt.py +870 -556
- webscout/Provider/OPENAI/chatsandbox.py +233 -173
- webscout/Provider/OPENAI/deepinfra.py +403 -322
- webscout/Provider/OPENAI/e2b.py +2370 -1414
- webscout/Provider/OPENAI/elmo.py +278 -0
- webscout/Provider/OPENAI/exaai.py +452 -417
- webscout/Provider/OPENAI/freeassist.py +446 -0
- webscout/Provider/OPENAI/gradient.py +448 -0
- webscout/Provider/OPENAI/groq.py +380 -364
- webscout/Provider/OPENAI/hadadxyz.py +292 -0
- webscout/Provider/OPENAI/heckai.py +333 -308
- webscout/Provider/OPENAI/huggingface.py +321 -0
- webscout/Provider/OPENAI/ibm.py +425 -0
- webscout/Provider/OPENAI/llmchat.py +253 -0
- webscout/Provider/OPENAI/llmchatco.py +378 -335
- webscout/Provider/OPENAI/meta.py +541 -0
- webscout/Provider/OPENAI/netwrck.py +374 -357
- webscout/Provider/OPENAI/nvidia.py +317 -0
- webscout/Provider/OPENAI/oivscode.py +348 -287
- webscout/Provider/OPENAI/openrouter.py +328 -0
- webscout/Provider/OPENAI/pydantic_imports.py +1 -172
- webscout/Provider/OPENAI/sambanova.py +397 -0
- webscout/Provider/OPENAI/sonus.py +305 -304
- webscout/Provider/OPENAI/textpollinations.py +370 -339
- webscout/Provider/OPENAI/toolbaz.py +375 -413
- webscout/Provider/OPENAI/typefully.py +419 -355
- webscout/Provider/OPENAI/typliai.py +279 -0
- webscout/Provider/OPENAI/utils.py +314 -318
- webscout/Provider/OPENAI/wisecat.py +359 -387
- webscout/Provider/OPENAI/writecream.py +185 -163
- webscout/Provider/OPENAI/x0gpt.py +462 -365
- webscout/Provider/OPENAI/zenmux.py +380 -0
- webscout/Provider/OpenRouter.py +386 -0
- webscout/Provider/Openai.py +337 -496
- webscout/Provider/PI.py +443 -429
- webscout/Provider/QwenLM.py +346 -254
- webscout/Provider/STT/__init__.py +28 -0
- webscout/Provider/STT/base.py +303 -0
- webscout/Provider/STT/elevenlabs.py +264 -0
- webscout/Provider/Sambanova.py +317 -0
- webscout/Provider/TTI/README.md +69 -82
- webscout/Provider/TTI/__init__.py +37 -7
- webscout/Provider/TTI/base.py +147 -64
- webscout/Provider/TTI/claudeonline.py +393 -0
- webscout/Provider/TTI/magicstudio.py +292 -201
- webscout/Provider/TTI/miragic.py +180 -0
- webscout/Provider/TTI/pollinations.py +331 -221
- webscout/Provider/TTI/together.py +334 -0
- webscout/Provider/TTI/utils.py +14 -11
- webscout/Provider/TTS/README.md +186 -192
- webscout/Provider/TTS/__init__.py +43 -10
- webscout/Provider/TTS/base.py +523 -159
- webscout/Provider/TTS/deepgram.py +286 -156
- webscout/Provider/TTS/elevenlabs.py +189 -111
- webscout/Provider/TTS/freetts.py +218 -0
- webscout/Provider/TTS/murfai.py +288 -113
- webscout/Provider/TTS/openai_fm.py +364 -129
- webscout/Provider/TTS/parler.py +203 -111
- webscout/Provider/TTS/qwen.py +334 -0
- webscout/Provider/TTS/sherpa.py +286 -0
- webscout/Provider/TTS/speechma.py +693 -580
- webscout/Provider/TTS/streamElements.py +275 -333
- webscout/Provider/TTS/utils.py +280 -280
- webscout/Provider/TextPollinationsAI.py +331 -308
- webscout/Provider/TogetherAI.py +450 -0
- webscout/Provider/TwoAI.py +309 -475
- webscout/Provider/TypliAI.py +311 -305
- webscout/Provider/UNFINISHED/ChatHub.py +219 -209
- webscout/Provider/{OPENAI/glider.py → UNFINISHED/ChutesAI.py} +331 -326
- webscout/Provider/{GizAI.py → UNFINISHED/GizAI.py} +300 -295
- webscout/Provider/{Marcus.py → UNFINISHED/Marcus.py} +218 -198
- webscout/Provider/UNFINISHED/Qodo.py +481 -0
- webscout/Provider/{MCPCore.py → UNFINISHED/XenAI.py} +330 -315
- webscout/Provider/UNFINISHED/Youchat.py +347 -330
- webscout/Provider/UNFINISHED/aihumanizer.py +41 -0
- webscout/Provider/UNFINISHED/grammerchecker.py +37 -0
- webscout/Provider/UNFINISHED/liner.py +342 -0
- webscout/Provider/UNFINISHED/liner_api_request.py +246 -263
- webscout/Provider/{samurai.py → UNFINISHED/samurai.py} +231 -224
- webscout/Provider/WiseCat.py +256 -233
- webscout/Provider/WrDoChat.py +390 -370
- webscout/Provider/__init__.py +115 -174
- webscout/Provider/ai4chat.py +181 -174
- webscout/Provider/akashgpt.py +330 -335
- webscout/Provider/cerebras.py +397 -290
- webscout/Provider/cleeai.py +236 -213
- webscout/Provider/elmo.py +291 -283
- webscout/Provider/geminiapi.py +343 -208
- webscout/Provider/julius.py +245 -223
- webscout/Provider/learnfastai.py +333 -325
- webscout/Provider/llama3mitril.py +230 -215
- webscout/Provider/llmchat.py +308 -258
- webscout/Provider/llmchatco.py +321 -306
- webscout/Provider/meta.py +996 -801
- webscout/Provider/oivscode.py +332 -309
- webscout/Provider/searchchat.py +316 -292
- webscout/Provider/sonus.py +264 -258
- webscout/Provider/toolbaz.py +359 -353
- webscout/Provider/turboseek.py +332 -266
- webscout/Provider/typefully.py +262 -202
- webscout/Provider/x0gpt.py +332 -299
- webscout/__init__.py +31 -39
- webscout/__main__.py +5 -5
- webscout/cli.py +585 -524
- webscout/client.py +1497 -70
- webscout/conversation.py +140 -436
- webscout/exceptions.py +383 -362
- webscout/litagent/__init__.py +29 -29
- webscout/litagent/agent.py +492 -455
- webscout/litagent/constants.py +60 -60
- webscout/models.py +505 -181
- webscout/optimizers.py +74 -420
- webscout/prompt_manager.py +376 -288
- webscout/sanitize.py +1514 -0
- webscout/scout/README.md +452 -404
- webscout/scout/__init__.py +8 -8
- webscout/scout/core/__init__.py +7 -7
- webscout/scout/core/crawler.py +330 -210
- webscout/scout/core/scout.py +800 -607
- webscout/scout/core/search_result.py +51 -96
- webscout/scout/core/text_analyzer.py +64 -63
- webscout/scout/core/text_utils.py +412 -277
- webscout/scout/core/web_analyzer.py +54 -52
- webscout/scout/element.py +872 -478
- webscout/scout/parsers/__init__.py +70 -69
- webscout/scout/parsers/html5lib_parser.py +182 -172
- webscout/scout/parsers/html_parser.py +238 -236
- webscout/scout/parsers/lxml_parser.py +203 -178
- webscout/scout/utils.py +38 -37
- webscout/search/__init__.py +47 -0
- webscout/search/base.py +201 -0
- webscout/search/bing_main.py +45 -0
- webscout/search/brave_main.py +92 -0
- webscout/search/duckduckgo_main.py +57 -0
- webscout/search/engines/__init__.py +127 -0
- webscout/search/engines/bing/__init__.py +15 -0
- webscout/search/engines/bing/base.py +35 -0
- webscout/search/engines/bing/images.py +114 -0
- webscout/search/engines/bing/news.py +96 -0
- webscout/search/engines/bing/suggestions.py +36 -0
- webscout/search/engines/bing/text.py +109 -0
- webscout/search/engines/brave/__init__.py +19 -0
- webscout/search/engines/brave/base.py +47 -0
- webscout/search/engines/brave/images.py +213 -0
- webscout/search/engines/brave/news.py +353 -0
- webscout/search/engines/brave/suggestions.py +318 -0
- webscout/search/engines/brave/text.py +167 -0
- webscout/search/engines/brave/videos.py +364 -0
- webscout/search/engines/duckduckgo/__init__.py +25 -0
- webscout/search/engines/duckduckgo/answers.py +80 -0
- webscout/search/engines/duckduckgo/base.py +189 -0
- webscout/search/engines/duckduckgo/images.py +100 -0
- webscout/search/engines/duckduckgo/maps.py +183 -0
- webscout/search/engines/duckduckgo/news.py +70 -0
- webscout/search/engines/duckduckgo/suggestions.py +22 -0
- webscout/search/engines/duckduckgo/text.py +221 -0
- webscout/search/engines/duckduckgo/translate.py +48 -0
- webscout/search/engines/duckduckgo/videos.py +80 -0
- webscout/search/engines/duckduckgo/weather.py +84 -0
- webscout/search/engines/mojeek.py +61 -0
- webscout/search/engines/wikipedia.py +77 -0
- webscout/search/engines/yahoo/__init__.py +41 -0
- webscout/search/engines/yahoo/answers.py +19 -0
- webscout/search/engines/yahoo/base.py +34 -0
- webscout/search/engines/yahoo/images.py +323 -0
- webscout/search/engines/yahoo/maps.py +19 -0
- webscout/search/engines/yahoo/news.py +258 -0
- webscout/search/engines/yahoo/suggestions.py +140 -0
- webscout/search/engines/yahoo/text.py +273 -0
- webscout/search/engines/yahoo/translate.py +19 -0
- webscout/search/engines/yahoo/videos.py +302 -0
- webscout/search/engines/yahoo/weather.py +220 -0
- webscout/search/engines/yandex.py +67 -0
- webscout/search/engines/yep/__init__.py +13 -0
- webscout/search/engines/yep/base.py +34 -0
- webscout/search/engines/yep/images.py +101 -0
- webscout/search/engines/yep/suggestions.py +38 -0
- webscout/search/engines/yep/text.py +99 -0
- webscout/search/http_client.py +172 -0
- webscout/search/results.py +141 -0
- webscout/search/yahoo_main.py +57 -0
- webscout/search/yep_main.py +48 -0
- webscout/server/__init__.py +48 -0
- webscout/server/config.py +78 -0
- webscout/server/exceptions.py +69 -0
- webscout/server/providers.py +286 -0
- webscout/server/request_models.py +131 -0
- webscout/server/request_processing.py +404 -0
- webscout/server/routes.py +642 -0
- webscout/server/server.py +351 -0
- webscout/server/ui_templates.py +1171 -0
- webscout/swiftcli/__init__.py +79 -95
- webscout/swiftcli/core/__init__.py +7 -7
- webscout/swiftcli/core/cli.py +574 -297
- webscout/swiftcli/core/context.py +98 -104
- webscout/swiftcli/core/group.py +268 -241
- webscout/swiftcli/decorators/__init__.py +28 -28
- webscout/swiftcli/decorators/command.py +243 -221
- webscout/swiftcli/decorators/options.py +247 -220
- webscout/swiftcli/decorators/output.py +392 -252
- webscout/swiftcli/exceptions.py +21 -21
- webscout/swiftcli/plugins/__init__.py +9 -9
- webscout/swiftcli/plugins/base.py +134 -135
- webscout/swiftcli/plugins/manager.py +269 -269
- webscout/swiftcli/utils/__init__.py +58 -59
- webscout/swiftcli/utils/formatting.py +251 -252
- webscout/swiftcli/utils/parsing.py +368 -267
- webscout/update_checker.py +280 -136
- webscout/utils.py +28 -14
- webscout/version.py +2 -1
- webscout/version.py.bak +3 -0
- webscout/zeroart/__init__.py +218 -135
- webscout/zeroart/base.py +70 -66
- webscout/zeroart/effects.py +155 -101
- webscout/zeroart/fonts.py +1799 -1239
- webscout-2026.1.19.dist-info/METADATA +638 -0
- webscout-2026.1.19.dist-info/RECORD +312 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/WHEEL +1 -1
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/entry_points.txt +1 -1
- webscout/DWEBS.py +0 -520
- webscout/Extra/Act.md +0 -309
- webscout/Extra/GitToolkit/gitapi/README.md +0 -110
- webscout/Extra/autocoder/__init__.py +0 -9
- webscout/Extra/autocoder/autocoder.py +0 -1105
- webscout/Extra/autocoder/autocoder_utiles.py +0 -332
- webscout/Extra/gguf.md +0 -430
- webscout/Extra/weather.md +0 -281
- webscout/Litlogger/README.md +0 -10
- webscout/Litlogger/__init__.py +0 -15
- webscout/Litlogger/formats.py +0 -4
- webscout/Litlogger/handlers.py +0 -103
- webscout/Litlogger/levels.py +0 -13
- webscout/Litlogger/logger.py +0 -92
- webscout/Provider/AI21.py +0 -177
- webscout/Provider/AISEARCH/DeepFind.py +0 -254
- webscout/Provider/AISEARCH/felo_search.py +0 -202
- webscout/Provider/AISEARCH/genspark_search.py +0 -324
- webscout/Provider/AISEARCH/hika_search.py +0 -186
- webscout/Provider/AISEARCH/scira_search.py +0 -298
- webscout/Provider/Aitopia.py +0 -316
- webscout/Provider/AllenAI.py +0 -440
- webscout/Provider/Blackboxai.py +0 -791
- webscout/Provider/ChatGPTClone.py +0 -237
- webscout/Provider/ChatGPTGratis.py +0 -194
- webscout/Provider/Cloudflare.py +0 -324
- webscout/Provider/ExaChat.py +0 -358
- webscout/Provider/Flowith.py +0 -217
- webscout/Provider/FreeGemini.py +0 -250
- webscout/Provider/Glider.py +0 -225
- webscout/Provider/HF_space/__init__.py +0 -0
- webscout/Provider/HF_space/qwen_qwen2.py +0 -206
- webscout/Provider/HuggingFaceChat.py +0 -469
- webscout/Provider/Hunyuan.py +0 -283
- webscout/Provider/LambdaChat.py +0 -411
- webscout/Provider/Llama3.py +0 -259
- webscout/Provider/Nemotron.py +0 -218
- webscout/Provider/OLLAMA.py +0 -396
- webscout/Provider/OPENAI/BLACKBOXAI.py +0 -766
- webscout/Provider/OPENAI/Cloudflare.py +0 -378
- webscout/Provider/OPENAI/FreeGemini.py +0 -283
- webscout/Provider/OPENAI/NEMOTRON.py +0 -232
- webscout/Provider/OPENAI/Qwen3.py +0 -283
- webscout/Provider/OPENAI/api.py +0 -969
- webscout/Provider/OPENAI/c4ai.py +0 -373
- webscout/Provider/OPENAI/chatgptclone.py +0 -494
- webscout/Provider/OPENAI/copilot.py +0 -242
- webscout/Provider/OPENAI/flowith.py +0 -162
- webscout/Provider/OPENAI/freeaichat.py +0 -359
- webscout/Provider/OPENAI/mcpcore.py +0 -389
- webscout/Provider/OPENAI/multichat.py +0 -376
- webscout/Provider/OPENAI/opkfc.py +0 -496
- webscout/Provider/OPENAI/scirachat.py +0 -477
- webscout/Provider/OPENAI/standardinput.py +0 -433
- webscout/Provider/OPENAI/typegpt.py +0 -364
- webscout/Provider/OPENAI/uncovrAI.py +0 -463
- webscout/Provider/OPENAI/venice.py +0 -431
- webscout/Provider/OPENAI/yep.py +0 -382
- webscout/Provider/OpenGPT.py +0 -209
- webscout/Provider/Perplexitylabs.py +0 -415
- webscout/Provider/Reka.py +0 -214
- webscout/Provider/StandardInput.py +0 -290
- webscout/Provider/TTI/aiarta.py +0 -365
- webscout/Provider/TTI/artbit.py +0 -0
- webscout/Provider/TTI/fastflux.py +0 -200
- webscout/Provider/TTI/piclumen.py +0 -203
- webscout/Provider/TTI/pixelmuse.py +0 -225
- webscout/Provider/TTS/gesserit.py +0 -128
- webscout/Provider/TTS/sthir.py +0 -94
- webscout/Provider/TeachAnything.py +0 -229
- webscout/Provider/UNFINISHED/puterjs.py +0 -635
- webscout/Provider/UNFINISHED/test_lmarena.py +0 -119
- webscout/Provider/Venice.py +0 -258
- webscout/Provider/VercelAI.py +0 -253
- webscout/Provider/Writecream.py +0 -246
- webscout/Provider/WritingMate.py +0 -269
- webscout/Provider/asksteve.py +0 -220
- webscout/Provider/chatglm.py +0 -215
- webscout/Provider/copilot.py +0 -425
- webscout/Provider/freeaichat.py +0 -285
- webscout/Provider/granite.py +0 -235
- webscout/Provider/hermes.py +0 -266
- webscout/Provider/koala.py +0 -170
- webscout/Provider/lmarena.py +0 -198
- webscout/Provider/multichat.py +0 -364
- webscout/Provider/scira_chat.py +0 -299
- webscout/Provider/scnet.py +0 -243
- webscout/Provider/talkai.py +0 -194
- webscout/Provider/typegpt.py +0 -289
- webscout/Provider/uncovr.py +0 -368
- webscout/Provider/yep.py +0 -389
- webscout/litagent/Readme.md +0 -276
- webscout/litprinter/__init__.py +0 -59
- webscout/swiftcli/Readme.md +0 -323
- webscout/tempid.py +0 -128
- webscout/webscout_search.py +0 -1184
- webscout/webscout_search_async.py +0 -654
- webscout/yep_search.py +0 -347
- webscout/zeroart/README.md +0 -89
- webscout-8.2.9.dist-info/METADATA +0 -1033
- webscout-8.2.9.dist-info/RECORD +0 -289
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/licenses/LICENSE.md +0 -0
- {webscout-8.2.9.dist-info → webscout-2026.1.19.dist-info}/top_level.txt +0 -0
|
@@ -1,44 +1,230 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
1
|
+
# 🎬 YTAPI: YouTube Data Extraction Module
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
YTAPI is a powerful, lightweight YouTube data extraction module within the Webscout Python package. It provides comprehensive tools for retrieving YouTube video, channel, playlist, and search data without requiring an API key.
|
|
6
|
+
|
|
7
|
+
## ✨ Features
|
|
8
|
+
|
|
9
|
+
### Core Classes
|
|
10
|
+
|
|
11
|
+
- **Video** - Video metadata, comments, chapters, related videos
|
|
12
|
+
- **Channel** - Channel info, uploads, streams, playlists
|
|
13
|
+
- **Playlist** - Playlist metadata and videos
|
|
14
|
+
- **Search** - Search videos, channels, playlists, Shorts, live streams
|
|
15
|
+
|
|
16
|
+
### New Classes
|
|
17
|
+
|
|
18
|
+
- **Suggestions** - YouTube search autocomplete
|
|
19
|
+
- **Shorts** - YouTube Shorts detection and search
|
|
20
|
+
- **Hashtag** - Videos by hashtag
|
|
21
|
+
- **Captions** - Video transcripts and subtitles
|
|
22
|
+
- **Extras** - Trending content by category
|
|
23
|
+
|
|
24
|
+
## 📦 Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install webscout
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## 💡 Quick Examples
|
|
31
|
+
|
|
32
|
+
### Video Operations
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from webscout.Extra.YTToolkit.ytapi import Video
|
|
36
|
+
|
|
37
|
+
video = Video("dQw4w9WgXcQ")
|
|
38
|
+
|
|
39
|
+
# Get metadata
|
|
40
|
+
meta = video.metadata
|
|
41
|
+
print(f"Title: {meta['title']}")
|
|
42
|
+
print(f"Views: {meta['views']}")
|
|
43
|
+
|
|
44
|
+
# New features
|
|
45
|
+
print(f"Is Live: {video.is_live}")
|
|
46
|
+
print(f"Is Short: {video.is_short}")
|
|
47
|
+
print(f"Hashtags: {video.hashtags}")
|
|
48
|
+
|
|
49
|
+
# Get related videos
|
|
50
|
+
related = video.get_related_videos(5)
|
|
51
|
+
print(f"Related: {related}")
|
|
52
|
+
|
|
53
|
+
# Get chapters
|
|
54
|
+
chapters = video.get_chapters()
|
|
55
|
+
if chapters:
|
|
56
|
+
for ch in chapters:
|
|
57
|
+
print(f"{ch['start_time']} - {ch['title']}")
|
|
58
|
+
|
|
59
|
+
# Stream comments
|
|
60
|
+
for comment in video.stream_comments(10):
|
|
61
|
+
print(f"{comment['author']}: {comment['text'][:50]}")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Search Operations
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from webscout.Extra.YTToolkit.ytapi import Search
|
|
68
|
+
|
|
69
|
+
# Basic search
|
|
70
|
+
videos = Search.videos("python tutorial", limit=10)
|
|
71
|
+
channels = Search.channels("tech", limit=5)
|
|
72
|
+
|
|
73
|
+
# New search features
|
|
74
|
+
shorts = Search.shorts("funny cats", limit=10)
|
|
75
|
+
live = Search.live_streams("music", limit=5)
|
|
76
|
+
|
|
77
|
+
# Filtered search
|
|
78
|
+
recent = Search.videos_by_upload_date("news", when="today", limit=10)
|
|
79
|
+
short_vids = Search.videos_by_duration("tutorial", duration="short", limit=10)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Suggestions (NEW)
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
from webscout.Extra.YTToolkit.ytapi import Suggestions
|
|
86
|
+
|
|
87
|
+
# Get autocomplete suggestions
|
|
88
|
+
suggestions = Suggestions.autocomplete("how to")
|
|
89
|
+
print(suggestions)
|
|
90
|
+
# ['how to make money', 'how to tie a tie', ...]
|
|
91
|
+
|
|
92
|
+
# Get trending searches
|
|
93
|
+
trending = Suggestions.trending_searches()
|
|
94
|
+
print(trending)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Shorts (NEW)
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from webscout.Extra.YTToolkit.ytapi import Shorts
|
|
101
|
+
|
|
102
|
+
# Check if a video is a Short
|
|
103
|
+
is_short = Shorts.is_short("video_id")
|
|
104
|
+
|
|
105
|
+
# Get trending Shorts
|
|
106
|
+
trending = Shorts.get_trending(10)
|
|
107
|
+
|
|
108
|
+
# Search for Shorts
|
|
109
|
+
results = Shorts.search("dance", limit=20)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Hashtag (NEW)
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from webscout.Extra.YTToolkit.ytapi import Hashtag
|
|
116
|
+
|
|
117
|
+
# Get videos by hashtag
|
|
118
|
+
videos = Hashtag.get_videos("python", limit=20)
|
|
119
|
+
|
|
120
|
+
# Get hashtag metadata
|
|
121
|
+
meta = Hashtag.get_metadata("coding")
|
|
122
|
+
print(f"Tag: {meta['tag']}")
|
|
123
|
+
print(f"Sample videos: {meta['sample_videos']}")
|
|
124
|
+
|
|
125
|
+
# Extract hashtags from text
|
|
126
|
+
tags = Hashtag.extract_from_text("Check out my #python #tutorial!")
|
|
127
|
+
print(tags) # ['python', 'tutorial']
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Captions (NEW)
|
|
131
|
+
|
|
132
|
+
```python
|
|
133
|
+
from webscout.Extra.YTToolkit.ytapi import Captions
|
|
134
|
+
|
|
135
|
+
# Get available languages
|
|
136
|
+
langs = Captions.get_available_languages("dQw4w9WgXcQ")
|
|
137
|
+
for lang in langs:
|
|
138
|
+
print(f"{lang['code']}: {lang['name']}")
|
|
139
|
+
|
|
140
|
+
# Get transcript
|
|
141
|
+
transcript = Captions.get_transcript("dQw4w9WgXcQ", "en")
|
|
142
|
+
print(transcript[:500])
|
|
143
|
+
|
|
144
|
+
# Get timed transcript
|
|
145
|
+
timed = Captions.get_timed_transcript("dQw4w9WgXcQ")
|
|
146
|
+
for entry in timed[:5]:
|
|
147
|
+
print(f"{entry['start']:.1f}s: {entry['text']}")
|
|
148
|
+
|
|
149
|
+
# Search within transcript
|
|
150
|
+
matches = Captions.search_transcript("dQw4w9WgXcQ", "never gonna")
|
|
151
|
+
for match in matches:
|
|
152
|
+
print(f"{match['start']:.1f}s: {match['text']}")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Extras (Trending)
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
from webscout.Extra.YTToolkit.ytapi import Extras
|
|
159
|
+
|
|
160
|
+
# Get trending content
|
|
161
|
+
trending = Extras.trending_videos(10)
|
|
162
|
+
music = Extras.music_videos(10)
|
|
163
|
+
gaming = Extras.gaming_videos(10)
|
|
164
|
+
news = Extras.news_videos(10)
|
|
165
|
+
live = Extras.live_videos(10)
|
|
166
|
+
sports = Extras.sport_videos(10)
|
|
167
|
+
educational = Extras.educational_videos(10)
|
|
168
|
+
|
|
169
|
+
# New categories
|
|
170
|
+
shorts = Extras.shorts_videos(10)
|
|
171
|
+
movies = Extras.movies(10)
|
|
172
|
+
podcasts = Extras.podcasts(10)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Channel Operations
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from webscout.Extra.YTToolkit.ytapi import Channel
|
|
179
|
+
|
|
180
|
+
channel = Channel("@MrBeast")
|
|
181
|
+
|
|
182
|
+
# Get metadata
|
|
183
|
+
meta = channel.metadata
|
|
184
|
+
print(f"Name: {meta['name']}")
|
|
185
|
+
print(f"Subscribers: {meta['subscribers']}")
|
|
186
|
+
|
|
187
|
+
# Get uploads
|
|
188
|
+
uploads = channel.uploads(20)
|
|
189
|
+
|
|
190
|
+
# Check if live
|
|
191
|
+
if channel.live:
|
|
192
|
+
print(f"Currently streaming: {channel.streaming_now}")
|
|
193
|
+
|
|
194
|
+
# Get playlists
|
|
195
|
+
playlists = channel.playlists
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Playlist Operations
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
from webscout.Extra.YTToolkit.ytapi import Playlist
|
|
202
|
+
|
|
203
|
+
playlist = Playlist("PLrAXtmErZgOeiKm4sgNOknGvNjby9efdf")
|
|
204
|
+
|
|
205
|
+
# Get metadata
|
|
206
|
+
meta = playlist.metadata
|
|
207
|
+
print(f"Name: {meta['name']}")
|
|
208
|
+
print(f"Videos: {meta['video_count']}")
|
|
209
|
+
print(f"Video IDs: {meta['videos']}")
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## 🔧 Available Classes
|
|
213
|
+
|
|
214
|
+
| Class | Methods |
|
|
215
|
+
|-------|---------|
|
|
216
|
+
| `Video` | `metadata`, `embed_html`, `embed_url`, `thumbnail_url`, `thumbnail_urls`, `is_live`, `is_short`, `hashtags`, `get_related_videos`, `get_chapters`, `stream_comments` |
|
|
217
|
+
| `Channel` | `metadata`, `live`, `streaming_now`, `current_streams`, `old_streams`, `uploads`, `last_uploaded`, `upcoming`, `playlists` |
|
|
218
|
+
| `Playlist` | `metadata` |
|
|
219
|
+
| `Search` | `video`, `videos`, `channel`, `channels`, `playlist`, `playlists`, `shorts`, `live_streams`, `videos_by_duration`, `videos_by_upload_date` |
|
|
220
|
+
| `Suggestions` | `autocomplete`, `trending_searches` |
|
|
221
|
+
| `Shorts` | `is_short`, `get_trending`, `search` |
|
|
222
|
+
| `Hashtag` | `get_videos`, `get_metadata`, `extract_from_text` |
|
|
223
|
+
| `Captions` | `get_available_languages`, `get_transcript`, `get_timed_transcript`, `search_transcript` |
|
|
224
|
+
| `Extras` | `trending_videos`, `music_videos`, `gaming_videos`, `news_videos`, `live_videos`, `sport_videos`, `educational_videos`, `shorts_videos`, `movies`, `podcasts` |
|
|
225
|
+
|
|
226
|
+
## ⚠️ Notes
|
|
227
|
+
|
|
228
|
+
- All features work without a YouTube API key
|
|
229
|
+
- Some features may break if YouTube changes their HTML structure
|
|
230
|
+
- Rate limiting may apply for excessive requests
|
|
@@ -1,6 +1,22 @@
|
|
|
1
|
-
from .
|
|
2
|
-
from .
|
|
3
|
-
from .
|
|
4
|
-
from .extras import Extras
|
|
5
|
-
from .
|
|
6
|
-
from .playlist import Playlist
|
|
1
|
+
from .captions import Captions
|
|
2
|
+
from .channel import Channel
|
|
3
|
+
from .errors import *
|
|
4
|
+
from .extras import Extras
|
|
5
|
+
from .hashtag import Hashtag
|
|
6
|
+
from .playlist import Playlist
|
|
7
|
+
from .query import Search
|
|
8
|
+
from .shorts import Shorts
|
|
9
|
+
from .suggestions import Suggestions
|
|
10
|
+
from .video import Video
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'Video',
|
|
14
|
+
'Search',
|
|
15
|
+
'Extras',
|
|
16
|
+
'Channel',
|
|
17
|
+
'Playlist',
|
|
18
|
+
'Suggestions',
|
|
19
|
+
'Shorts',
|
|
20
|
+
'Hashtag',
|
|
21
|
+
'Captions'
|
|
22
|
+
]
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"""YouTube video captions and transcripts.
|
|
2
|
+
|
|
3
|
+
This module wraps the YTTranscriber for a simplified interface.
|
|
4
|
+
"""
|
|
5
|
+
import re
|
|
6
|
+
from typing import Any, Dict, List, Optional
|
|
7
|
+
|
|
8
|
+
from curl_cffi.requests import Session
|
|
9
|
+
|
|
10
|
+
# Use the existing robust YTTranscriber
|
|
11
|
+
from webscout.Extra.YTToolkit.transcriber import TranscriptListFetcher, YTTranscriber
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Captions:
|
|
15
|
+
"""Class for YouTube captions and transcripts.
|
|
16
|
+
|
|
17
|
+
Uses YTTranscriber internally for reliable transcript fetching.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> from webscout.Extra.YTToolkit.ytapi import Captions
|
|
21
|
+
>>> transcript = Captions.get_transcript("dQw4w9WgXcQ")
|
|
22
|
+
>>> print(transcript[:100])
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
@staticmethod
|
|
26
|
+
def _extract_video_id(video_id: str) -> str:
|
|
27
|
+
"""Extract clean video ID from URL or ID."""
|
|
28
|
+
if not video_id:
|
|
29
|
+
return ""
|
|
30
|
+
|
|
31
|
+
patterns = [
|
|
32
|
+
r'(?:v=|youtu\.be/|shorts/)([a-zA-Z0-9_-]{11})',
|
|
33
|
+
r'^([a-zA-Z0-9_-]{11})$'
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
for pattern in patterns:
|
|
37
|
+
match = re.search(pattern, video_id)
|
|
38
|
+
if match:
|
|
39
|
+
return match.group(1)
|
|
40
|
+
|
|
41
|
+
return video_id
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def get_available_languages(video_id: str) -> List[Dict[str, str]]:
|
|
45
|
+
"""
|
|
46
|
+
Get available caption languages for a video.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
video_id: YouTube video ID or URL
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
List of dicts with 'code', 'name', 'is_auto' for each language
|
|
53
|
+
"""
|
|
54
|
+
if not video_id:
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
video_id = Captions._extract_video_id(video_id)
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
session = Session()
|
|
61
|
+
session.headers.update({
|
|
62
|
+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
fetcher = TranscriptListFetcher(session)
|
|
66
|
+
transcript_list = fetcher.fetch(video_id)
|
|
67
|
+
|
|
68
|
+
languages = []
|
|
69
|
+
|
|
70
|
+
# Add manually created transcripts
|
|
71
|
+
for transcript in transcript_list._manually_created_transcripts.values():
|
|
72
|
+
languages.append({
|
|
73
|
+
'code': transcript.language_code,
|
|
74
|
+
'name': transcript.language,
|
|
75
|
+
'is_auto': False
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
# Add generated transcripts
|
|
79
|
+
for transcript in transcript_list._generated_transcripts.values():
|
|
80
|
+
languages.append({
|
|
81
|
+
'code': transcript.language_code,
|
|
82
|
+
'name': transcript.language,
|
|
83
|
+
'is_auto': True
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return languages
|
|
87
|
+
except Exception:
|
|
88
|
+
return []
|
|
89
|
+
|
|
90
|
+
@staticmethod
|
|
91
|
+
def get_transcript(video_id: str, language: str = "en") -> Optional[str]:
|
|
92
|
+
"""
|
|
93
|
+
Get plain text transcript for a video.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
video_id: YouTube video ID or URL
|
|
97
|
+
language: Language code (e.g., 'en', 'es')
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
Transcript text or None
|
|
101
|
+
"""
|
|
102
|
+
timed = Captions.get_timed_transcript(video_id, language)
|
|
103
|
+
if not timed:
|
|
104
|
+
return None
|
|
105
|
+
|
|
106
|
+
return " ".join([entry['text'] for entry in timed])
|
|
107
|
+
|
|
108
|
+
@staticmethod
|
|
109
|
+
def get_timed_transcript(video_id: str, language: str = "en") -> Optional[List[Dict[str, Any]]]:
|
|
110
|
+
"""
|
|
111
|
+
Get transcript with timestamps.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
video_id: YouTube video ID or URL
|
|
115
|
+
language: Language code (e.g., 'en', 'es'). Use 'any' for first available.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
List of dicts with 'text', 'start', 'duration' or None
|
|
119
|
+
"""
|
|
120
|
+
if not video_id:
|
|
121
|
+
return None
|
|
122
|
+
|
|
123
|
+
video_id = Captions._extract_video_id(video_id)
|
|
124
|
+
|
|
125
|
+
try:
|
|
126
|
+
# Use YTTranscriber for reliable fetching
|
|
127
|
+
transcript = YTTranscriber.get_transcript(
|
|
128
|
+
video_id,
|
|
129
|
+
languages=language if language != 'any' else None
|
|
130
|
+
)
|
|
131
|
+
return transcript
|
|
132
|
+
except Exception:
|
|
133
|
+
# If requested language fails, try any available
|
|
134
|
+
if language != 'any':
|
|
135
|
+
try:
|
|
136
|
+
transcript = YTTranscriber.get_transcript(video_id, languages=None)
|
|
137
|
+
return transcript
|
|
138
|
+
except Exception:
|
|
139
|
+
pass
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
@staticmethod
|
|
143
|
+
def search_transcript(video_id: str, query: str, language: str = "en") -> List[Dict[str, Any]]:
|
|
144
|
+
"""
|
|
145
|
+
Search within a video's transcript.
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
video_id: YouTube video ID or URL
|
|
149
|
+
query: Text to search for
|
|
150
|
+
language: Language code
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
List of matching segments with timestamps
|
|
154
|
+
"""
|
|
155
|
+
if not query:
|
|
156
|
+
return []
|
|
157
|
+
|
|
158
|
+
transcript = Captions.get_timed_transcript(video_id, language)
|
|
159
|
+
if not transcript:
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
query_lower = query.lower()
|
|
163
|
+
results = []
|
|
164
|
+
|
|
165
|
+
for entry in transcript:
|
|
166
|
+
if query_lower in entry['text'].lower():
|
|
167
|
+
results.append(entry)
|
|
168
|
+
|
|
169
|
+
return results
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
if __name__ == "__main__":
|
|
173
|
+
# Test with a video that has captions
|
|
174
|
+
video_id = "dQw4w9WgXcQ"
|
|
175
|
+
|
|
176
|
+
print("Available languages:")
|
|
177
|
+
langs = Captions.get_available_languages(video_id)
|
|
178
|
+
for lang in langs[:5]:
|
|
179
|
+
print(f" - {lang['code']}: {lang['name']} (auto: {lang.get('is_auto', False)})")
|
|
180
|
+
|
|
181
|
+
print("\nGetting transcript:")
|
|
182
|
+
transcript = Captions.get_timed_transcript(video_id)
|
|
183
|
+
if transcript:
|
|
184
|
+
print(f" Found {len(transcript)} segments")
|
|
185
|
+
for entry in transcript[:3]:
|
|
186
|
+
print(f" {entry['start']:.1f}s: {entry['text'][:50]}")
|
|
187
|
+
else:
|
|
188
|
+
print(" No transcript available")
|
|
189
|
+
|
|
190
|
+
|