@@ -52,6 +52,8 @@ defmodule Pinchflat.Downloading.MediaDownloader do
52
52
# Looks complicated, but here's the key points:
53
53
# - download_with_options runs a pre-check to see if the media item is suitable for download.
54
54
# - If the media item fails the precheck, it returns {:error, :unsuitable_for_download, message}
55
+ # - However, if the precheck fails in a way that we think can be fixed by using cookies, we retry with cookies
56
+ # and return the result of that
55
57
# - If the precheck passes but the download fails, it normally returns {:error, :download_failed, message}
56
58
# - However, there are some errors we can recover from (eg: failure to communicate with SponsorBlock).
57
59
# In this case, we attempt the download anyway and update the media item with what details we do have.
@@ -68,6 +70,8 @@ defmodule Pinchflat.Downloading.MediaDownloader do
68
70
# - `:unrecoverable` if there was an initial failure and the recovery attempt failed
69
71
# - `:download_failed` for all other yt-dlp-related downloading errors
70
72
# - `:unknown` for any other errors, including those not related to yt-dlp
73
+ # - If we retry using cookies, all of the above return values apply. The cookie retry
74
+ # logic is handled transparently as far as the caller is concerned
71
75
defp attempt_download_and_update_for_media_item ( media_item , override_opts ) do
72
76
output_filepath = FilesystemUtils . generate_metadata_tmpfile ( :json )
73
77
media_with_preloads = Repo . preload ( media_item , [ :metadata , source: :media_profile ] )
@@ -152,14 +156,48 @@ defmodule Pinchflat.Downloading.MediaDownloader do
152
156
153
157
defp download_with_options ( url , item_with_preloads , output_filepath , override_opts ) do
154
158
{ :ok , options } = DownloadOptionBuilder . build ( item_with_preloads , override_opts )
159
+ force_use_cookies = Keyword . get ( override_opts , :force_use_cookies , false )
160
+ source_uses_cookies = Sources . use_cookies? ( item_with_preloads . source , :downloading )
161
+ should_use_cookies = force_use_cookies || source_uses_cookies
155
162
156
- use_cookies = Sources . use_cookies? ( item_with_preloads . source , :downloading )
157
- runner_opts = [ output_filepath: output_filepath , use_cookies: use_cookies ]
163
+ runner_opts = [ output_filepath: output_filepath , use_cookies: should_use_cookies ]
158
164
159
- case YtDlpMedia . get_downloadable_status ( url , use_cookies: use_cookies ) do
160
- { :ok , :downloadable } -> YtDlpMedia . download ( url , options , runner_opts )
161
- { :ok , :ignorable } -> { :error , :unsuitable_for_download }
162
- err -> err
165
+ case { YtDlpMedia . get_downloadable_status ( url , use_cookies: should_use_cookies ) , should_use_cookies } do
166
+ { { :ok , :downloadable } , _ } ->
167
+ YtDlpMedia . download ( url , options , runner_opts )
168
+
169
+ { { :ok , :ignorable } , _ } ->
170
+ { :error , :unsuitable_for_download }
171
+
172
+ { { :error , _message , _exit_code } = err , false } ->
173
+ # If there was an error and we don't have cookies, this method will retry with cookies
174
+ # if doing so would help AND the source allows. Otherwise, it will return the error as-is
175
+ maybe_retry_with_cookies ( url , item_with_preloads , output_filepath , override_opts , err )
176
+
177
+ # This gets hit if cookies are enabled which, importantly, also covers the case where we
178
+ # retry a download with cookies and it fails again
179
+ { { :error , message , exit_code } , true } ->
180
+ { :error , message , exit_code }
181
+
182
+ { err , _ } ->
183
+ err
184
+ end
185
+ end
186
+
187
+ defp maybe_retry_with_cookies ( url , item_with_preloads , output_filepath , override_opts , err ) do
188
+ { :error , message , _ } = err
189
+ source = item_with_preloads . source
190
+ message_contains_cookie_error = String . contains? ( to_string ( message ) , recoverable_cookie_errors ( ) )
191
+
192
+ if Sources . use_cookies? ( source , :error_recovery ) && message_contains_cookie_error do
193
+ download_with_options (
194
+ url ,
195
+ item_with_preloads ,
196
+ output_filepath ,
197
+ Keyword . put ( override_opts , :force_use_cookies , true )
198
+ )
199
+ else
200
+ err
163
201
end
164
202
end
165
203
@@ -168,4 +206,11 @@ defmodule Pinchflat.Downloading.MediaDownloader do
168
206
"Unable to communicate with SponsorBlock"
169
207
]
170
208
end
209
+
210
+ defp recoverable_cookie_errors do
211
+ [
212
+ "Sign in to confirm" ,
213
+ "This video is available to this channel's members"
214
+ ]
215
+ end
171
216
end
0 commit comments