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,118 +1,178 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
trending_feeds,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
trending_sports
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
from
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
"""
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"""
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
1
|
+
from typing import List, Optional
|
|
2
|
+
|
|
3
|
+
from .https import (
|
|
4
|
+
_get_trending_learning_videos,
|
|
5
|
+
trending_feeds,
|
|
6
|
+
trending_games,
|
|
7
|
+
trending_songs,
|
|
8
|
+
trending_sports,
|
|
9
|
+
trending_streams,
|
|
10
|
+
trending_videos,
|
|
11
|
+
)
|
|
12
|
+
from .patterns import _ExtraPatterns as Patterns
|
|
13
|
+
from .utils import dup_filter, request
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Extras:
|
|
17
|
+
|
|
18
|
+
@staticmethod
|
|
19
|
+
def trending_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
20
|
+
"""
|
|
21
|
+
Get trending videos from YouTube.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
limit (int, optional): Maximum number of videos to return.
|
|
25
|
+
Alternatively, manual slicing can be used:
|
|
26
|
+
Extras.trending_videos()[:5]
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
30
|
+
"""
|
|
31
|
+
data = Patterns.video_id.findall(trending_videos())
|
|
32
|
+
return dup_filter(data, limit) if data else None
|
|
33
|
+
|
|
34
|
+
@staticmethod
|
|
35
|
+
def music_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
36
|
+
"""
|
|
37
|
+
Get trending music videos from YouTube.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
limit (int, optional): Maximum number of videos to return.
|
|
41
|
+
Alternatively, manual slicing can be used:
|
|
42
|
+
Extras.music_videos()[:5]
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
46
|
+
"""
|
|
47
|
+
data = Patterns.video_id.findall(trending_songs())
|
|
48
|
+
return dup_filter(data, limit) if data else None
|
|
49
|
+
|
|
50
|
+
@staticmethod
|
|
51
|
+
def gaming_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
52
|
+
"""
|
|
53
|
+
Get trending gaming videos from YouTube.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
limit (int, optional): Maximum number of videos to return.
|
|
57
|
+
Alternatively, manual slicing can be used:
|
|
58
|
+
Extras.gaming_videos()[:5]
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
62
|
+
"""
|
|
63
|
+
return dup_filter(Patterns.video_id.findall(trending_games()), limit)
|
|
64
|
+
|
|
65
|
+
@staticmethod
|
|
66
|
+
def news_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
67
|
+
"""
|
|
68
|
+
Get trending news videos from YouTube.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
limit (int, optional): Maximum number of videos to return.
|
|
72
|
+
Alternatively, manual slicing can be used:
|
|
73
|
+
Extras.news_videos()[:5]
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
77
|
+
"""
|
|
78
|
+
return dup_filter(Patterns.video_id.findall(trending_feeds()), limit)
|
|
79
|
+
|
|
80
|
+
@staticmethod
|
|
81
|
+
def live_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
82
|
+
"""
|
|
83
|
+
Get trending live videos from YouTube.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
limit (int, optional): Maximum number of videos to return.
|
|
87
|
+
Alternatively, manual slicing can be used:
|
|
88
|
+
Extras.live_videos()[:5]
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
92
|
+
"""
|
|
93
|
+
return dup_filter(Patterns.video_id.findall(trending_streams()), limit)
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def educational_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
97
|
+
"""
|
|
98
|
+
Get trending educational videos from YouTube.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
limit (int, optional): Maximum number of videos to return.
|
|
102
|
+
Alternatively, manual slicing can be used:
|
|
103
|
+
Extras.educational_videos()[:5]
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
107
|
+
"""
|
|
108
|
+
return dup_filter(Patterns.video_id.findall(_get_trending_learning_videos()), limit)
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
def sport_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
112
|
+
"""
|
|
113
|
+
Get trending sports videos from YouTube.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
limit (int, optional): Maximum number of videos to return.
|
|
117
|
+
Alternatively, manual slicing can be used:
|
|
118
|
+
Extras.sport_videos()[:5]
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Optional[List[str]]: List of video IDs or None if no videos found
|
|
122
|
+
"""
|
|
123
|
+
return dup_filter(Patterns.video_id.findall(trending_sports()), limit)
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def shorts_videos(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
127
|
+
"""
|
|
128
|
+
Get trending YouTube Shorts.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
limit (int, optional): Maximum number of Shorts to return.
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
Optional[List[str]]: List of video IDs or None if no Shorts found
|
|
135
|
+
"""
|
|
136
|
+
try:
|
|
137
|
+
html = request("https://www.youtube.com/shorts")
|
|
138
|
+
video_ids = Patterns.video_id.findall(html)
|
|
139
|
+
return dup_filter(video_ids, limit) if video_ids else None
|
|
140
|
+
except Exception:
|
|
141
|
+
return None
|
|
142
|
+
|
|
143
|
+
@staticmethod
|
|
144
|
+
def movies(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
145
|
+
"""
|
|
146
|
+
Get featured movies from YouTube.
|
|
147
|
+
|
|
148
|
+
Args:
|
|
149
|
+
limit (int, optional): Maximum number of movies to return.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Optional[List[str]]: List of video IDs or None if no movies found
|
|
153
|
+
"""
|
|
154
|
+
try:
|
|
155
|
+
html = request("https://www.youtube.com/feed/storefront")
|
|
156
|
+
video_ids = Patterns.video_id.findall(html)
|
|
157
|
+
return dup_filter(video_ids, limit) if video_ids else None
|
|
158
|
+
except Exception:
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
@staticmethod
|
|
162
|
+
def podcasts(limit: Optional[int] = None) -> Optional[List[str]]:
|
|
163
|
+
"""
|
|
164
|
+
Get trending podcasts from YouTube.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
limit (int, optional): Maximum number of podcasts to return.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Optional[List[str]]: List of video IDs or None if no podcasts found
|
|
171
|
+
"""
|
|
172
|
+
try:
|
|
173
|
+
html = request("https://www.youtube.com/podcasts")
|
|
174
|
+
video_ids = Patterns.video_id.findall(html)
|
|
175
|
+
return dup_filter(video_ids, limit) if video_ids else None
|
|
176
|
+
except Exception:
|
|
177
|
+
return None
|
|
178
|
+
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""YouTube Hashtag functionality."""
|
|
2
|
+
import re
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
from urllib.parse import quote
|
|
5
|
+
|
|
6
|
+
from .patterns import _ExtraPatterns as Patterns
|
|
7
|
+
from .utils import dup_filter, request
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Hashtag:
|
|
11
|
+
"""Class for YouTube hashtag operations."""
|
|
12
|
+
|
|
13
|
+
BASE_URL = "https://www.youtube.com/hashtag"
|
|
14
|
+
|
|
15
|
+
@staticmethod
|
|
16
|
+
def get_videos(tag: str, limit: int = 20) -> List[str]:
|
|
17
|
+
"""
|
|
18
|
+
Get videos associated with a hashtag.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
tag: Hashtag (with or without #)
|
|
22
|
+
limit: Maximum number of videos to return
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
List of video IDs
|
|
26
|
+
"""
|
|
27
|
+
if not tag:
|
|
28
|
+
return []
|
|
29
|
+
|
|
30
|
+
# Remove # if present and clean the tag
|
|
31
|
+
tag = tag.lstrip('#').strip().lower()
|
|
32
|
+
tag = re.sub(r'[^a-zA-Z0-9]', '', tag)
|
|
33
|
+
|
|
34
|
+
if not tag:
|
|
35
|
+
return []
|
|
36
|
+
|
|
37
|
+
url = f"{Hashtag.BASE_URL}/{quote(tag)}"
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
html = request(url)
|
|
41
|
+
video_ids = Patterns.video_id.findall(html)
|
|
42
|
+
return dup_filter(video_ids, limit)
|
|
43
|
+
except Exception:
|
|
44
|
+
return []
|
|
45
|
+
|
|
46
|
+
@staticmethod
|
|
47
|
+
def get_metadata(tag: str) -> Dict[str, Any]:
|
|
48
|
+
"""
|
|
49
|
+
Get metadata about a hashtag.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
tag: Hashtag (with or without #)
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Dictionary with hashtag info (name, video_count if available)
|
|
56
|
+
"""
|
|
57
|
+
if not tag:
|
|
58
|
+
return {}
|
|
59
|
+
|
|
60
|
+
tag = tag.lstrip('#').strip().lower()
|
|
61
|
+
tag = re.sub(r'[^a-zA-Z0-9]', '', tag)
|
|
62
|
+
|
|
63
|
+
if not tag:
|
|
64
|
+
return {}
|
|
65
|
+
|
|
66
|
+
url = f"{Hashtag.BASE_URL}/{quote(tag)}"
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
html = request(url)
|
|
70
|
+
|
|
71
|
+
# Try to extract video count if available
|
|
72
|
+
video_count_match = re.search(r'"videoCountText":\s*\{\s*"runs":\s*\[\s*\{\s*"text":\s*"([^"]+)"', html)
|
|
73
|
+
video_count = video_count_match.group(1) if video_count_match else None
|
|
74
|
+
|
|
75
|
+
# Get sample of videos
|
|
76
|
+
video_ids = Patterns.video_id.findall(html)
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
'tag': tag,
|
|
80
|
+
'url': url,
|
|
81
|
+
'video_count': video_count,
|
|
82
|
+
'sample_videos': dup_filter(video_ids, 10)
|
|
83
|
+
}
|
|
84
|
+
except Exception:
|
|
85
|
+
return {'tag': tag, 'url': url}
|
|
86
|
+
|
|
87
|
+
@staticmethod
|
|
88
|
+
def extract_from_text(text: str) -> List[str]:
|
|
89
|
+
"""
|
|
90
|
+
Extract hashtags from text.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
text: Text containing hashtags
|
|
94
|
+
|
|
95
|
+
Returns:
|
|
96
|
+
List of hashtags found
|
|
97
|
+
"""
|
|
98
|
+
if not text:
|
|
99
|
+
return []
|
|
100
|
+
|
|
101
|
+
pattern = r'#([a-zA-Z0-9_]+)'
|
|
102
|
+
matches = re.findall(pattern, text)
|
|
103
|
+
return list(dict.fromkeys(matches)) # Remove duplicates, preserve order
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
if __name__ == "__main__":
|
|
107
|
+
print("Testing Hashtag.get_videos:")
|
|
108
|
+
videos = Hashtag.get_videos("python", 5)
|
|
109
|
+
for vid in videos:
|
|
110
|
+
print(f" - {vid}")
|
|
111
|
+
|
|
112
|
+
print("\nHashtag metadata:")
|
|
113
|
+
meta = Hashtag.get_metadata("coding")
|
|
114
|
+
print(f" Tag: {meta.get('tag')}")
|
|
115
|
+
print(f" Videos: {len(meta.get('sample_videos', []))}")
|
|
116
|
+
|
|
117
|
+
print("\nExtract hashtags:")
|
|
118
|
+
text = "Check out my new #python #tutorial for #beginners!"
|
|
119
|
+
tags = Hashtag.extract_from_text(text)
|
|
120
|
+
print(f" Found: {tags}")
|
|
@@ -1,88 +1,89 @@
|
|
|
1
|
-
from urllib.parse import quote
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
1
|
+
from urllib.parse import quote
|
|
2
|
+
|
|
3
|
+
from .utils import request
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def channel_about(head: str) -> str:
|
|
7
|
+
return request(head + '/about')
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def video_count(channel_id: str) -> str:
|
|
11
|
+
head = 'https://www.youtube.com/results?search_query='
|
|
12
|
+
tail = '&sp=EgIQAg%253D%253D'
|
|
13
|
+
return request(head + channel_id + tail)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def uploads_data(head: str) -> str:
|
|
17
|
+
url = head + '/videos'
|
|
18
|
+
return request(url)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def streams_data(head: str) -> str:
|
|
22
|
+
url = head + '/streams'
|
|
23
|
+
return request(url)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def channel_playlists(head: str) -> str:
|
|
27
|
+
url = head + '/playlists'
|
|
28
|
+
return request(url)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def upcoming_videos(head: str) -> str:
|
|
32
|
+
url = head + '/videos?view=2&live_view=502'
|
|
33
|
+
return request(url)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def video_data(video_id: str) -> str:
|
|
37
|
+
url = f'https://www.youtube.com/watch?v={video_id}'
|
|
38
|
+
return request(url)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def playlist_data(playlist_id: str) -> str:
|
|
42
|
+
url = 'https://www.youtube.com/playlist?list=' + playlist_id
|
|
43
|
+
return request(url)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def trending_videos() -> str:
|
|
47
|
+
return request('https://www.youtube.com/feed/trending')
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def trending_songs() -> str:
|
|
51
|
+
return request('https://www.youtube.com/feed/music')
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def trending_games() -> str:
|
|
55
|
+
return request('https://www.youtube.com/gaming')
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def trending_feeds() -> str:
|
|
59
|
+
return request('https://www.youtube.com/news')
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def trending_streams() -> str:
|
|
63
|
+
return request('https://www.youtube.com/live')
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _get_trending_learning_videos() -> str:
|
|
67
|
+
return request('https://www.youtube.com/learning')
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def trending_sports() -> str:
|
|
71
|
+
return request('https://www.youtube.com/sports')
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def find_videos(query: str) -> str:
|
|
75
|
+
head = 'https://www.youtube.com/results?search_query='
|
|
76
|
+
tail = '&sp=EgIQAQ%253D%253D'
|
|
77
|
+
return request(head + quote(query) + tail)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def find_channels(query: str) -> str:
|
|
81
|
+
head = 'https://www.youtube.com/results?search_query='
|
|
82
|
+
tail = '&sp=EgIQAg%253D%253D'
|
|
83
|
+
return request(head + quote(query) + tail)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def find_playlists(query: str) -> str:
|
|
87
|
+
head = 'https://www.youtube.com/results?search_query='
|
|
88
|
+
tail = '&sp=EgIQAw%253D%253D'
|
|
89
|
+
return request(head + quote(query) + tail)
|