Last week, after analyzing the reasons for the high recognition rate with the YesWeScan library, it turned out that the recognition rate was poor when casting AVCapturePhoto to UIImage, but it improved significantly when using CMSampleBuffer cast to CIImage.
Additionally, to handle automatic text recognition without manually triggering capture actions, I found that by using AVCaptureVideo instead of AVCapturePhoto, I could input each frame and cast the received CMSampleBuffer to CIImage. This way, text recognition through Vision could automatically process cases when text was recognized.
Last week, I wrote a Python script to fetch video lists from a specific YouTube channel.
When the number of videos from a specific channel is very large, there are limits on the free API usage, so even if a delay is specified, it may not fetch all videos. Additionally, if there are separate videos in a playlist, I also created a script to fetch the video list from the playlist.
🔗 YouTube API Docs - playlistitem
import requests
import time
# Step 1: API Settings
API_KEY = '' # Enter your actual API key here
PLAYLIST_ID = '' # Playlist ID
CHANNEL_ID = '' # Channel ID to fetch titles from
MAX_RESULTS = 50 # Maximum number of results to fetch at once (up to 50)
# Base URL for YouTube Data API v3 playlistItems endpoint
youtube_url = 'https://www.googleapis.com/youtube/v3/playlistItems'
# Parameters required for the API request
params = {
'part': 'snippet',
'maxResults': MAX_RESULTS,
'playlistId': PLAYLIST_ID,
'key': API_KEY
}
# Function to fetch video titles and URLs from the playlist
def fetch_playlist_video_titles_and_urls():
videosResult = []
next_page_token = None
index = 1 # Starting index for videos
while True:
if next_page_token:
params['pageToken'] = next_page_token
# Step 2: Send GET request to YouTube Data API
response = requests.get(youtube_url, params=params)
data = response.json()
# Step 3: Extract video titles and URLs
for item in data['items']:
title = item['snippet']['title']
video_id = item['snippet']['resourceId']['videoId']
video_url = f'https://www.youtube.com/watch?v={video_id}&list={PLAYLIST_ID}&index={index}'
videosResult.append((title, video_url))
index += 1
# Check if there's a next page
next_page_token = data.get('nextPageToken')
# Wait 61 seconds if there's a next page
if not next_page_token:
break
return videosResult
# Function to save titles and URLs to a text file
def save_titles_and_urls_to_file(videos, filename='playlist_video_titles_and_urls.txt'):
with open(filename, 'w', encoding='utf-8') as file:
for index, (title, url) in enumerate(videos, start=1):
file.write(f"{index}. **[{title}]({url})**\n\n")
# Execute the code
videos = fetch_playlist_video_titles_and_urls()
save_titles_and_urls_to_file(videos)
playlist_video_titles_and_urls.txt
file.In iOS, some systems require permission to access certain features. For example, if location permission is needed, you must have permission to access location information.
You can determine the status of permissions using an enum object called AuthorizationStatus
.
For location access, it varies slightly with CLAuthorizationStatus
, but most cases fall into three categories that are frequently used: (Authorized
, Denied
, NotDetermined
).
Authorized
: Permission has been granted.Denied
: Permission has been denied.NotDetermined
: Permission has not yet been asked.The NotDetermined
state indicates that permission has not been requested. However, there can be instances where it remains NotDetermined
even after the app prompts for permission when it first starts, which was puzzling, and I found only information about potential errors when searching.
When making permission requests in a closure, it is important to ensure that UI-related tasks are performed on the main thread.
[A-Z0-91{2}_[A-Z0-9]{2}_[A-Z0-9]{2}
and ([A-Z0-9]{2}_){2}[A-Z0-9]{2}
are identical.@objc func keyboardWillShow(note: NSNotification) {
if let keyboardSize = (note.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
var keyboardHeight = CGFloat(Int(keyboardSize.height))
self.scrollView.snp.updateConstraints {
$0.bottom.equalToSuperView().offset(-keyboardHeight)
}
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
}