From 0200572011cad8b5a0d35fb0ae790f945c1b7256 Mon Sep 17 00:00:00 2001 From: tigeren Date: Wed, 8 Jan 2025 00:33:30 +0800 Subject: [PATCH] v3 version --- Download-ODLivePhotosV2.ps1 | 255 +++++++++++++++++++++--------------- 1 file changed, 152 insertions(+), 103 deletions(-) diff --git a/Download-ODLivePhotosV2.ps1 b/Download-ODLivePhotosV2.ps1 index 73c15a6..8526404 100644 --- a/Download-ODLivePhotosV2.ps1 +++ b/Download-ODLivePhotosV2.ps1 @@ -37,23 +37,45 @@ foreach ($module in $requiredModules) { function Connect-GraphWithDebug { try { - # Required scopes for OneDrive access $scopes = @( "Files.Read.All", "Files.ReadWrite.All", + "Files.Read", + "Files.ReadWrite", "offline_access", "openid", "profile" ) Write-Host "Connecting to Microsoft Graph..." - Connect-MgGraph -Scopes $scopes + # Force a new token by disconnecting first + Disconnect-MgGraph -ErrorAction SilentlyContinue - # Get and display current connection info + # Try to connect and verify the connection worked + Connect-MgGraph -Scopes $scopes $context = Get-MgContext + + if (-not $context -or [string]::IsNullOrEmpty($context.Account)) { + Write-Error "Failed to authenticate with Microsoft Graph - no valid context" + return $false + } + Write-Host "Connected as: $($context.Account)" Write-Host "Scopes: $($context.Scopes -join ', ')" + # Verify we can actually access the API + try { + $testDrive = Get-MgDrive -Filter "driveType eq 'personal'" -ErrorAction Stop | Select-Object -First 1 + if (-not $testDrive) { + Write-Error "Could not access OneDrive after authentication" + return $false + } + } + catch { + Write-Error "Failed to verify Graph API access: $_" + return $false + } + return $true } catch { @@ -92,19 +114,6 @@ function Get-DriveItems { Write-Host "Found $($items.Count) items in specified folder" - # Debug output for first few items - $items | Select-Object -First 50000 | ForEach-Object { - Write-Host "`nItem: $($_.Name)" - Write-Host "Type: $($_.File.MimeType)" - Write-Host "ID: $($_.Id)" - - # Additional debug info for photos - if ($_.Photo) { - Write-Host "Photo metadata found!" - $_.Photo | Format-List | Out-String | Write-Host - } - } - return $items } catch { @@ -142,6 +151,14 @@ function Test-DownloadItem { } Write-Host "Downloading to: $fileName" + + # Try to refresh token before download + $context = Get-MgContext + if (-not $context -or $context.ExpiresOn -le (Get-Date)) { + Write-Host "Token expired or missing, reconnecting..." -ForegroundColor Yellow + Connect-GraphWithDebug | Out-Null + } + Get-MgDriveItemContent -DriveId $drive.Id -DriveItemId $ItemId -OutFile $fileName if (Test-Path $fileName) { @@ -152,6 +169,20 @@ function Test-DownloadItem { } catch { Write-Error "Download failed: $_" + Write-Host "Attempting to reconnect and retry..." -ForegroundColor Yellow + + try { + Connect-GraphWithDebug | Out-Null + Get-MgDriveItemContent -DriveId $drive.Id -DriveItemId $ItemId -OutFile $fileName + + if (Test-Path $fileName) { + Write-Host "Successfully downloaded on retry: $fileName" -ForegroundColor Green + return $true + } + } + catch { + Write-Error "Retry download failed: $_" + } return $false } } @@ -161,55 +192,47 @@ function Get-LivePhotoBundle { [Parameter(Mandatory)] $item, [Parameter(Mandatory)] - $drive, - [Parameter(Mandatory)] - $AccessToken + $drive ) try { if ($item.File.MimeType -eq "image/heic") { - Write-Host "Found HEIC file: $($item.Name)" -ForegroundColor Cyan + Write-Host "`nDetailed HEIC Analysis:" -ForegroundColor Cyan + Write-Host "------------------------" + Write-Host "File Name: $($item.Name)" + Write-Host "File Size: $($item.Size) bytes" + + # Try to download video directly using the same item ID $baseName = [System.IO.Path]::GetFileNameWithoutExtension($item.Name) - - # Get the video component using the direct video format API $videoPath = Join-Path $SaveTo "$baseName.mov" - $tmpFile = Join-Path $SaveTo "tmp-file.mov" - if (-not (Test-Path $videoPath)) { - Write-Host "Attempting to download video component..." + # Use the same video download URL format as the original script + $videoUri = "https://api.onedrive.com/v1.0/drive/items/$($item.Id)/content?format=video" + Write-Host "Attempting direct video download: $videoUri" + + try { + $response = Invoke-MgGraphRequest -Method GET -Uri $videoUri -OutputFilePath $videoPath - # Use exactly the same endpoint and headers as original script - $videoUri = "https://api.onedrive.com/v1.0/drive/items/$($item.Id)/content?format=video" - Write-Host "Using video endpoint: $videoUri" - - try { - # Use exact same headers as original script - $headers = @{ - 'Authorization' = "BEARER $AccessToken" # Note: BEARER in uppercase - } + if ((Test-Path $videoPath) -and (Get-Item $videoPath).Length -gt 0) { + Write-Host "Successfully downloaded video component" -ForegroundColor Green + return $true + } else { + Write-Host "Downloaded file appears to be invalid" -ForegroundColor Yellow + Remove-Item $videoPath -ErrorAction SilentlyContinue - Write-Host "Calling OneDrive API for video..." - $WebRequest = Invoke-WebRequest -Method "GET" -Uri $videoUri -Header $headers -ErrorAction SilentlyContinue -OutFile $tmpFile -PassThru - Write-Host "WebRequest: Done Calling OneDrive API" - if ((Test-Path $tmpFile) -and (Get-Item $tmpFile).Length -gt 0) { - $fileName = ($WebRequest.Headers.'Content-Disposition'.Split('=',2)[-1]).Trim('"') - if ($fileName) { - Write-Host "Renaming $tmpFile to $fileName" - if (Test-Path $videoPath) { - Remove-Item $videoPath - } - Rename-Item -Path $tmpFile -NewName $fileName - return $true - } - } } - catch { - Write-Host "Failed to download video component: $_" -ForegroundColor Red - Remove-Item $tmpFile -ErrorAction SilentlyContinue - } - } else { - Write-Host "Video file already exists: $videoPath" -ForegroundColor Yellow - return $true + } + catch { + Write-Host "Direct video download failed, trying alternative methods..." -ForegroundColor Yellow + Write-Host "Error details:" -ForegroundColor Red + Write-Host "Status Code: $($_.Exception.Response.StatusCode.value__)" -ForegroundColor Red + Write-Host "Status Description: $($_.Exception.Response.StatusDescription)" -ForegroundColor Red + Write-Host "Error Message: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "Request URI: $videoUri" -ForegroundColor Red + + # Write full error object for debugging + Write-Debug "Full Error Object:" + Write-Debug ($_ | Format-List -Force | Out-String) } } return $false @@ -296,57 +319,83 @@ if (!(Test-Path $SaveTo)) { New-Item -ItemType Directory -Force -Path $SaveTo } -# Get both authentication tokens -Write-Host "Getting Graph API token..." -if (Connect-GraphWithDebug) { - Write-Host "`nGetting OneDrive Photos token..." - $photosToken = Get-ODPhotosToken +# Get Graph API token with retry +$maxRetries = 3 +$retryCount = 0 +$connected = $false + +while (-not $connected -and $retryCount -lt $maxRetries) { + $retryCount++ + Write-Host "`nAttempting Graph API connection (Attempt $retryCount of $maxRetries)..." - Write-Host "`nQuerying OneDrive items..." - $items = Get-DriveItems -FolderPath $PathToScan + if (Connect-GraphWithDebug) { + $connected = $true + break + } - if ($items) { - # Get drive reference - $drive = Get-MgDrive -Filter "driveType eq 'personal'" | Select-Object -First 1 - if (-not $drive) { - Write-Error "Could not get drive reference" - return - } - - Write-Host "`nProcessing items for Live Photos..." - foreach ($item in $items) { - Write-Host "`nChecking item: $($item.Name)" - - # Process only HEIC files - if ($item.File.MimeType -eq "image/heic") { - Write-Host "Found HEIC file, checking for Live Photo components..." - - # Download the HEIC file if it doesn't exist - try { - $result = Test-DownloadItem -ItemId $item.Id -SavePath $SaveTo -item $item - if ($result) { - # Try to get the video component, passing all items and the photos token - $hasVideo = Get-LivePhotoBundle -item $item -drive $drive -AccessToken $photosToken.'AccessToken-OneDrive.ReadWrite' - if ($hasVideo) { - Write-Host "Successfully processed Live Photo bundle for: $($item.Name)" -ForegroundColor Green - } else { - Write-Host "No Live Photo video component found for: $($item.Name)" -ForegroundColor Yellow - } - } - } - catch { - Write-Host "Error processing $($item.Name): $_" -ForegroundColor Red - } - - # Add a small delay between items - Start-Sleep -Milliseconds 500 - } - } - - Write-Host "`nCompleted processing Live Photos" - } else { - Write-Host "No items found to process" + if ($retryCount -lt $maxRetries) { + Write-Host "Connection failed. Waiting 5 seconds before retry..." + Start-Sleep -Seconds 5 } } +if (-not $connected) { + Write-Error "Failed to connect to Graph API after $maxRetries attempts. Exiting." + return +} + +# Get both authentication tokens +Write-Host "`nGetting OneDrive Photos token..." +$photosToken = Get-ODPhotosToken +if (-not $photosToken) { + Write-Error "Failed to get OneDrive Photos token. Exiting." + return +} + +# Get drive reference first +$drive = Get-MgDrive -Filter "driveType eq 'personal'" | Select-Object -First 1 +if (-not $drive) { + Write-Error "Could not get drive reference" + return +} + +Write-Host "`nQuerying OneDrive items..." +$items = Get-DriveItems -FolderPath $PathToScan +if (-not $items) { + Write-Error "No items found or error occurred while fetching items" + return +} + +Write-Host "`nProcessing items for Live Photos..." +foreach ($item in $items) { + Write-Host "`nChecking item: $($item.Name)" + + # Process only HEIC files + if ($item.File.MimeType -eq "image/heic") { + Write-Host "Found HEIC file, checking for Live Photo components..." + + # Download the HEIC file if it doesn't exist + try { + $result = Test-DownloadItem -ItemId $item.Id -SavePath $SaveTo -item $item + if ($result) { + # Try to get the video component, passing all items and the photos token + $hasVideo = Get-LivePhotoBundle -item $item -drive $drive + if ($hasVideo) { + Write-Host "Successfully processed Live Photo bundle for: $($item.Name)" -ForegroundColor Green + } else { + Write-Host "No Live Photo video component found for: $($item.Name)" -ForegroundColor Yellow + } + } + } + catch { + Write-Host "Error processing $($item.Name): $_" -ForegroundColor Red + } + + # Add a small delay between items + Start-Sleep -Milliseconds 500 + } +} + +Write-Host "`nCompleted processing Live Photos" + Write-Host "`nDebug script completed" \ No newline at end of file