mirror of
https://github.com/chibicitiberiu/ytsm.git
synced 2024-02-24 05:43:31 +00:00
Added docker support
This commit is contained in:
0
app/external/__init__.py
vendored
Normal file
0
app/external/__init__.py
vendored
Normal file
19
app/external/pytaw/.gitignore
vendored
Normal file
19
app/external/pytaw/.gitignore
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
*.bak
|
||||
*.egg
|
||||
*.egg-info/
|
||||
*.eggs/
|
||||
*.pyproj
|
||||
*.sln
|
||||
*.vs/
|
||||
*~
|
||||
.DS_Store
|
||||
.cache/
|
||||
.coverage
|
||||
.idea/
|
||||
.tox/
|
||||
_build/
|
||||
build/
|
||||
dist/
|
||||
|
||||
__pycache__/
|
||||
*.ini
|
3
app/external/pytaw/.pytaw.conf
vendored
Normal file
3
app/external/pytaw/.pytaw.conf
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
; by default pytaw will look for this file (".pytaw.conf") in the user's home directory
|
||||
[youtube]
|
||||
developer_key = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
|
29
app/external/pytaw/README.md
vendored
Normal file
29
app/external/pytaw/README.md
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
# PYTAW: Python YouTube API Wrapper
|
||||
|
||||
###Note
|
||||
This library is copied from [https://github.com/chibicitiberiu/pytaw/tree/improvements](https://github.com/chibicitiberiu/pytaw/tree/improvements).
|
||||
|
||||
|
||||
```python
|
||||
>>> from pytaw import YouTube
|
||||
>>> youtube = YouTube(key='your_api_key')
|
||||
>>> video = youtube.video('4vuW6tQ0218')
|
||||
>>> video.title
|
||||
'Monty Python - Dead Parrot'
|
||||
>>> video.published_at
|
||||
datetime.datetime(2007, 2, 14, 13, 55, 51, tzinfo=tzutc())
|
||||
>>> channel = video.channel
|
||||
>>> channel.title
|
||||
'Chadner'
|
||||
>>> search = youtube.search(q='monty python')
|
||||
>>> search[0]
|
||||
<Channel UCGm3CO6LPcN-Y7HIuyE0Rew "Monty Python">
|
||||
>>> for r in search[:5]:
|
||||
... print(r)
|
||||
...
|
||||
Monty Python
|
||||
Chemist Sketch - Monty Python's Flying Circus
|
||||
A Selection of Sketches from "Monty Python's Flying Circus" - #4
|
||||
Monty Python - Dead Parrot
|
||||
Monty Python And the holy grail
|
||||
```
|
0
app/external/pytaw/__init__.py
vendored
Normal file
0
app/external/pytaw/__init__.py
vendored
Normal file
20
app/external/pytaw/docs/Makefile
vendored
Normal file
20
app/external/pytaw/docs/Makefile
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = pytaw
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
169
app/external/pytaw/docs/conf.py
vendored
Normal file
169
app/external/pytaw/docs/conf.py
vendored
Normal file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# pytaw documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Nov 27 19:26:35 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'pytaw'
|
||||
copyright = '2017, 6000hulls'
|
||||
author = '6000hulls'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'sphinx_rtd_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# This is required for the alabaster theme
|
||||
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
|
||||
html_sidebars = {
|
||||
'**': [
|
||||
'relations.html', # needs 'show_related': True theme option to display
|
||||
'searchbox.html',
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'pytawdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'pytaw.tex', 'pytaw Documentation',
|
||||
'6000hulls', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'pytaw', 'pytaw Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'pytaw', 'pytaw Documentation',
|
||||
author, 'pytaw', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
18
app/external/pytaw/docs/index.rst
vendored
Normal file
18
app/external/pytaw/docs/index.rst
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
PYTAW: Python YouTube API Wrapper
|
||||
=================================
|
||||
|
||||
It's a wrapper for the YouTube python API. Written in python.
|
||||
|
||||
.. automodule:: pytaw.youtube
|
||||
:members:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
36
app/external/pytaw/docs/make.bat
vendored
Normal file
36
app/external/pytaw/docs/make.bat
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
set SPHINXPROJ=pytaw
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
13
app/external/pytaw/main_test.py
vendored
Normal file
13
app/external/pytaw/main_test.py
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import pytaw
|
||||
|
||||
yt = pytaw.YouTube(key='AIzaSyBabzE4Bup77WexdLMa9rN9z-wJidEfNX8')
|
||||
c = yt.channel('UCmmPgObSUPw1HL2lq6H4ffA')
|
||||
|
||||
uploads_playlist = c.uploads_playlist
|
||||
print(repr(uploads_playlist))
|
||||
|
||||
uploads_list = list(uploads_playlist.items)
|
||||
for item in uploads_list:
|
||||
print(item.position, '...', repr(item), ' .... ', repr(item.video))
|
||||
print(item.thumbnails)
|
||||
break
|
1
app/external/pytaw/pytaw/__init__.py
vendored
Normal file
1
app/external/pytaw/pytaw/__init__.py
vendored
Normal file
@ -0,0 +1 @@
|
||||
from .youtube import YouTube
|
92
app/external/pytaw/pytaw/utils.py
vendored
Normal file
92
app/external/pytaw/pytaw/utils.py
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
import re
|
||||
import urllib.parse
|
||||
import typing
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import dateutil.parser
|
||||
import itertools
|
||||
|
||||
def string_to_datetime(string):
|
||||
if string is None:
|
||||
return None
|
||||
else:
|
||||
return dateutil.parser.parse(string)
|
||||
|
||||
|
||||
def datetime_to_string(dt):
|
||||
if dt is None:
|
||||
return None
|
||||
if dt.tzinfo is None:
|
||||
dt = dt.astimezone(timezone.utc)
|
||||
return dt.isoformat()
|
||||
|
||||
|
||||
def youtube_url_to_id(url):
|
||||
"""Extract video id from a youtube url.
|
||||
|
||||
If parsing fails, try regex. If that fails, return None.
|
||||
|
||||
The regex is from somewhere in this thread, I think:
|
||||
https://stackoverflow.com/questions/3452546/how-do-i-get-the-youtube-video-id-from-a-url
|
||||
|
||||
"""
|
||||
url = urllib.parse.unquote(url)
|
||||
url_data = urllib.parse.urlparse(url)
|
||||
query = urllib.parse.parse_qs(url_data.query)
|
||||
try:
|
||||
# parse the url for a video query
|
||||
return query["v"][0]
|
||||
except KeyError:
|
||||
# use regex to try and extract id
|
||||
match = re.search(
|
||||
r"((?<=(v|V)/)|(?<=be/)|(?<=(\?|\&)v=)|(?<=embed/))([\w-]+)",
|
||||
url,
|
||||
)
|
||||
if match:
|
||||
return match.group()
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def youtube_duration_to_seconds(value):
|
||||
"""Convert youtube (ISO 8601) duration to seconds.
|
||||
|
||||
https://en.wikipedia.org/wiki/ISO_8601#Durations
|
||||
https://regex101.com/r/ALmmSS/1
|
||||
|
||||
"""
|
||||
iso8601 = r"P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)W)?(?:(\d+)D)?T?(?:(\d+)H)?(?:(\d+)M)?(?:(\d+)S)?"
|
||||
match = re.match(iso8601, value)
|
||||
if match is None:
|
||||
return None
|
||||
|
||||
group_names = ['years', 'months', 'weeks', 'days', 'hours', 'minutes', 'seconds']
|
||||
d = dict()
|
||||
for name, group in zip(group_names, match.groups(default=0)):
|
||||
d[name] = int(group)
|
||||
|
||||
return int(
|
||||
d['years']*365*24*60*60 +
|
||||
d['months']*30*24*60*60 +
|
||||
d['weeks']*7*24*60*60 +
|
||||
d['days']*24*60*60 +
|
||||
d['hours']*60*60 +
|
||||
d['minutes']*60 +
|
||||
d['seconds']
|
||||
)
|
||||
|
||||
|
||||
def iterate_chunks(iterable: typing.Iterable, chunk_size: int):
|
||||
"""
|
||||
Iterates an iterable in chunks of chunk_size elements.
|
||||
:param iterable: An iterable containing items to iterate.
|
||||
:param chunk_size: Chunk size
|
||||
:return: Returns a generator which will yield chunks of size chunk_size
|
||||
"""
|
||||
|
||||
it = iter(iterable)
|
||||
while True:
|
||||
chunk = tuple(itertools.islice(it, chunk_size))
|
||||
if not chunk:
|
||||
return
|
||||
yield chunk
|
1055
app/external/pytaw/pytaw/youtube.py
vendored
Normal file
1055
app/external/pytaw/pytaw/youtube.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
12
app/external/pytaw/setup.py
vendored
Normal file
12
app/external/pytaw/setup.py
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
from setuptools import setup
|
||||
|
||||
setup(
|
||||
name='pytaw',
|
||||
version='0.0.1',
|
||||
packages=['pytaw'],
|
||||
url='https://github.com/6000hulls/pytaw',
|
||||
license='',
|
||||
author='6000hulls',
|
||||
author_email='6000hulls@gmail.com',
|
||||
description='PYTAW: Python YouTube API Wrapper'
|
||||
)
|
0
app/external/pytaw/tests/__init__.py
vendored
Normal file
0
app/external/pytaw/tests/__init__.py
vendored
Normal file
165
app/external/pytaw/tests/test_pytaw.py
vendored
Normal file
165
app/external/pytaw/tests/test_pytaw.py
vendored
Normal file
@ -0,0 +1,165 @@
|
||||
import pytest
|
||||
import logging
|
||||
import sys
|
||||
import collections
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from googleapiclient.errors import HttpError
|
||||
|
||||
from pytaw import YouTube
|
||||
from pytaw.youtube import Resource, Video, AttributeDef
|
||||
|
||||
|
||||
logging.basicConfig(stream=sys.stdout) # show log output when run with pytest -s
|
||||
log = logging.getLogger(__name__)
|
||||
log.setLevel(logging.INFO)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def youtube():
|
||||
"""A YouTube instance initialised with a developer key loaded from config.ini"""
|
||||
return YouTube()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def video(youtube):
|
||||
"""A Video instance for the classic video 'Me at the zoo'"""
|
||||
return youtube.video('jNQXAC9IVRw')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def channel(youtube):
|
||||
"""A Channel instance for the 'YouTube Help' channel"""
|
||||
return youtube.channel('UCMDQxm7cUx3yXkfeHa5zJIQ')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def search(youtube):
|
||||
"""A ListResponse instance corresponding to a search for the query 'python'"""
|
||||
return youtube.search()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def video_search(youtube):
|
||||
"""A ListResponse instance corresponding to a video search for the query 'python'"""
|
||||
return youtube.search(q='python', type='video')
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def video_search_array(youtube):
|
||||
"""An array of video searches with a wide range of results (zero to millions)."""
|
||||
one_minute_ago = datetime.utcnow() - timedelta(minutes=1)
|
||||
five_minutes_ago = datetime.utcnow() - timedelta(minutes=5)
|
||||
return [
|
||||
#
|
||||
# no results
|
||||
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2000, 1, 1)),
|
||||
#
|
||||
# less than 100 results
|
||||
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2005, 7, 1)),
|
||||
#
|
||||
# over 100 results
|
||||
youtube.search(q='minecraft', type='video', publishedBefore=datetime(2006, 1, 1)),
|
||||
#
|
||||
# variable number of results (hundreds or thousands...?)
|
||||
youtube.search(q='minecraft', type='video', publishedAfter=one_minute_ago),
|
||||
youtube.search(q='minecraft', type='video', publishedAfter=five_minutes_ago),
|
||||
#
|
||||
# over a million results
|
||||
youtube.search(q='minecraft', type='video'),
|
||||
youtube.search(q='minecraft'),
|
||||
]
|
||||
|
||||
|
||||
class TestResource:
|
||||
|
||||
def test_equality(self, search):
|
||||
a = search[0]
|
||||
b = search[0]
|
||||
c = search[1]
|
||||
assert a == b
|
||||
assert a != c
|
||||
|
||||
def test_unknown_attribute(self, video):
|
||||
with pytest.raises(AttributeError):
|
||||
_ = video.attribute_name_which_definitely_will_never_exist
|
||||
|
||||
def test_unknown_part_in_attributedef(self, video):
|
||||
video.ATTRIBUTE_DEFS['x'] = AttributeDef('nonexistant_part', 'x')
|
||||
with pytest.raises(HttpError):
|
||||
_ = video.x
|
||||
|
||||
def test_unknown_attribute_name_in_attributedef(self, video):
|
||||
video.ATTRIBUTE_DEFS['x'] = AttributeDef('snippet', 'nonexistant_attribute')
|
||||
assert video.x is None
|
||||
|
||||
|
||||
class TestVideo:
|
||||
|
||||
def test_bad_video_id(self, youtube):
|
||||
video = youtube.video('not_a_valid_youtube_video_id')
|
||||
assert video is None
|
||||
|
||||
def test_title(self, video):
|
||||
assert video.title == "Me at the zoo"
|
||||
|
||||
def test_published_at(self, video):
|
||||
assert video.published_at.isoformat() == '2005-04-24T03:31:52+00:00'
|
||||
|
||||
def test_n_views(self, video):
|
||||
assert video.n_views > int(40e6)
|
||||
|
||||
def test_tags(self, video):
|
||||
assert video.tags == ['jawed', 'karim', 'elephant', 'zoo', 'youtube', 'first', 'video']
|
||||
|
||||
def test_duration(self, video):
|
||||
assert video.duration.total_seconds() == 19
|
||||
|
||||
|
||||
class TestChannel:
|
||||
|
||||
def test_title(self, channel):
|
||||
assert channel.title == "YouTube Help"
|
||||
|
||||
|
||||
class TestSearch:
|
||||
|
||||
def test_video_search_returns_a_video(self, video_search):
|
||||
assert isinstance(video_search[0], Video)
|
||||
|
||||
def test_video_search_has_many_results(self, video_search):
|
||||
# make video_search unlazy (populate pageInfo attributes)
|
||||
_ = video_search[0]
|
||||
assert video_search.total_results > 10000
|
||||
|
||||
def test_search_iteration(self, search):
|
||||
"""Simply iterate over a search, creating all resources, to check for exceptions."""
|
||||
for resource in search:
|
||||
log.debug(resource)
|
||||
|
||||
|
||||
class TestListResponse:
|
||||
|
||||
def test_if_iterable(self, search):
|
||||
assert isinstance(search, collections.Iterator)
|
||||
|
||||
def test_integer_indexing(self, search):
|
||||
assert isinstance(search[0], Resource)
|
||||
|
||||
def test_slice_indexing(self, search):
|
||||
assert isinstance(search[1:3], list)
|
||||
|
||||
def test_full_listing_iteration(self, video_search_array):
|
||||
"""Iterate over all search results to check no exceptions are raised when paging etc.
|
||||
|
||||
Even if millions of results are found, the API will never return more than 500 (by
|
||||
design), so we're okay to just bang right through the search results generator for the
|
||||
whole array of video searches.
|
||||
|
||||
"""
|
||||
for i, search in enumerate(video_search_array):
|
||||
c = 0
|
||||
for _ in search:
|
||||
c += 1
|
||||
|
||||
log.debug(f"checked first {c} results (search #{i})")
|
Reference in New Issue
Block a user