py-youtube-search 0.2.3__py3-none-any.whl → 0.2.4__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.
@@ -1,6 +1,8 @@
1
1
  import re
2
2
  import aiohttp
3
3
  import asyncio
4
+ import requests
5
+
4
6
 
5
7
  # Filter constants accessible to the user
6
8
  class Filters:
@@ -78,6 +80,68 @@ class YouTubeSearch:
78
80
 
79
81
  return results
80
82
 
83
+
84
+ class YouTubeSearchSync:
85
+ def __init__(self):
86
+ """
87
+ Initialize the YouTubeSearchSync client.
88
+ The client is stateless; parameters are passed to the search method.
89
+ """
90
+ self.base_url = "https://www.youtube.com/results"
91
+ self.headers = {
92
+ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
93
+ }
94
+
95
+ def _fetch_source(self, query: str, sp: str = None):
96
+ params = {"search_query": query.replace(" ", "+")}
97
+ if sp:
98
+ params["sp"] = sp
99
+
100
+ response = requests.get(self.base_url, params=params, headers=self.headers)
101
+ return response.text
102
+
103
+ def search(self, query: str, sp: str = None, limit: int = 15):
104
+ """
105
+ Synchronously fetches and parses search results for the given query.
106
+
107
+ Args:
108
+ query (str): The search query.
109
+ sp (str, optional): The filter string (use Filters class). Defaults to None.
110
+ limit (int, optional): Max number of results. Defaults to 15.
111
+
112
+ Returns:
113
+ list: A list of dictionaries containing video details.
114
+ """
115
+ source = self._fetch_source(query, sp)
116
+
117
+ # Regex to capture distinct JSON fields for ID, Title, Duration, and Views.
118
+ pattern = (
119
+ r'\"videoRenderer\":\{'
120
+ r'.+?\"videoId\":\"(?P<id>\S{11})\"'
121
+ r'.+?\"title\":\{\"runs\":\[\{\"text\":\"(?P<title>.+?)\"\}\]'
122
+ r'.+?\"lengthText\":\{.*?\"simpleText\":\"(?P<duration>.+?)\"\}'
123
+ r'.+?\"viewCountText\":\{\"simpleText\":\"(?P<views>.+?)\"\}'
124
+ )
125
+
126
+ matches = re.finditer(pattern, source)
127
+
128
+ results = []
129
+ for match in matches:
130
+ if len(results) >= limit:
131
+ break
132
+
133
+ data = match.groupdict()
134
+ results.append({
135
+ "id": data["id"],
136
+ "title": data["title"],
137
+ "duration": data["duration"],
138
+ "views": data["views"],
139
+ "url_suffix": f"/watch?v={data['id']}"
140
+ })
141
+
142
+ return results
143
+
144
+
81
145
  # --- Usage Example (Async) ---
82
146
  # import asyncio
83
147
  # async def main():
@@ -94,3 +158,19 @@ class YouTubeSearch:
94
158
  # print(f"Found {len(videos2)} videos")
95
159
  #
96
160
  # asyncio.run(main())
161
+
162
+ # --- Usage Example (Sync) ---
163
+ # def main():
164
+ # yt = YouTubeSearchSync()
165
+ #
166
+ # # Search 1: Long videos about LangGraph
167
+ # print("Searching LangGraph...")
168
+ # videos1 = yt.search("LangGraph", sp=Filters.long_this_week, limit=5)
169
+ # print(f"Found {len(videos1)} videos")
170
+ #
171
+ # # Search 2: Short Python tutorials (reusing the same instance)
172
+ # print("Searching Python...")
173
+ # videos2 = yt.search("Python", sp=Filters.medium_today, limit=3)
174
+ # print(f"Found {len(videos2)} videos")
175
+ #
176
+ # main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: py-youtube-search
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: A lightweight, regex-based YouTube search library without API keys.
5
5
  Home-page: https://github.com/VishvaRam/py-youtube-search
6
6
  Author: VishvaRam
@@ -12,6 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
14
14
  Requires-Dist: aiohttp>=3.8.0
15
+ Requires-Dist: requests>=2.25.0
15
16
  Dynamic: author
16
17
  Dynamic: author-email
17
18
  Dynamic: classifier
@@ -25,12 +26,12 @@ Dynamic: summary
25
26
 
26
27
  # py-youtube-search
27
28
 
28
- A lightweight, asynchronous Python library to search YouTube videos programmatically without an API key.
29
- It scrapes search results using `aiohttp` and `re`, making it fast, robust, and perfect for high-performance applications.
29
+ A lightweight Python library to search YouTube videos programmatically without an API key.
30
+ It scrapes search results using regex, making it fast, robust, and perfect for both synchronous and asynchronous applications.
30
31
 
31
32
  ## Features
32
33
 
33
- - **Async Support**: Fully asynchronous using `aiohttp` for non-blocking execution.
34
+ - **Async & Sync Support**: Choose between fully asynchronous (`aiohttp`) or synchronous (`requests`) implementations.
34
35
  - **Reusable Client**: Create a single instance and run multiple searches with different configurations.
35
36
  - **No API Key Required**: Search YouTube directly without setting up Google Cloud projects.
36
37
  - **Advanced Filtering**: Built-in support for duration (Medium 3-20m, Long >20m) and upload date filters.
@@ -44,15 +45,15 @@ pip install py-youtube-search
44
45
 
45
46
  ## Quick Start
46
47
 
47
- ### 1. Basic Async Search
48
- Initialize the client once and run multiple searches.
48
+ ### 1. Async Search (Recommended for Concurrent Operations)
49
+ Perfect for FastAPI, async applications, or when running multiple searches concurrently.
49
50
 
50
51
  ```python
51
52
  import asyncio
52
53
  from py_youtube_search import YouTubeSearch
53
54
 
54
55
  async def main():
55
- # 1. Initialize the client (reusable)
56
+ # 1. Initialize the async client (reusable)
56
57
  yt = YouTubeSearch()
57
58
 
58
59
  # 2. Run a search
@@ -68,7 +69,30 @@ if __name__ == "__main__":
68
69
  asyncio.run(main())
69
70
  ```
70
71
 
71
- ### 2. Advanced Search with Filters
72
+ ### 2. Sync Search (Simple Scripts & Notebooks)
73
+ Perfect for simple scripts, Jupyter notebooks, or synchronous applications.
74
+
75
+ ```python
76
+ from py_youtube_search import YouTubeSearchSync
77
+
78
+ def main():
79
+ # 1. Initialize the sync client (reusable)
80
+ yt = YouTubeSearchSync()
81
+
82
+ # 2. Run a search
83
+ videos = yt.search("Python async tutorials", limit=5)
84
+
85
+ for v in videos:
86
+ print(f"Title: {v['title']}")
87
+ print(f"Duration: {v['duration']}")
88
+ print(f"Views: {v['views']}")
89
+ print(f"Link: https://www.youtube.com/watch?v={v['id']}\n")
90
+
91
+ if __name__ == "__main__":
92
+ main()
93
+ ```
94
+
95
+ ### 3. Advanced Search with Filters (Async)
72
96
  Search for specific content, like long-form videos (>20m) uploaded this week.
73
97
 
74
98
  ```python
@@ -96,6 +120,32 @@ if __name__ == "__main__":
96
120
  asyncio.run(main())
97
121
  ```
98
122
 
123
+ ### 4. Advanced Search with Filters (Sync)
124
+
125
+ ```python
126
+ from py_youtube_search import YouTubeSearchSync, Filters
127
+
128
+ def main():
129
+ yt = YouTubeSearchSync()
130
+
131
+ # Search 1: Long videos about LangGraph
132
+ print("Searching for LangGraph...")
133
+ videos = yt.search("LangGraph", sp=Filters.long_this_week, limit=3)
134
+
135
+ for v in videos:
136
+ print(f"🎥 {v['title']} | ⏱ {v['duration']} | 👁 {v['views']}")
137
+
138
+ # Search 2: Reusing the same client for a different query
139
+ print("\nSearching for Python...")
140
+ videos_py = yt.search("Python 3.12", sp=Filters.medium_today, limit=3)
141
+
142
+ for v in videos_py:
143
+ print(f"🐍 {v['title']}")
144
+
145
+ if __name__ == "__main__":
146
+ main()
147
+ ```
148
+
99
149
  ## Available Filters
100
150
 
101
151
  Pass these constants into the `sp` parameter of the `search()` method.
@@ -118,7 +168,7 @@ Pass these constants into the `sp` parameter of the `search()` method.
118
168
 
119
169
  ## Data Structure
120
170
 
121
- The `.search()` method returns a list of dictionaries:
171
+ Both `.search()` methods return a list of dictionaries:
122
172
 
123
173
  ```json
124
174
  [
@@ -132,8 +182,55 @@ The `.search()` method returns a list of dictionaries:
132
182
  ]
133
183
  ```
134
184
 
185
+ ## API Reference
186
+
187
+ ### `YouTubeSearch` (Async)
188
+
189
+ ```python
190
+ async def search(query: str, sp: str = None, limit: int = 15) -> list
191
+ ```
192
+
193
+ **Parameters:**
194
+ - `query` (str): The search query
195
+ - `sp` (str, optional): Filter string from `Filters` class
196
+ - `limit` (int, optional): Maximum number of results (default: 15)
197
+
198
+ **Returns:** List of video dictionaries
199
+
200
+ ### `YouTubeSearchSync` (Sync)
201
+
202
+ ```python
203
+ def search(query: str, sp: str = None, limit: int = 15) -> list
204
+ ```
205
+
206
+ **Parameters:**
207
+ - `query` (str): The search query
208
+ - `sp` (str, optional): Filter string from `Filters` class
209
+ - `limit` (int, optional): Maximum number of results (default: 15)
210
+
211
+ **Returns:** List of video dictionaries
212
+
213
+ ## When to Use Async vs Sync?
214
+
215
+ ### Use `YouTubeSearch` (Async) when:
216
+ - Building FastAPI, aiohttp, or other async web applications
217
+ - Running multiple searches concurrently
218
+ - Integrating with async frameworks or event loops
219
+
220
+ ### Use `YouTubeSearchSync` (Sync) when:
221
+ - Writing simple scripts or automation tools
222
+ - Working in Jupyter notebooks or interactive environments
223
+ - Building synchronous applications (Flask, Django views, etc.)
224
+
135
225
  ## Dependencies
136
- - `aiohttp` (for async requests)
226
+ - `aiohttp>=3.8.0` (for async version)
227
+ - `requests>=2.25.0` (for sync version)
137
228
 
138
229
  ## License
139
230
  MIT License. See LICENSE file for details.
231
+
232
+ ## Contributing
233
+ Contributions are welcome! Please feel free to submit a Pull Request.
234
+
235
+ ## Issues
236
+ If you encounter any problems, please file an issue on GitHub.
@@ -0,0 +1,5 @@
1
+ py_youtube_search/__init__.py,sha256=dUemIKQyFx1Gpc_-4iZyKDvYXMWJYXtK8a8p1CZEpGA,5999
2
+ py_youtube_search-0.2.4.dist-info/METADATA,sha256=pqGPEGid5FP5c0Pjv42N8TzM7wX84HOfpN7l4opcg3Q,6805
3
+ py_youtube_search-0.2.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
4
+ py_youtube_search-0.2.4.dist-info/top_level.txt,sha256=4EMqIznKjzwgAcB_78SKaMIzZXpIxWQ4SRLeakY3fzQ,18
5
+ py_youtube_search-0.2.4.dist-info/RECORD,,
@@ -1,5 +0,0 @@
1
- py_youtube_search/__init__.py,sha256=izTjs9UNT9lxj_atAEOPGa4a2kn-_URj7SkGMfDwNj4,3292
2
- py_youtube_search-0.2.3.dist-info/METADATA,sha256=pSiIS7-NPmQ5X7E0jfHyV8K4pDiHi8ZgXQrQa3f3iRE,4038
3
- py_youtube_search-0.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
4
- py_youtube_search-0.2.3.dist-info/top_level.txt,sha256=4EMqIznKjzwgAcB_78SKaMIzZXpIxWQ4SRLeakY3fzQ,18
5
- py_youtube_search-0.2.3.dist-info/RECORD,,